integrate tiptap text editor
This commit is contained in:
parent
55123c386d
commit
93fba2d46d
|
@ -2,6 +2,7 @@ import os
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
|
from bleach import sanitizer
|
||||||
from django.conf import settings as d_settings
|
from django.conf import settings as d_settings
|
||||||
|
|
||||||
|
|
||||||
|
@ -179,5 +180,10 @@ class Settings(BaseSettings):
|
||||||
ALLOW_COMMENTS = True
|
ALLOW_COMMENTS = True
|
||||||
"""Allow comments."""
|
"""Allow comments."""
|
||||||
|
|
||||||
|
# ---- bleach
|
||||||
|
ALLOWED_TAGS = [*sanitizer.ALLOWED_TAGS, "br", "p", "h3", "h4", "h5"]
|
||||||
|
ALLOWED_ATTRIBUTES = sanitizer.ALLOWED_ATTRIBUTES
|
||||||
|
ALLOWED_PROTOCOLS = sanitizer.ALLOWED_PROTOCOLS
|
||||||
|
|
||||||
|
|
||||||
settings = Settings("AIRCOX")
|
settings = Settings("AIRCOX")
|
||||||
|
|
|
@ -13,6 +13,7 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from filer.fields.image import FilerImageField
|
from filer.fields.image import FilerImageField
|
||||||
from model_utils.managers import InheritanceQuerySet
|
from model_utils.managers import InheritanceQuerySet
|
||||||
|
|
||||||
|
from ..conf import settings
|
||||||
from .station import Station
|
from .station import Station
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
@ -120,6 +121,14 @@ class BasePage(Renderable, models.Model):
|
||||||
return "{}".format(self.title or self.pk)
|
return "{}".format(self.title or self.pk)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
if self.content:
|
||||||
|
self.content = bleach.clean(
|
||||||
|
self.content,
|
||||||
|
tags=settings.ALLOWED_TAGS,
|
||||||
|
attributes=settings.ALLOWED_ATTRIBUTES,
|
||||||
|
protocols=settings.ALLOWED_PROTOCOLS,
|
||||||
|
)
|
||||||
|
|
||||||
if not self.slug:
|
if not self.slug:
|
||||||
self.slug = slugify(self.title)[:100]
|
self.slug = slugify(self.title)[:100]
|
||||||
count = Page.objects.filter(slug__startswith=self.slug).count()
|
count = Page.objects.filter(slug__startswith=self.slug).count()
|
||||||
|
@ -165,17 +174,6 @@ class BasePage(Renderable, models.Model):
|
||||||
headline[-1] += suffix
|
headline[-1] += suffix
|
||||||
return mark_safe(" ".join(headline))
|
return mark_safe(" ".join(headline))
|
||||||
|
|
||||||
_url_re = re.compile(
|
|
||||||
"((http|https)\:\/\/)?[a-zA-Z0-9\.\/\?\:@\-_=#]+\.([a-zA-Z]){2,6}([a-zA-Z0-9\.\&\/\?\:@\-_=#])*"
|
|
||||||
)
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def display_content(self):
|
|
||||||
if "<p>" in self.content:
|
|
||||||
return self.content
|
|
||||||
content = self._url_re.sub(r'<a href="\1" target="new">\1</a>', self.content)
|
|
||||||
return content.replace("\n\n", "\n").replace("\n", "<br>")
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_init_kwargs_from(cls, page, **kwargs):
|
def get_init_kwargs_from(cls, page, **kwargs):
|
||||||
kwargs.setdefault("cover", page.cover)
|
kwargs.setdefault("cover", page.cover)
|
||||||
|
|
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
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
|
@ -136,9 +136,9 @@ Usefull context:
|
||||||
|
|
||||||
{% block content-container %}
|
{% block content-container %}
|
||||||
{% if page and page.content %}
|
{% if page and page.content %}
|
||||||
<section class="container content page-content">
|
<section class="container no-reset content page-content">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{{ page.display_content|safe }}
|
{{ page.content|safe }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</section>
|
</section>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -18,6 +18,12 @@ aircox.labels = {% inline_labels %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block title-container %}
|
||||||
|
{{ block.super }}
|
||||||
|
{% block page-actions %}
|
||||||
|
{% include "aircox/widgets/page_actions.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content-container %}
|
{% block content-container %}
|
||||||
<a-select-file ref="cover-select"
|
<a-select-file ref="cover-select"
|
||||||
|
@ -102,8 +108,11 @@ aircox.labels = {% inline_labels %}
|
||||||
<div>
|
<div>
|
||||||
<div class="field {% if field.name != "content" %}is-horizontal{% endif %}">
|
<div class="field {% if field.name != "content" %}is-horizontal{% endif %}">
|
||||||
<label class="label">{{ field.label }}</label>
|
<label class="label">{{ field.label }}</label>
|
||||||
<div class="control clear-unset">
|
<div class="control clear-unset no-reset">
|
||||||
|
<a-editor name="{{ field.name }}" initial="{{ field.value }}"/>
|
||||||
|
{% comment %}
|
||||||
<textarea name="{{ field.name }}" class="is-fullwidth height-25">{{ field.value|default:""|striptags|safe }}</textarea>
|
<textarea name="{{ field.name }}" class="is-fullwidth height-25">{{ field.value|default:""|striptags|safe }}</textarea>
|
||||||
|
{% endcomment %}
|
||||||
</div>
|
</div>
|
||||||
<p class="help">{{ field.help_text }}</p>
|
<p class="help">{{ field.help_text }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,24 +2,24 @@
|
||||||
|
|
||||||
{% block user-actions-container %}
|
{% block user-actions-container %}
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
{{ object.get_status_display }}
|
{{ object.get_status_display|capfirst }}
|
||||||
|
|
||||||
{% if object.pub_date %}
|
{% if object.pub_date %}
|
||||||
({{ object.pub_date|date:"d/m/Y H:i" }})
|
({{ object.pub_date|date:"d/m/Y H:i" }})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if user.is_authenticated and can_edit %}
|
{% if user.is_authenticated %}
|
||||||
{% with request.resolver_match.view_name as view_name %}
|
{% with request.resolver_match.view_name as view_name %}
|
||||||
|
|
||||||
{% if "-edit" in view_name %}
|
{% if request.path != object.get_absolute_url %}
|
||||||
<a href="{% url view_name|detail_view page.slug %}" target="_self" title="{% translate 'View' %} {{ page }}">
|
<a href="{% url view_name|detail_view page.slug %}" target="_self" title="{% translate 'View' %} {{ page }}">
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<i class="fa-regular fa-eye"></i>
|
<i class="fa-regular fa-eye"></i>
|
||||||
</span>
|
</span>
|
||||||
<span>{% translate 'View' %} </span>
|
<span>{% translate 'View' %} </span>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% elif can_edit %}
|
||||||
<a href="{% url view_name|edit_view page.pk %}" target="_self" title="{% translate 'Edit' %} {{ page }}">
|
<a href="{% url view_name|edit_view page.pk %}" target="_self" title="{% translate 'Edit' %} {{ page }}">
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<i class="fa-solid fa-pencil"></i>
|
<i class="fa-solid fa-pencil"></i>
|
||||||
|
|
|
@ -55,6 +55,9 @@ class EpisodeUpdateView(UserPassesTestMixin, VueFormDataMixin, PageUpdateView):
|
||||||
form_class = forms.EpisodeForm
|
form_class = forms.EpisodeForm
|
||||||
template_name = "aircox/episode_form.html"
|
template_name = "aircox/episode_form.html"
|
||||||
|
|
||||||
|
def can_edit(self, obj):
|
||||||
|
return self.test_func()
|
||||||
|
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
return permissions.program.can(self.request.user, "update", obj)
|
return permissions.program.can(self.request.user, "update", obj)
|
||||||
|
|
|
@ -33,6 +33,17 @@ def attach(cls):
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
|
|
||||||
|
class CanEditMixin:
|
||||||
|
"""Add context 'can_edit' set to True when object is editable by user."""
|
||||||
|
|
||||||
|
def can_edit(self, object):
|
||||||
|
"""Return True if user can edit current page."""
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
return super().get_context_data(can_edit=self.can_edit(self.object), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class BasePageMixin:
|
class BasePageMixin:
|
||||||
category = None
|
category = None
|
||||||
|
|
||||||
|
@ -156,16 +167,12 @@ class PageListView(FiltersMixin, BasePageListView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class PageDetailView(BasePageDetailView):
|
class PageDetailView(CanEditMixin, BasePageDetailView):
|
||||||
"""Base view class for pages."""
|
"""Base view class for pages."""
|
||||||
|
|
||||||
template_name = None
|
template_name = None
|
||||||
context_object_name = "page"
|
context_object_name = "page"
|
||||||
|
|
||||||
def can_edit(self, object):
|
|
||||||
"""Return True if user can edit current page."""
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_template_names(self):
|
def get_template_names(self):
|
||||||
return super().get_template_names() + ["aircox/page_detail.html"]
|
return super().get_template_names() + ["aircox/page_detail.html"]
|
||||||
|
|
||||||
|
@ -185,7 +192,6 @@ class PageDetailView(BasePageDetailView):
|
||||||
if related:
|
if related:
|
||||||
related = related[: self.related_count]
|
related = related[: self.related_count]
|
||||||
kwargs["related_objects"] = related
|
kwargs["related_objects"] = related
|
||||||
kwargs["can_edit"] = self.can_edit(self.object)
|
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_comment_form(self):
|
def get_comment_form(self):
|
||||||
|
@ -210,7 +216,7 @@ class PageDetailView(BasePageDetailView):
|
||||||
return self.get(request, *args, **kwargs)
|
return self.get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class PageCreateView(BaseView, CreateView):
|
class PageCreateView(CanEditMixin, BaseView, CreateView):
|
||||||
def get_page(self):
|
def get_page(self):
|
||||||
return self.object
|
return self.object
|
||||||
|
|
||||||
|
@ -218,7 +224,7 @@ class PageCreateView(BaseView, CreateView):
|
||||||
return self.request.path
|
return self.request.path
|
||||||
|
|
||||||
|
|
||||||
class PageUpdateView(BaseView, UpdateView):
|
class PageUpdateView(CanEditMixin, BaseView, UpdateView):
|
||||||
def get_page(self):
|
def get_page(self):
|
||||||
return self.object
|
return self.object
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,9 @@ class ProgramCreateView(PermissionRequiredMixin, ProgramEditMixin, page.PageCrea
|
||||||
|
|
||||||
|
|
||||||
class ProgramUpdateView(UserPassesTestMixin, ProgramEditMixin, page.PageUpdateView):
|
class ProgramUpdateView(UserPassesTestMixin, ProgramEditMixin, page.PageUpdateView):
|
||||||
|
def can_edit(self, obj):
|
||||||
|
return self.test_func()
|
||||||
|
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
return permissions.program.can(self.request.user, "update", obj)
|
return permissions.program.can(self.request.user, "update", obj)
|
||||||
|
|
|
@ -20,6 +20,11 @@
|
||||||
"vue": "^3.4.21"
|
"vue": "^3.4.21"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@tiptap/extension-link": "^2.3.0",
|
||||||
|
"@tiptap/extension-underline": "^2.3.0",
|
||||||
|
"@tiptap/pm": "^2.3.0",
|
||||||
|
"@tiptap/starter-kit": "^2.3.0",
|
||||||
|
"@tiptap/vue-3": "^2.3.0",
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"bulma": "^0.9.4",
|
"bulma": "^0.9.4",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
|
|
132
assets/src/components/AEditor.vue
Normal file
132
assets/src/components/AEditor.vue
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
<template>
|
||||||
|
<input ref="input" type="hidden" :name="name" :value="value"/>
|
||||||
|
<div class="">
|
||||||
|
<template v-for="group, index in menu" :key="index">
|
||||||
|
<div class="button-group d-inline-block mr-3">
|
||||||
|
<template v-for="info, index in group" :key="index">
|
||||||
|
<button type="button" class="button square smaller" :title="info.label" @click="edit(info.action, ...(info.args || []))">
|
||||||
|
<span class="icon"><i :class="info.icon"/></span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="button-group d-inline-block">
|
||||||
|
<div class="dropdown is-hoverable">
|
||||||
|
<div class="dropdown-trigger">
|
||||||
|
<button type="button" class="button square smaller">
|
||||||
|
<span class="icon"><i class="fa fa-link"/></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="dropdown-menu" style="min-width: 20rem; margin-top: -0.2rem;">
|
||||||
|
<div class="dropdown-content p-3">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">Lien</label>
|
||||||
|
<div class="control">
|
||||||
|
<input ref="link-url" type="text" class="input" placeholder="lien"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="has-text-right">
|
||||||
|
<button type="button" class="button secondary"
|
||||||
|
@click="edit('setLink', {href:$refs['link-url'].value})">
|
||||||
|
Ajouter le lien
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="button square smaller" title="Remove link" @click="edit('unsetLink')">
|
||||||
|
<span class="icon"><i class="fa fa-link-slash"/></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<editor-content class="editor" v-if="editor" :editor="editor" />
|
||||||
|
</template>
|
||||||
|
<style>
|
||||||
|
.editor .tiptap {
|
||||||
|
border: 1px black solid;
|
||||||
|
padding: 0.3em;
|
||||||
|
}
|
||||||
|
.editor .tiptap ul, .editor .tiptap ol {
|
||||||
|
margin-left: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor .tiptap ul { list-style: disc }
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import { Editor, EditorContent } from '@tiptap/vue-3'
|
||||||
|
import StarterKit from '@tiptap/starter-kit'
|
||||||
|
import Underline from '@tiptap/extension-underline'
|
||||||
|
import Link from '@tiptap/extension-link'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {EditorContent},
|
||||||
|
props: {
|
||||||
|
config: {type: Object, default: (() => {})},
|
||||||
|
//! Input field name.
|
||||||
|
name: String,
|
||||||
|
//! Initial input value
|
||||||
|
initial: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editor: null,
|
||||||
|
menu: [
|
||||||
|
[
|
||||||
|
{label: "Bold", icon: "fa fa-bold", action: "toggleBold" },
|
||||||
|
{label: "Italic", icon: "fa fa-italic", action: "toggleItalic" },
|
||||||
|
{label: "Underline", icon: "fa fa-underline", action: "toggleUnderline" },
|
||||||
|
{label: "Strike", icon: "fa fa-strikethrough", action: "toggleStrike" },
|
||||||
|
],[
|
||||||
|
{label: "List", icon: "fa fa-list", action: "toggleBulletList" },
|
||||||
|
{label: "Ordered List", icon: "fa fa-list-ol", action: "toggleOrderedList" },
|
||||||
|
],[
|
||||||
|
{label: "Heading 1", icon: "fa fa-h", action: "setHeading", args: [{level:3}] },
|
||||||
|
{label: "Heading 2", icon: "fa fa-h smaller", action: "toggleHeading", args: [{level:4}] },
|
||||||
|
// {label: "Heading 3", icon: "fa fa-h small", action: "toggleHeading", args: [{level:5}] },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
value() { return this.editor && this.editor.getHTML() },
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
chain(action, ...args) {
|
||||||
|
let chain = this.editor.chain().focus()
|
||||||
|
return chain[action](...args)
|
||||||
|
},
|
||||||
|
|
||||||
|
edit(action, ...args) {
|
||||||
|
this.chain(action, ...args).run()
|
||||||
|
},
|
||||||
|
|
||||||
|
setLink() {
|
||||||
|
this.edit("setLink", {href: this.$refs['link-url']})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.editor = new Editor({
|
||||||
|
content: this.initial || "",
|
||||||
|
injectCss: false,
|
||||||
|
extensions: [
|
||||||
|
StarterKit.configure({
|
||||||
|
heading: {
|
||||||
|
levels: [3, 4, 5]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Underline,
|
||||||
|
Link.configure({autolink: true}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
beforeUnmount() {
|
||||||
|
this.editor.destroy()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -6,6 +6,7 @@ import AStreamer from './AStreamer.vue'
|
||||||
import AFormSet from './AFormSet.vue'
|
import AFormSet from './AFormSet.vue'
|
||||||
import ATrackListEditor from './ATrackListEditor.vue'
|
import ATrackListEditor from './ATrackListEditor.vue'
|
||||||
import ASoundListEditor from './ASoundListEditor.vue'
|
import ASoundListEditor from './ASoundListEditor.vue'
|
||||||
|
import AEditor from './AEditor.vue'
|
||||||
|
|
||||||
import AManyToManyEdit from "./AManyToManyEdit.vue"
|
import AManyToManyEdit from "./AManyToManyEdit.vue"
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ import base from "./index.js"
|
||||||
export const admin = {
|
export const admin = {
|
||||||
...base,
|
...base,
|
||||||
AManyToManyEdit,
|
AManyToManyEdit,
|
||||||
AFileUpload, ASelectFile,
|
AFileUpload, ASelectFile, AEditor,
|
||||||
AFormSet, ATrackListEditor, ASoundListEditor,
|
AFormSet, ATrackListEditor, ASoundListEditor,
|
||||||
AStatistics, AStreamer,
|
AStatistics, AStreamer,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
:root {
|
:root {
|
||||||
--title-1-sz: 1.6rem;
|
--title-1-sz: 1.6rem;
|
||||||
--title-2-sz: 1.4rem;
|
--title-2-sz: 1.4rem;
|
||||||
--title-3-sz: 1.2rem;
|
--title-3-sz: 1.3rem;
|
||||||
|
--title-4-sz: 1.2rem;
|
||||||
--subtitle-1-sz: 1.6rem;
|
--subtitle-1-sz: 1.6rem;
|
||||||
--subtitle-2-sz: 1.4rem;
|
--subtitle-2-sz: 1.4rem;
|
||||||
--subtitle-3-sz: 1.2rem;
|
--subtitle-3-sz: 1.2rem;
|
||||||
|
@ -96,6 +97,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- headings
|
// ---- headings
|
||||||
|
|
||||||
|
.no-reset h1 { font-size: var(--title-1-sz); }
|
||||||
|
.no-reset h2 { font-size: var(--title-2-sz); }
|
||||||
|
.no-reset h3 { font-size: var(--title-3-sz); }
|
||||||
|
.no-reset h3 { font-size: var(--title-3-sz); }
|
||||||
|
.no-reset h4 { font-size: var(--title-4-sz); }
|
||||||
|
.no-reset h5 { font-size: var(--title-5-sz); }
|
||||||
|
|
||||||
.title, .header.preview .title {
|
.title, .header.preview .title {
|
||||||
&.is-1 { font-size: var(--title-1-sz); }
|
&.is-1 { font-size: var(--title-1-sz); }
|
||||||
&.is-2 { font-size: var(--title-2-sz); }
|
&.is-2 { font-size: var(--title-2-sz); }
|
||||||
|
@ -215,6 +224,10 @@
|
||||||
&:last-child { border-right: 0px; }
|
&:last-child { border-right: 0px; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-group + .button-group {
|
||||||
|
border-left: 1px solid var(--text-color-light);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,9 @@
|
||||||
.bg-secondary-light { background-color: var(--secondary-color-light); }
|
.bg-secondary-light { background-color: var(--secondary-color-light); }
|
||||||
.bg-transparent { background-color: transparent; }
|
.bg-transparent { background-color: transparent; }
|
||||||
|
|
||||||
|
.border { border: 1px solid var(--text-color); }
|
||||||
|
.border-main { border: 1px solid var(--main-color); }
|
||||||
|
.border-secondary { border: 1px solid var(--secondary-color); }
|
||||||
.border-bottom-main { border-bottom: 1px solid var(--main-color); }
|
.border-bottom-main { border-bottom: 1px solid var(--main-color); }
|
||||||
.border-bottom-secondary { border-bottom: 1px solid var(--secondary-color); }
|
.border-bottom-secondary { border-bottom: 1px solid var(--secondary-color); }
|
||||||
|
|
||||||
|
|
|
@ -77,99 +77,6 @@ except Exception:
|
||||||
# -- django-taggit
|
# -- django-taggit
|
||||||
TAGGIT_CASE_INSENSITIVE = True
|
TAGGIT_CASE_INSENSITIVE = True
|
||||||
|
|
||||||
# -- django-CKEditor
|
|
||||||
CKEDITOR_CONFIGS = {
|
|
||||||
"default": {
|
|
||||||
"format_tags": "h1;h2;h3;p;pre",
|
|
||||||
# 'skin': 'office2013',
|
|
||||||
"toolbar_Custom": [
|
|
||||||
{
|
|
||||||
"name": "editing",
|
|
||||||
"items": [
|
|
||||||
"Undo",
|
|
||||||
"Redo",
|
|
||||||
"-",
|
|
||||||
"Find",
|
|
||||||
"Replace",
|
|
||||||
"-",
|
|
||||||
"Source",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "basicstyles",
|
|
||||||
"items": [
|
|
||||||
"Bold",
|
|
||||||
"Italic",
|
|
||||||
"Underline",
|
|
||||||
"Strike",
|
|
||||||
"Subscript",
|
|
||||||
"Superscript",
|
|
||||||
"-",
|
|
||||||
"RemoveFormat",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "paragraph",
|
|
||||||
"items": [
|
|
||||||
"NumberedList",
|
|
||||||
"BulletedList",
|
|
||||||
"-",
|
|
||||||
"Outdent",
|
|
||||||
"Indent",
|
|
||||||
"-",
|
|
||||||
"Blockquote",
|
|
||||||
"CreateDiv",
|
|
||||||
"-",
|
|
||||||
"JustifyLeft",
|
|
||||||
"JustifyCenter",
|
|
||||||
"JustifyRight",
|
|
||||||
"JustifyBlock",
|
|
||||||
"-",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"/",
|
|
||||||
{"name": "links", "items": ["Link", "Unlink", "Anchor"]},
|
|
||||||
{
|
|
||||||
"name": "insert",
|
|
||||||
"items": [
|
|
||||||
"Image",
|
|
||||||
"Table",
|
|
||||||
"HorizontalRule",
|
|
||||||
"SpecialChar",
|
|
||||||
"PageBreak",
|
|
||||||
"Iframe",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "styles",
|
|
||||||
"items": ["Styles", "Format", "Font", "FontSize"],
|
|
||||||
},
|
|
||||||
{"name": "colors", "items": ["TextColor", "BGColor"]},
|
|
||||||
"/", # put this to force next toolbar on new line
|
|
||||||
],
|
|
||||||
"toolbar": "Custom",
|
|
||||||
"extraPlugins": ",".join(
|
|
||||||
[
|
|
||||||
"uploadimage",
|
|
||||||
"div",
|
|
||||||
"autolink",
|
|
||||||
"autoembed",
|
|
||||||
"embedsemantic",
|
|
||||||
"embed",
|
|
||||||
"iframe",
|
|
||||||
"iframedialog",
|
|
||||||
"autogrow",
|
|
||||||
"widget",
|
|
||||||
"lineutils",
|
|
||||||
"dialog",
|
|
||||||
"dialogui",
|
|
||||||
"elementspath",
|
|
||||||
]
|
|
||||||
),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
CKEDITOR_UPLOAD_PATH = "uploads/"
|
|
||||||
|
|
||||||
|
|
||||||
# -- easy_thumbnails
|
# -- easy_thumbnails
|
||||||
THUMBNAIL_PROCESSORS = (
|
THUMBNAIL_PROCESSORS = (
|
||||||
|
@ -190,8 +97,6 @@ INSTALLED_APPS = (
|
||||||
"rest_framework",
|
"rest_framework",
|
||||||
"django_filters",
|
"django_filters",
|
||||||
"content_editor",
|
"content_editor",
|
||||||
"ckeditor",
|
|
||||||
"ckeditor_uploader",
|
|
||||||
"easy_thumbnails",
|
"easy_thumbnails",
|
||||||
"filer",
|
"filer",
|
||||||
"taggit",
|
"taggit",
|
||||||
|
|
|
@ -8,7 +8,6 @@ django-filer~=3.1
|
||||||
django-honeypot~=1.0
|
django-honeypot~=1.0
|
||||||
django-taggit~=3.0
|
django-taggit~=3.0
|
||||||
django-admin-sortable2~=2.1
|
django-admin-sortable2~=2.1
|
||||||
django-ckeditor~=6.4
|
|
||||||
bleach~=5.0
|
bleach~=5.0
|
||||||
easy-thumbnails~=2.8
|
easy-thumbnails~=2.8
|
||||||
tzlocal~=4.2
|
tzlocal~=4.2
|
||||||
|
|
Loading…
Reference in New Issue
Block a user