Skip to content

Commit e18961e

Browse files
committed
Update documentation
1 parent d2b5f6e commit e18961e

File tree

9 files changed

+17
-354
lines changed

9 files changed

+17
-354
lines changed

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ Key features
2121
rebuild you site's plugin tree if css framework is changed in the
2222
future, e.g. from Bootstrap 5 to a future version.
2323

24-
- **New link plugin** allowing to link to internal pages provided by
25-
other applications, such as `djangocms-blog
24+
- Leverage of new **djangocms-link features** allowing to link to internal pages
25+
provided by other applications, such as `djangocms-blog
2626
<https://github.com/nephila/djangocms-blog>`_.
2727

2828
- **Nice and well-arranged admin frontend** of `djangocms-bootstrap4

djangocms_frontend/contrib/link/cms_plugins.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from cms.plugin_pool import plugin_pool
22
from django.apps import apps
33
from django.conf import settings as django_settings
4-
from django.urls import path
54
from django.utils.translation import gettext_lazy as _
65

76
from djangocms_frontend.helpers import get_plugin_template, insert_fields
@@ -10,7 +9,7 @@
109
from ...cms_plugins import CMSUIPlugin
1110
from ...common import AttributesMixin, SpacingMixin
1211
from .. import link
13-
from . import forms, models, views
12+
from . import forms, models
1413
from .constants import USE_LINK_ICONS
1514
from .helpers import GetLinkMixin
1615

@@ -99,11 +98,6 @@ class TextLinkPlugin(mixin_factory("Link"), AttributesMixin, SpacingMixin, LinkP
9998
def get_render_template(self, context, instance, placeholder):
10099
return get_plugin_template(instance, "link", "link", settings.LINK_TEMPLATE_CHOICES)
101100

102-
def get_plugin_urls(self):
103-
return [
104-
path("autocomplete/", views.AutocompleteJsonView.as_view(), name="link_link_autocomplete"),
105-
]
106-
107101

108102
if "djangocms_frontend.contrib.link" in django_settings.INSTALLED_APPS:
109103
# Only register plugin if in INSTALLED_APPS

djangocms_frontend/contrib/link/forms.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
from django import apps, forms
66
from django.conf import settings as django_settings
77
from django.contrib.admin.widgets import SELECT2_TRANSLATIONS, AutocompleteMixin
8-
from django.contrib.contenttypes.models import ContentType
98
from django.contrib.sites.models import Site
10-
from django.core.exceptions import ObjectDoesNotExist
11-
from django.db import models
129
from django.utils.translation import get_language
1310
from django.utils.translation import gettext as _
1411
from djangocms_link.fields import LinkFormField
@@ -29,7 +26,6 @@
2926
from ...models import FrontendUIItem
3027
from .. import link
3128
from .constants import LINK_CHOICES, LINK_SIZE_CHOICES, TARGET_CHOICES
32-
from .helpers import get_object_for_value
3329

3430
mixin_factory = settings.get_forms(link)
3531

@@ -112,30 +108,6 @@ def optgroups(self, name, value, attr=None):
112108
return groups
113109

114110

115-
class SmartLinkField(forms.ChoiceField):
116-
widget = Select2jqWidget
117-
118-
def prepare_value(self, value):
119-
if value:
120-
if isinstance(value, dict): # Entangled dictionary?
121-
try:
122-
app_label, model = value["model"].rsplit(".", 1)
123-
content_type = ContentType.objects.get(app_label=app_label, model=model)
124-
return f"{content_type.id}-{value['pk']}"
125-
except (TypeError, ValueError, KeyError, ObjectDoesNotExist):
126-
pass
127-
elif isinstance(value, models.Model):
128-
content_type = ContentType.objects.get_for_model(value)
129-
return f"{content_type.id}-{value.id}"
130-
return ""
131-
132-
def clean(self, value):
133-
obj = get_object_for_value(value)
134-
if obj is not None:
135-
return obj
136-
return super().clean(value)
137-
138-
139111
if apps.apps.is_installed("djangocms_url_manager"):
140112
from djangocms_url_manager.forms import (
141113
HtmlLinkSiteSelectWidget,

djangocms_frontend/contrib/link/helpers.py

Lines changed: 1 addition & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,10 @@
1-
from importlib import import_module
2-
3-
from cms.forms.utils import get_page_choices
4-
from cms.models import Page
51
from django.apps import apps
6-
from django.conf import settings as django_settings
7-
from django.contrib.admin import site
82
from django.contrib.contenttypes.models import ContentType
93
from django.contrib.sites.models import Site
10-
from django.core.exceptions import FieldError, ObjectDoesNotExist
11-
from django.utils.encoding import force_str
4+
from django.core.exceptions import ObjectDoesNotExist
125

136
from djangocms_frontend.helpers import get_related_object
147

15-
LINK_MODELS = getattr(django_settings, "DJANGOCMS_FRONTEND_LINK_MODELS", [])
16-
17-
18-
def create_querysets(link_models):
19-
querysets = []
20-
for item in link_models:
21-
if item["class_path"] != "cms.models.Page":
22-
# CMS pages are collected using a cms function to preserve hierarchy
23-
section = item["type"]
24-
parts = item["class_path"].rsplit(".", 1)
25-
cls = getattr(import_module(parts[0]), parts[1])
26-
queryset = cls.objects
27-
28-
if "manager_method" in item:
29-
queryset = getattr(queryset, item["manager_method"])()
30-
31-
if "filter" in item:
32-
for k, v in item["filter"].items():
33-
try:
34-
# Attempt to execute any callables in the filter dict.
35-
item["filter"][k] = v()
36-
except TypeError:
37-
# OK, it wasn't a callable, so, leave it be
38-
pass
39-
queryset = queryset.filter(**item["filter"])
40-
else:
41-
if "manager_method" not in item:
42-
queryset = queryset.all()
43-
if "order_by" in item:
44-
queryset = queryset.order_by(item["order_by"])
45-
querysets.append((section, queryset, item.get("search", None), cls))
46-
return querysets
47-
48-
49-
_querysets = create_querysets(LINK_MODELS)
50-
518

529
def get_object_for_value(value):
5310
if isinstance(value, str) and "-" in value:
@@ -63,81 +20,6 @@ def get_object_for_value(value):
6320
return None
6421

6522

66-
def unescape(text, nbsp):
67-
return (
68-
text.replace("&nbsp;", nbsp)
69-
.replace("&amp;", "&")
70-
.replace("&lt;", "<")
71-
.replace("&gt;", ">")
72-
.replace("&quot;", '"')
73-
.replace("&#x27;", "'")
74-
)
75-
76-
77-
def get_link_choices(request, term="", lang=None, nbsp=None):
78-
global _querysets
79-
80-
if nbsp is None:
81-
nbsp = "" if term else "\u2000"
82-
available_objects = []
83-
# Now create our list of cms pages
84-
type_id = ContentType.objects.get_for_model(Page).id
85-
for value, descr in get_page_choices(lang):
86-
if isinstance(descr, list):
87-
available_objects.append(
88-
{
89-
"text": value,
90-
"children": [
91-
dict(
92-
id=f"{type_id}-{page}",
93-
# django admin's autocomplete view requires unescaped strings
94-
# get_page_choices escapes strings, so we undo the escape
95-
text=unescape(name, nbsp),
96-
)
97-
for page, name in descr
98-
if not isinstance(term, str) or term.upper() in name.upper()
99-
],
100-
}
101-
)
102-
elif value and isinstance(value, int):
103-
available_objects.append(dict(id=f"{type_id}-{value}"))
104-
105-
# Add list of additional non-cms pages
106-
for section, qs, search, cls in _querysets:
107-
objects = None
108-
model_admin = site._registry.get(cls, None)
109-
if search:
110-
try:
111-
objects = qs.filter(**{search + "__icontains": term})
112-
except FieldError:
113-
pass
114-
if objects is None:
115-
objects = [item for item in qs.all() if (not isinstance(term, str)) or term.upper() in str(item).upper()]
116-
if objects:
117-
type_class = ContentType.objects.get_for_model(objects[0].__class__)
118-
available_objects.append(
119-
{
120-
"text": force_str(section),
121-
"children": [
122-
dict(id=f"{type_class.id}-{obj.id}", text=str(obj))
123-
for obj in objects
124-
if request is None or model_admin and model_admin.has_view_permission(request, obj=obj)
125-
],
126-
}
127-
)
128-
return available_objects
129-
130-
131-
def get_choices(request, term="", lang=None) -> list:
132-
def to_choices(json):
133-
return list(
134-
(elem["text"], to_choices(elem["children"])) if "children" in elem else (elem["id"], elem["text"])
135-
for elem in json
136-
)
137-
138-
return to_choices(get_link_choices(request, term, lang, "&nbsp;"))
139-
140-
14123
class GetLinkMixin:
14224
def get_link(self) -> str:
14325
if "url_grouper" in self.config and self.config["url_grouper"] and apps.is_installed("djangocms_url_manager"):

djangocms_frontend/contrib/link/views.py

Lines changed: 0 additions & 30 deletions
This file was deleted.

docs/source/components.rst

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -342,29 +342,8 @@ to a CMS page or pages of other Django applications. They are dynamic, i.e. if
342342
the page's url changes (e.g. because it is moved in the page tree) all links
343343
pointing to the page change accordingly.
344344

345-
.. note::
346-
347-
**djangocms-frontend** uses django-cms' function ``get_page_choices(lang)``
348-
to get the list of available pages in the current language.
349-
350-
The developer can extend the list of available internal link targets to pages
351-
outside the CMS page tree using the
352-
``DJANGOCMS_FRONTEND_LINK_MODELS`` setting in the project's ``.settings`` file.
353-
The link/button
354-
component can point to any page controlled by a Django model if the model class
355-
implements the ``get_absolute_url`` method. A typical use case would, e.g.,
356-
blog entries of `djangocms-blog <https://github.com/nephila/djangocms-blog>`_.
357-
(This approach was inspired by mkoisten's `djangocms-styledlink
358-
<https://github.com/mkoistinen/djangocms-styledlink>`_.)
359-
360-
For more information, see
361-
:ref:`How to add internal link targets outside of the CMS`
362-
363-
.. note::
345+
If targets are deleted the link will fallback to regular text.
364346

365-
Only those destinations (outside the CMS) are shown for which a model admin
366-
is registered and the logged in user has view permissions: A user will only
367-
see a destination if they can view it in the admin site.
368347

369348
Re-usable component example
370349
===========================

docs/source/getting_started.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ by adding an option:
2929
djangocms-frontend[djangocms-icon] # Installs djangocms-icon for icons support in links
3030
djangocms-frontend[static-ace] # Installs djangocms-static-ace to include the ace code editor in static files
3131
djangocms-frontend[static-ace, djangocms-icon] # comma-separate multiple dependencies
32+
djangocms-frontend[djangocms-link] # Installs djangocms-link for link support
3233
3334
``djangocms-frontend[static-ace]`` is useful if your project cannot or should not
3435
access a CDN to load the `ace code editor <https://ace.c9.io>`_ for the code plugin.
@@ -44,6 +45,7 @@ Add the following entries to your ``INSTALLED_APPS``:
4445
4546
"djangocms_icon", # optional
4647
"easy_thumbnails",
48+
"djangocms_link", # Needed for link support
4749
"djangocms_frontend",
4850
"djangocms_frontend.contrib.accordion",
4951
"djangocms_frontend.contrib.alert",

0 commit comments

Comments
 (0)