From 03c4bb09d2f6298711d0a2e00f16b5e2d9f23bc9 Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Thu, 5 Aug 2021 00:25:54 -0500 Subject: [PATCH 01/15] GH-75: Data List - Plugin: Container, no Items yet --- .../contrib/taccsite_data_list/TODO.md | 3 + .../contrib/taccsite_data_list/__init__.py | 0 .../contrib/taccsite_data_list/cms_plugins.py | 77 +++++++++++++++++++ .../contrib/taccsite_data_list/constants.py | 38 +++++++++ .../migrations/0001_initial.py | 32 ++++++++ .../taccsite_data_list/migrations/__init__.py | 0 .../contrib/taccsite_data_list/models.py | 62 +++++++++++++++ .../templates/data_list.html | 7 ++ taccsite_cms/settings.py | 1 + 9 files changed, 220 insertions(+) create mode 100644 taccsite_cms/contrib/taccsite_data_list/TODO.md create mode 100644 taccsite_cms/contrib/taccsite_data_list/__init__.py create mode 100644 taccsite_cms/contrib/taccsite_data_list/cms_plugins.py create mode 100644 taccsite_cms/contrib/taccsite_data_list/constants.py create mode 100644 taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py create mode 100644 taccsite_cms/contrib/taccsite_data_list/migrations/__init__.py create mode 100644 taccsite_cms/contrib/taccsite_data_list/models.py create mode 100644 taccsite_cms/contrib/taccsite_data_list/templates/data_list.html diff --git a/taccsite_cms/contrib/taccsite_data_list/TODO.md b/taccsite_cms/contrib/taccsite_data_list/TODO.md new file mode 100644 index 000000000..572248eac --- /dev/null +++ b/taccsite_cms/contrib/taccsite_data_list/TODO.md @@ -0,0 +1,3 @@ +# To Do + +- [ ] Add Data List Item plugin diff --git a/taccsite_cms/contrib/taccsite_data_list/__init__.py b/taccsite_cms/contrib/taccsite_data_list/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py new file mode 100644 index 000000000..418648949 --- /dev/null +++ b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py @@ -0,0 +1,77 @@ +from cms.plugin_base import CMSPluginBase +from cms.plugin_pool import plugin_pool +from django.utils.translation import gettext_lazy as _ + +from taccsite_cms.contrib.helpers import concat_classnames +from taccsite_cms.contrib.taccsite_offset.cms_plugins import get_direction_classname + +from .models import TaccsiteDataList +from .constants import ORIENTATION_DICT, TYPE_STYLE_DICT, DENSITY_DICT + + + +# Helpers + +def get_classname(dict, value): + """Get layout class based on value.""" + return dict.get(value, {}).get('classname') + + + +# Plugins + +@plugin_pool.register_plugin +class TaccsiteDataListPlugin(CMSPluginBase): + """ + Components > "Data List" Plugin + https://confluence.tacc.utexas.edu/x/EiIFDg + """ + module = 'TACC Site' + model = TaccsiteDataList + name = _('Data List') + render_template = 'data_list.html' + + cache = True + text_enabled = False + allow_children = True + child_classes = [ + 'TaccsiteStaticDataListItemPlugin' + ] + + fieldsets = [ + (_('Required configuration'), { + 'fields': ( + 'type_style', + 'orientation', + 'density', + ) + }), + (_('Optional configuration'), { + 'fields': ( + 'truncate_values', + ) + }), + (_('Advanced settings'), { + 'classes': ('collapse',), + 'fields': ( + 'attributes', + ) + }), + ] + + # Render + + def render(self, context, instance, placeholder): + context = super().render(context, instance, placeholder) + request = context['request'] + + classes = concat_classnames([ + 'c-data_list', + get_classname(ORIENTATION_DICT, instance.orientation), + get_classname(TYPE_STYLE_DICT, instance.type_style), + get_classname(DENSITY_DICT, instance.density), + instance.attributes.get('class'), + ]) + instance.attributes['class'] = classes + + return context diff --git a/taccsite_cms/contrib/taccsite_data_list/constants.py b/taccsite_cms/contrib/taccsite_data_list/constants.py new file mode 100644 index 000000000..ae1e01941 --- /dev/null +++ b/taccsite_cms/contrib/taccsite_data_list/constants.py @@ -0,0 +1,38 @@ +# TODO: Consider using an Enum (and an Abstract Enum with `get_choices` and `get_classname` methods) + +ORIENTATION_DICT = { + 'horizontal': { + 'classname': 'c-data-list--is-horz', + 'description': 'Horizontal (all data on one row)', + 'short_description': 'Horizontal', + }, + 'vertical': { + 'classname': 'c-data-list--is-vert', + 'description': 'Vertical (every label and value has its own row)', + 'short_description': 'Vertical', + }, +} + +TYPE_STYLE_DICT = { + 'table': { + 'description': 'Tabular Data (ex: Columns; Table, no Header)', + 'short_description': 'Table', + }, + 'dlist': { + 'description': 'List of Data (ex: Glossary; Metadata; List)', + 'short_description': 'List', + }, +} + +DENSITY_DICT = { + 'default': { + 'classname': 'c-data-list--is-wide', + 'description': 'Default (ample extra space)', + 'short_description': 'Default', + }, + 'compact': { + 'classname': 'c-data-list--is-narrow', + 'description': 'Compact (minimal extra space)', + 'short_description': 'Compact', + }, +} diff --git a/taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py b/taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py new file mode 100644 index 000000000..a85fc12de --- /dev/null +++ b/taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py @@ -0,0 +1,32 @@ +# Generated by Django 2.2.16 on 2021-08-05 05:05 + +from django.db import migrations, models +import django.db.models.deletion +import djangocms_attributes_field.fields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('cms', '0022_auto_20180620_1551'), + ] + + operations = [ + migrations.CreateModel( + name='TaccsiteDataList', + fields=[ + ('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='taccsite_data_list_taccsitedatalist', serialize=False, to='cms.CMSPlugin')), + ('orientation', models.CharField(choices=[('horizontal', 'Horizontal (all data on one row)'), ('vertical', 'Vertical (every label and value has its own row)')], help_text='The direction in which to lay out the data. Hint: Choose based on the amount of space available in the layout for the data.', max_length=255, verbose_name='Orientation')), + ('type_style', models.CharField(choices=[('table', 'Tabular Data (ex: Columns; Table, no Header)'), ('dlist', 'List of Data (ex: Glossary; Metadata; List)')], help_text='The type of data to display, glossary/metadata or tabular. Notice: Each type of list has a slightly different style.', max_length=255, verbose_name='Type / Style')), + ('density', models.CharField(choices=[('default', 'Default (ample extra space)'), ('compact', 'Compact (minimal extra space)')], help_text='The amount of extra space in the layout. Hint: Choose based on the amount of space available in the layout for the data.', max_length=255, verbose_name='Density (Layout Spacing)')), + ('truncate_values', models.BooleanField(default=False, help_text='Truncate values if there is not enough space to show the label and the value. Notice: Labels are truncated as necessary.', verbose_name='Truncate the values (as necessary)')), + ('attributes', djangocms_attributes_field.fields.AttributesField(default=dict)), + ], + options={ + 'abstract': False, + }, + bases=('cms.cmsplugin',), + ), + ] diff --git a/taccsite_cms/contrib/taccsite_data_list/migrations/__init__.py b/taccsite_cms/contrib/taccsite_data_list/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/taccsite_cms/contrib/taccsite_data_list/models.py b/taccsite_cms/contrib/taccsite_data_list/models.py new file mode 100644 index 000000000..f2ed24480 --- /dev/null +++ b/taccsite_cms/contrib/taccsite_data_list/models.py @@ -0,0 +1,62 @@ +from cms.models.pluginmodel import CMSPlugin + +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from djangocms_attributes_field import fields + +from taccsite_cms.contrib.helpers import get_choices + +from .constants import ORIENTATION_DICT, TYPE_STYLE_DICT, DENSITY_DICT + + + +# Constants + +ORIENTATION_CHOICES = get_choices(ORIENTATION_DICT) +TYPE_STYLE_CHOICES = get_choices(TYPE_STYLE_DICT) +DENSITY_CHOICES = get_choices(DENSITY_DICT) + + + +# Models + +class TaccsiteDataList(CMSPlugin): + """ + Components > "Data List" Model + """ + orientation = models.CharField( + verbose_name=_('Orientation'), + help_text=_('The direction in which to lay out the data. Hint: Choose based on the amount of space available in the layout for the data.'), + choices=ORIENTATION_CHOICES, + blank=False, + max_length=255, + ) + type_style = models.CharField( + verbose_name=_('Type / Style'), + help_text=_('The type of data to display, glossary/metadata or tabular. Notice: Each type of list has a slightly different style.'), + choices=TYPE_STYLE_CHOICES, + blank=False, + max_length=255, + ) + density = models.CharField( + verbose_name=_('Density (Layout Spacing)'), + help_text=_('The amount of extra space in the layout. Hint: Choose based on the amount of space available in the layout for the data.'), + choices=DENSITY_CHOICES, + blank=False, + max_length=255, + ) + truncate_values = models.BooleanField( + verbose_name=_('Truncate the values (as necessary)'), + help_text=_('Truncate values if there is not enough space to show the label and the value. Notice: Labels are truncated as necessary.'), + default=False, + ) + + attributes = fields.AttributesField() + + def get_short_description(self): + orientation = ORIENTATION_DICT[self.orientation]['short_description'] + type_style = TYPE_STYLE_DICT[self.type_style]['short_description'] + density = DENSITY_DICT[self.density]['short_description'] + + return density + ', ' + orientation + ' ' + type_style diff --git a/taccsite_cms/contrib/taccsite_data_list/templates/data_list.html b/taccsite_cms/contrib/taccsite_data_list/templates/data_list.html new file mode 100644 index 000000000..9899137b6 --- /dev/null +++ b/taccsite_cms/contrib/taccsite_data_list/templates/data_list.html @@ -0,0 +1,7 @@ +{% load static %} + +
+ {% for plugin_instance in instance.child_plugin_instances %} + {# {% render_plugin plugin_instance %} #} + {% endfor %} +
diff --git a/taccsite_cms/settings.py b/taccsite_cms/settings.py index 530c2d3fd..5f07ba9bf 100644 --- a/taccsite_cms/settings.py +++ b/taccsite_cms/settings.py @@ -241,6 +241,7 @@ def getsecrets(): # TODO: Extract TACC CMS UI components into pip-installable plugins # FAQ: The djangocms_bootstrap4 library can serve as an example 'taccsite_cms.contrib.taccsite_sample', + 'taccsite_cms.contrib.taccsite_data_list', ] # Convert list of paths to list of dotted module names From 7271f343a76dfc6ec496dc3436f311c7450e7e57 Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Thu, 5 Aug 2021 23:32:18 -0500 Subject: [PATCH 02/15] GH-75: Data List - Plugin: Items - Add item child plugin. - Fix classes. - Tweak dict descriptions. - Support tables. - Add To Do item (add link support). --- .../contrib/taccsite_data_list/TODO.md | 2 +- .../contrib/taccsite_data_list/cms_plugins.py | 47 +++++++++++++++++-- .../contrib/taccsite_data_list/constants.py | 4 +- .../migrations/0001_initial.py | 17 ++++++- .../contrib/taccsite_data_list/models.py | 32 +++++++++++++ .../templates/data_list.html | 18 ++++++- .../templates/data_list_item.html | 15 ++++++ 7 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 taccsite_cms/contrib/taccsite_data_list/templates/data_list_item.html diff --git a/taccsite_cms/contrib/taccsite_data_list/TODO.md b/taccsite_cms/contrib/taccsite_data_list/TODO.md index 572248eac..11a7fe6c5 100644 --- a/taccsite_cms/contrib/taccsite_data_list/TODO.md +++ b/taccsite_cms/contrib/taccsite_data_list/TODO.md @@ -1,3 +1,3 @@ # To Do -- [ ] Add Data List Item plugin +- [ ] Add missing link feature to "Data List Item" plugin. diff --git a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py index 418648949..bcbb0a23f 100644 --- a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py +++ b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py @@ -5,7 +5,7 @@ from taccsite_cms.contrib.helpers import concat_classnames from taccsite_cms.contrib.taccsite_offset.cms_plugins import get_direction_classname -from .models import TaccsiteDataList +from .models import TaccsiteDataList, TaccsiteDataListItem from .constants import ORIENTATION_DICT, TYPE_STYLE_DICT, DENSITY_DICT @@ -32,10 +32,10 @@ class TaccsiteDataListPlugin(CMSPluginBase): render_template = 'data_list.html' cache = True - text_enabled = False + text_enabled = True allow_children = True child_classes = [ - 'TaccsiteStaticDataListItemPlugin' + 'TaccsiteDataListItemPlugin' ] fieldsets = [ @@ -66,12 +66,51 @@ def render(self, context, instance, placeholder): request = context['request'] classes = concat_classnames([ - 'c-data_list', + 'c-data-list', get_classname(ORIENTATION_DICT, instance.orientation), get_classname(TYPE_STYLE_DICT, instance.type_style), get_classname(DENSITY_DICT, instance.density), + 'c-data-list--should-truncate-values' + if instance.truncate_values else '', instance.attributes.get('class'), ]) instance.attributes['class'] = classes return context + +@plugin_pool.register_plugin +class TaccsiteDataListItemPlugin(CMSPluginBase): + """ + Components > "Data List Item" Plugin + https://confluence.tacc.utexas.edu/x/EiIFDg + """ + module = 'TACC Site' + model = TaccsiteDataListItem + name = _('Data List Item') + render_template = 'data_list_item.html' + + cache = True + text_enabled = False + allow_children = False + + fieldsets = [ + (None, { + 'fields': ( + ('key', 'value'), + ) + }) + ] + + # Render + + def render(self, context, instance, placeholder): + context = super().render(context, instance, placeholder) + request = context['request'] + + parent_plugin_instance = instance.parent.get_plugin_instance()[0] + + context.update({ + 'parent_plugin_instance': parent_plugin_instance + }) + + return context diff --git a/taccsite_cms/contrib/taccsite_data_list/constants.py b/taccsite_cms/contrib/taccsite_data_list/constants.py index ae1e01941..8a27bd084 100644 --- a/taccsite_cms/contrib/taccsite_data_list/constants.py +++ b/taccsite_cms/contrib/taccsite_data_list/constants.py @@ -15,11 +15,11 @@ TYPE_STYLE_DICT = { 'table': { - 'description': 'Tabular Data (ex: Columns; Table, no Header)', + 'description': 'Table (e.g. Columns)', 'short_description': 'Table', }, 'dlist': { - 'description': 'List of Data (ex: Glossary; Metadata; List)', + 'description': 'List (e.g. Glossary, Metadata)', 'short_description': 'List', }, } diff --git a/taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py b/taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py index a85fc12de..2a59bc45a 100644 --- a/taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py +++ b/taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.16 on 2021-08-05 05:05 +# Generated by Django 2.2.16 on 2021-08-06 04:17 from django.db import migrations, models import django.db.models.deletion @@ -19,7 +19,7 @@ class Migration(migrations.Migration): fields=[ ('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='taccsite_data_list_taccsitedatalist', serialize=False, to='cms.CMSPlugin')), ('orientation', models.CharField(choices=[('horizontal', 'Horizontal (all data on one row)'), ('vertical', 'Vertical (every label and value has its own row)')], help_text='The direction in which to lay out the data. Hint: Choose based on the amount of space available in the layout for the data.', max_length=255, verbose_name='Orientation')), - ('type_style', models.CharField(choices=[('table', 'Tabular Data (ex: Columns; Table, no Header)'), ('dlist', 'List of Data (ex: Glossary; Metadata; List)')], help_text='The type of data to display, glossary/metadata or tabular. Notice: Each type of list has a slightly different style.', max_length=255, verbose_name='Type / Style')), + ('type_style', models.CharField(choices=[('table', 'Table (e.g. Columns)'), ('dlist', 'List (e.g. Glossary, Metadata)')], help_text='The type of data to display, glossary/metadata or tabular. Notice: Each type of list has a slightly different style.', max_length=255, verbose_name='Type / Style')), ('density', models.CharField(choices=[('default', 'Default (ample extra space)'), ('compact', 'Compact (minimal extra space)')], help_text='The amount of extra space in the layout. Hint: Choose based on the amount of space available in the layout for the data.', max_length=255, verbose_name='Density (Layout Spacing)')), ('truncate_values', models.BooleanField(default=False, help_text='Truncate values if there is not enough space to show the label and the value. Notice: Labels are truncated as necessary.', verbose_name='Truncate the values (as necessary)')), ('attributes', djangocms_attributes_field.fields.AttributesField(default=dict)), @@ -29,4 +29,17 @@ class Migration(migrations.Migration): }, bases=('cms.cmsplugin',), ), + migrations.CreateModel( + name='TaccsiteDataListItem', + fields=[ + ('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='taccsite_data_list_taccsitedatalistitem', serialize=False, to='cms.CMSPlugin')), + ('key', models.CharField(help_text='The label for the item value.', max_length=50, verbose_name='Label')), + ('value', models.CharField(help_text='The data value.', max_length=100, verbose_name='Value')), + ('attributes', djangocms_attributes_field.fields.AttributesField(default=dict)), + ], + options={ + 'abstract': False, + }, + bases=('cms.cmsplugin',), + ), ] diff --git a/taccsite_cms/contrib/taccsite_data_list/models.py b/taccsite_cms/contrib/taccsite_data_list/models.py index f2ed24480..ff07a26f9 100644 --- a/taccsite_cms/contrib/taccsite_data_list/models.py +++ b/taccsite_cms/contrib/taccsite_data_list/models.py @@ -60,3 +60,35 @@ def get_short_description(self): density = DENSITY_DICT[self.density]['short_description'] return density + ', ' + orientation + ' ' + type_style + +class TaccsiteDataListItem(CMSPlugin): + """ + Components > "Data List Item" Model + """ + key = models.CharField( + verbose_name=_('Label'), + help_text=_('The label for the item value.'), + blank=False, + max_length=50, + ) + value = models.CharField( + verbose_name=_('Value'), + help_text=_('The data value.'), + blank=False, + max_length=100, + ) + + attributes = fields.AttributesField() + + def get_short_description(self): + key = self.key + val = self.value + max_len = 4 + + should_truncate_key = len(key) > max_len + key_desc = key[0:max_len] + '…' if should_truncate_key else key + + should_truncate_val = len(key) > max_len + val_desc = val[0:max_len] + '…' if should_truncate_val else val + + return key_desc + ': ' + val_desc diff --git a/taccsite_cms/contrib/taccsite_data_list/templates/data_list.html b/taccsite_cms/contrib/taccsite_data_list/templates/data_list.html index 9899137b6..d6c38f17c 100644 --- a/taccsite_cms/contrib/taccsite_data_list/templates/data_list.html +++ b/taccsite_cms/contrib/taccsite_data_list/templates/data_list.html @@ -1,7 +1,21 @@ -{% load static %} +{% load cms_tags %} + +{% if instance.type_style == 'dlist' %}
{% for plugin_instance in instance.child_plugin_instances %} - {# {% render_plugin plugin_instance %} #} + {% render_plugin plugin_instance %} {% endfor %}
+ +{% elif instance.type_style == 'table' %} + + + + {% for plugin_instance in instance.child_plugin_instances %} + {% render_plugin plugin_instance %} + {% endfor %} + +
+ +{% endif %} diff --git a/taccsite_cms/contrib/taccsite_data_list/templates/data_list_item.html b/taccsite_cms/contrib/taccsite_data_list/templates/data_list_item.html new file mode 100644 index 000000000..18f53d456 --- /dev/null +++ b/taccsite_cms/contrib/taccsite_data_list/templates/data_list_item.html @@ -0,0 +1,15 @@ +{% load cms_tags %} + +{% if parent_plugin_instance.type_style == 'dlist' %} + +
{{ instance.key }}
+
{{ instance.value }}
+ +{% elif parent_plugin_instance.type_style == 'table' %} + + + {{ instance.key }} + {{ instance.value }} + + +{% endif %} From 39fc77b82fe24b800b70341ad3dce563f914486e Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Fri, 6 Aug 2021 15:50:40 -0500 Subject: [PATCH 03/15] GH-75: Data List - Plugin: Support Label Link --- taccsite_cms/contrib/taccsite_data_list/TODO.md | 2 +- .../contrib/taccsite_data_list/cms_plugins.py | 11 +++++++++-- .../taccsite_data_list/migrations/0001_initial.py | 5 +++-- taccsite_cms/contrib/taccsite_data_list/models.py | 7 ++++++- .../taccsite_data_list/templates/data_list_item.html | 10 ++++++---- .../templates/data_list_item_key.html | 9 +++++++++ 6 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 taccsite_cms/contrib/taccsite_data_list/templates/data_list_item_key.html diff --git a/taccsite_cms/contrib/taccsite_data_list/TODO.md b/taccsite_cms/contrib/taccsite_data_list/TODO.md index 11a7fe6c5..10ed2591a 100644 --- a/taccsite_cms/contrib/taccsite_data_list/TODO.md +++ b/taccsite_cms/contrib/taccsite_data_list/TODO.md @@ -1,3 +1,3 @@ # To Do -- [ ] Add missing link feature to "Data List Item" plugin. +- [ ] Support label that is link within text. → GH-306 diff --git a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py index bcbb0a23f..4f280c658 100644 --- a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py +++ b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py @@ -5,6 +5,8 @@ from taccsite_cms.contrib.helpers import concat_classnames from taccsite_cms.contrib.taccsite_offset.cms_plugins import get_direction_classname +from taccsite_cms.contrib.helpers import AbstractMaxChildrenPlugin + from .models import TaccsiteDataList, TaccsiteDataListItem from .constants import ORIENTATION_DICT, TYPE_STYLE_DICT, DENSITY_DICT @@ -21,7 +23,7 @@ def get_classname(dict, value): # Plugins @plugin_pool.register_plugin -class TaccsiteDataListPlugin(CMSPluginBase): +class TaccsiteDataListPlugin(CMSPluginBase, AbstractMaxChildrenPlugin): """ Components > "Data List" Plugin https://confluence.tacc.utexas.edu/x/EiIFDg @@ -91,12 +93,17 @@ class TaccsiteDataListItemPlugin(CMSPluginBase): cache = True text_enabled = False - allow_children = False + allow_children = True + child_classes = [ + 'LinkPlugin' + ] + max_children = 1 # Only a label until we know what value will need fieldsets = [ (None, { 'fields': ( ('key', 'value'), + ('use_plugin_as_key'), ) }) ] diff --git a/taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py b/taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py index 2a59bc45a..2c82520b9 100644 --- a/taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py +++ b/taccsite_cms/contrib/taccsite_data_list/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.16 on 2021-08-06 04:17 +# Generated by Django 2.2.16 on 2021-08-06 20:17 from django.db import migrations, models import django.db.models.deletion @@ -33,8 +33,9 @@ class Migration(migrations.Migration): name='TaccsiteDataListItem', fields=[ ('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='taccsite_data_list_taccsitedatalistitem', serialize=False, to='cms.CMSPlugin')), - ('key', models.CharField(help_text='The label for the item value.', max_length=50, verbose_name='Label')), + ('key', models.CharField(help_text='A label for the data value. To create a link, add a child plugin.', max_length=50, verbose_name='Label')), ('value', models.CharField(help_text='The data value.', max_length=100, verbose_name='Value')), + ('use_plugin_as_key', models.BooleanField(default=True, help_text='If a child plugin is added, and this option is checked, then the child plugin will be used (not the Label field text).', verbose_name='Support child plugin for Label')), ('attributes', djangocms_attributes_field.fields.AttributesField(default=dict)), ], options={ diff --git a/taccsite_cms/contrib/taccsite_data_list/models.py b/taccsite_cms/contrib/taccsite_data_list/models.py index ff07a26f9..4d1190647 100644 --- a/taccsite_cms/contrib/taccsite_data_list/models.py +++ b/taccsite_cms/contrib/taccsite_data_list/models.py @@ -67,7 +67,7 @@ class TaccsiteDataListItem(CMSPlugin): """ key = models.CharField( verbose_name=_('Label'), - help_text=_('The label for the item value.'), + help_text=_('A label for the data value. To create a link, add a child plugin.'), blank=False, max_length=50, ) @@ -77,6 +77,11 @@ class TaccsiteDataListItem(CMSPlugin): blank=False, max_length=100, ) + use_plugin_as_key = models.BooleanField( + verbose_name=_('Support child plugin for Label'), + help_text=_('If a child plugin is added, and this option is checked, then the child plugin will be used (not the Label field text).'), + default=True, + ) attributes = fields.AttributesField() diff --git a/taccsite_cms/contrib/taccsite_data_list/templates/data_list_item.html b/taccsite_cms/contrib/taccsite_data_list/templates/data_list_item.html index 18f53d456..0ed71f277 100644 --- a/taccsite_cms/contrib/taccsite_data_list/templates/data_list_item.html +++ b/taccsite_cms/contrib/taccsite_data_list/templates/data_list_item.html @@ -1,14 +1,16 @@ -{% load cms_tags %} - {% if parent_plugin_instance.type_style == 'dlist' %} -
{{ instance.key }}
+
+ {% include "./data_list_item_key.html" %} +
{{ instance.value }}
{% elif parent_plugin_instance.type_style == 'table' %} - {{ instance.key }} + + {% include "./data_list_item_key.html" %} + {{ instance.value }} diff --git a/taccsite_cms/contrib/taccsite_data_list/templates/data_list_item_key.html b/taccsite_cms/contrib/taccsite_data_list/templates/data_list_item_key.html new file mode 100644 index 000000000..a6cc3ad86 --- /dev/null +++ b/taccsite_cms/contrib/taccsite_data_list/templates/data_list_item_key.html @@ -0,0 +1,9 @@ +{% load cms_tags %} + +{% if instance.use_plugin_as_key and instance.child_plugin_instances|length %} + {% for plugin_instance in instance.child_plugin_instances %} + {% render_plugin plugin_instance %} + {% endfor %} +{% else %} + {{ instance.key }} +{% endif %} From b17c416f7dc70fe9c76899d29f07f2950c058f7d Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Fri, 6 Aug 2021 20:49:19 -0500 Subject: [PATCH 04/15] GH-75: Data List - Plugin: Drop Text Support Do not enable text support, because one can not nest "Data List Item".* * Or, I found no way. --- taccsite_cms/contrib/taccsite_data_list/cms_plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py index 4f280c658..59fac2ad2 100644 --- a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py +++ b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py @@ -34,7 +34,7 @@ class TaccsiteDataListPlugin(CMSPluginBase, AbstractMaxChildrenPlugin): render_template = 'data_list.html' cache = True - text_enabled = True + text_enabled = False allow_children = True child_classes = [ 'TaccsiteDataListItemPlugin' From 889f1dc4ce3198b40dafaa4a50c392ca9fb3f56e Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Mon, 9 Aug 2021 11:31:47 -0500 Subject: [PATCH 05/15] GH-75: Data List - Plugin: Remove TODO --- taccsite_cms/contrib/taccsite_data_list/TODO.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 taccsite_cms/contrib/taccsite_data_list/TODO.md diff --git a/taccsite_cms/contrib/taccsite_data_list/TODO.md b/taccsite_cms/contrib/taccsite_data_list/TODO.md deleted file mode 100644 index 10ed2591a..000000000 --- a/taccsite_cms/contrib/taccsite_data_list/TODO.md +++ /dev/null @@ -1,3 +0,0 @@ -# To Do - -- [ ] Support label that is link within text. → GH-306 From 75b219c761ff5e14fd4062bc194b343a6a05c12f Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Mon, 9 Aug 2021 12:49:23 -0500 Subject: [PATCH 06/15] GH-75: Cleanup import. Provide missing helpers. --- taccsite_cms/contrib/helpers.py | 68 +++++++++++++++++++ .../contrib/taccsite_data_list/cms_plugins.py | 8 +-- 2 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 taccsite_cms/contrib/helpers.py diff --git a/taccsite_cms/contrib/helpers.py b/taccsite_cms/contrib/helpers.py new file mode 100644 index 000000000..0a63d3646 --- /dev/null +++ b/taccsite_cms/contrib/helpers.py @@ -0,0 +1,68 @@ +# Get Django `models.CharField` `choices` +def get_choices(choice_dict): + """Get a sequence for a Django model field choices from a dictionary. + :param Dict[str, Dict[str, str]] dictionary: choice as key for dictionary of classnames and descriptions + :return: a sequence for django.db.models.CharField.choices + :rtype: List[Tuple[str, str], ...] + """ + choices = [] + + for key, data in choice_dict.items(): + choice = (key, data['description']) + choices.append(choice) + + return choices + + + +# GH-93, GH-142, GH-133: Upcoming functions here (ease merge conflict, maybe) + + + +# Concatenate a list of CSS classes +# SEE: https://github.com/django-cms/djangocms-bootstrap4/blob/master/djangocms_bootstrap4/helpers.py +def concat_classnames(classes): + """Concatenate a list of classname strings (without failing on None)""" + # SEE: https://stackoverflow.com/a/20271297/11817077 + return ' '.join(_class for _class in classes if _class) + + + +# GH-93, GH-142, GH-133: Upcoming functions here (ease merge conflict, maybe) + + + +# Allow plugins to set max number of nested children + +from django.shortcuts import render + +# SEE: https://github.com/django-cms/django-cms/issues/5102#issuecomment-597150141 +class AbstractMaxChildrenPlugin(): + """ + Abstract extension of `CMSPluginBase` that allows setting maximum amount of nested/child plugins. + Usage: + 1. Extend this class, + after extending `CMSPluginBase` or a class that extends `CMSPluginBase`. + 2. Set `max_children` to desired limit. + """ + + max_children = None + + def add_view(self,request, form_url='', extra_context=None): + + if self.max_children: + # FAQ: Placeholders do not have a parent, only plugins do + if self._cms_initial_attributes['parent']: + num_allowed = len([v for v in self._cms_initial_attributes['parent'].get_children() if v.get_plugin_instance()[0] is not None]) + else: + num_allowed = len([v for v in self.placeholder.get_plugins() if v.get_plugin_instance()[0] is not None and v.get_plugin_name() == self.name]) + + if num_allowed >= self.max_children: + return render(request , "path/to/your/max_reached_template.html", { + 'max_children': self.max_children, + }) + return super(AbstractMaxChildrenPlugin, self).add_view(request, form_url, extra_context) + + + +# GH-93, GH-142, GH-133: Upcoming functions here (ease merge conflict, maybe) diff --git a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py index 59fac2ad2..580caf424 100644 --- a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py +++ b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py @@ -2,10 +2,10 @@ from cms.plugin_pool import plugin_pool from django.utils.translation import gettext_lazy as _ -from taccsite_cms.contrib.helpers import concat_classnames -from taccsite_cms.contrib.taccsite_offset.cms_plugins import get_direction_classname - -from taccsite_cms.contrib.helpers import AbstractMaxChildrenPlugin +from taccsite_cms.contrib.helpers import ( + concat_classnames, + AbstractMaxChildrenPlugin +) from .models import TaccsiteDataList, TaccsiteDataListItem from .constants import ORIENTATION_DICT, TYPE_STYLE_DICT, DENSITY_DICT From 041680dda35769d89eb99b1976d445670419841f Mon Sep 17 00:00:00 2001 From: "W. Bomar" <62723358+tacc-wbomar@users.noreply.github.com> Date: Thu, 12 Aug 2021 17:20:21 -0500 Subject: [PATCH 07/15] Update taccsite_cms/contrib/helpers.py Co-authored-by: Ian Park --- taccsite_cms/contrib/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taccsite_cms/contrib/helpers.py b/taccsite_cms/contrib/helpers.py index 0a63d3646..48efaec00 100644 --- a/taccsite_cms/contrib/helpers.py +++ b/taccsite_cms/contrib/helpers.py @@ -48,7 +48,7 @@ class AbstractMaxChildrenPlugin(): max_children = None - def add_view(self,request, form_url='', extra_context=None): + def add_view(self, request, form_url='', extra_context=None): if self.max_children: # FAQ: Placeholders do not have a parent, only plugins do From e7c6e655a592dd8d54d94b137596ecb5e9ae4807 Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Thu, 12 Aug 2021 19:37:06 -0500 Subject: [PATCH 08/15] GH-75: Update submod (merge main) --- taccsite_custom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taccsite_custom b/taccsite_custom index 4330d0cda..23ab68ff3 160000 --- a/taccsite_custom +++ b/taccsite_custom @@ -1 +1 @@ -Subproject commit 4330d0cdaf209310567312e3b59878fd7c175494 +Subproject commit 23ab68ff3b1560b16858f9c1e877a3a2354e7e62 From e224ea6f37d78243057959283be5f97bdb3523bd Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Thu, 12 Aug 2021 20:10:18 -0500 Subject: [PATCH 09/15] GH-75: Tell user how add link to "Data List Item" --- taccsite_cms/contrib/constants.py | 7 +++++++ .../contrib/taccsite_data_list/cms_plugins.py | 20 +++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 taccsite_cms/contrib/constants.py diff --git a/taccsite_cms/contrib/constants.py b/taccsite_cms/contrib/constants.py new file mode 100644 index 000000000..169450392 --- /dev/null +++ b/taccsite_cms/contrib/constants.py @@ -0,0 +1,7 @@ +TEXT_FOR_NESTED_PLUGIN_CONTENT_SWAP = '\ +
\ +
To add {element},
\ +
nest "{plugin_name}" plugin inside this plugin.
\ +
To edit {element},
\ +
edit existing nested "{plugin_name}" plugin.
\ +
' diff --git a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py index 580caf424..30f408ab9 100644 --- a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py +++ b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py @@ -2,6 +2,7 @@ from cms.plugin_pool import plugin_pool from django.utils.translation import gettext_lazy as _ +from taccsite_cms.contrib.constants import TEXT_FOR_NESTED_PLUGIN_CONTENT_SWAP from taccsite_cms.contrib.helpers import ( concat_classnames, AbstractMaxChildrenPlugin @@ -103,8 +104,23 @@ class TaccsiteDataListItemPlugin(CMSPluginBase): (None, { 'fields': ( ('key', 'value'), - ('use_plugin_as_key'), - ) + ), + }), + (_('Link'), { + 'classes': ('collapse',), + 'description': TEXT_FOR_NESTED_PLUGIN_CONTENT_SWAP.format( + element='a link', + plugin_name='Link' + ) + '\ +
\ + The "Link" plugin\'s "Display name" field takes precedence over this plugin\'s "Label" field. If "Link" pluign is not rendered, then check "Advanced settings" of this plugin.', + 'fields': (), + }), + (_('Advanced settings'), { + 'classes': ('collapse',), + 'fields': ( + 'use_plugin_as_key', + ), }) ] From a7c6ae4241e20ba0a27be1019ec63cdaa38b193a Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Thu, 12 Aug 2021 20:10:58 -0500 Subject: [PATCH 10/15] GH-75: Allow empty Label field So smart user can add "Link" sans "Data List Item" Label text. --- taccsite_cms/contrib/taccsite_data_list/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/taccsite_cms/contrib/taccsite_data_list/models.py b/taccsite_cms/contrib/taccsite_data_list/models.py index 4d1190647..e1562c822 100644 --- a/taccsite_cms/contrib/taccsite_data_list/models.py +++ b/taccsite_cms/contrib/taccsite_data_list/models.py @@ -67,8 +67,8 @@ class TaccsiteDataListItem(CMSPlugin): """ key = models.CharField( verbose_name=_('Label'), - help_text=_('A label for the data value. To create a link, add a child plugin.'), - blank=False, + help_text=_('A label for the data value.'), + blank=True, max_length=50, ) value = models.CharField( From 4fbf1e2244d07235b206c89e01593c7e33f200bf Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Thu, 12 Aug 2021 20:11:27 -0500 Subject: [PATCH 11/15] GH-75: Add missing padding to Data List row --- .../site_cms/css/src/_imports/components/c-data-list.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/taccsite_cms/static/site_cms/css/src/_imports/components/c-data-list.css b/taccsite_cms/static/site_cms/css/src/_imports/components/c-data-list.css index 374ac3c97..9a197d2d2 100644 --- a/taccsite_cms/static/site_cms/css/src/_imports/components/c-data-list.css +++ b/taccsite_cms/static/site_cms/css/src/_imports/components/c-data-list.css @@ -58,6 +58,12 @@ table.c-data-list { } } +/* To space out elements (tables) */ +th.c-data-list__key, +td.c-data-list__value { + padding-block: 0.5em; +} + /* To add colon (non-tables) */ .c-data-list__key:not(th)::after { content: ':'; From b30cbd01f02b6dedf19fbac52b5b8119a311b283 Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Thu, 12 Aug 2021 20:40:26 -0500 Subject: [PATCH 12/15] GH-75: Get dict value consistently --- taccsite_cms/contrib/taccsite_data_list/models.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/taccsite_cms/contrib/taccsite_data_list/models.py b/taccsite_cms/contrib/taccsite_data_list/models.py index e1562c822..9b77c001f 100644 --- a/taccsite_cms/contrib/taccsite_data_list/models.py +++ b/taccsite_cms/contrib/taccsite_data_list/models.py @@ -11,6 +11,14 @@ +# Helpers + +def get_short_descritpion(dict, value): + """Get layout class based on value.""" + return dict.get(value, {}).get('short_description') + + + # Constants ORIENTATION_CHOICES = get_choices(ORIENTATION_DICT) @@ -55,9 +63,9 @@ class TaccsiteDataList(CMSPlugin): attributes = fields.AttributesField() def get_short_description(self): - orientation = ORIENTATION_DICT[self.orientation]['short_description'] - type_style = TYPE_STYLE_DICT[self.type_style]['short_description'] - density = DENSITY_DICT[self.density]['short_description'] + orientation = get_short_descritpion(ORIENTATION_DICT, self.orientation) + type_style = get_short_descritpion(TYPE_STYLE_DICT, self.type_style) + density = get_short_descritpion(DENSITY_DICT, self.density) return density + ', ' + orientation + ' ' + type_style From 2c174cf9c9a3c1a33ecf09422a244cdcdcfc77a3 Mon Sep 17 00:00:00 2001 From: Wesley Bomar Date: Thu, 12 Aug 2021 21:44:18 -0500 Subject: [PATCH 13/15] GH-75: Remove AbstractMaxChildrenPlugin helper It does not seem to work, so I am removing it. Without it, lable can be multiple links... that's okay. --- taccsite_cms/contrib/helpers.py | 37 ------------------- .../contrib/taccsite_data_list/cms_plugins.py | 7 +--- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/taccsite_cms/contrib/helpers.py b/taccsite_cms/contrib/helpers.py index 48efaec00..f26f86cf5 100644 --- a/taccsite_cms/contrib/helpers.py +++ b/taccsite_cms/contrib/helpers.py @@ -28,41 +28,4 @@ def concat_classnames(classes): -# GH-93, GH-142, GH-133: Upcoming functions here (ease merge conflict, maybe) - - - -# Allow plugins to set max number of nested children - -from django.shortcuts import render - -# SEE: https://github.com/django-cms/django-cms/issues/5102#issuecomment-597150141 -class AbstractMaxChildrenPlugin(): - """ - Abstract extension of `CMSPluginBase` that allows setting maximum amount of nested/child plugins. - Usage: - 1. Extend this class, - after extending `CMSPluginBase` or a class that extends `CMSPluginBase`. - 2. Set `max_children` to desired limit. - """ - - max_children = None - - def add_view(self, request, form_url='', extra_context=None): - - if self.max_children: - # FAQ: Placeholders do not have a parent, only plugins do - if self._cms_initial_attributes['parent']: - num_allowed = len([v for v in self._cms_initial_attributes['parent'].get_children() if v.get_plugin_instance()[0] is not None]) - else: - num_allowed = len([v for v in self.placeholder.get_plugins() if v.get_plugin_instance()[0] is not None and v.get_plugin_name() == self.name]) - - if num_allowed >= self.max_children: - return render(request , "path/to/your/max_reached_template.html", { - 'max_children': self.max_children, - }) - return super(AbstractMaxChildrenPlugin, self).add_view(request, form_url, extra_context) - - - # GH-93, GH-142, GH-133: Upcoming functions here (ease merge conflict, maybe) diff --git a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py index 30f408ab9..0f53ee24d 100644 --- a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py +++ b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py @@ -3,10 +3,7 @@ from django.utils.translation import gettext_lazy as _ from taccsite_cms.contrib.constants import TEXT_FOR_NESTED_PLUGIN_CONTENT_SWAP -from taccsite_cms.contrib.helpers import ( - concat_classnames, - AbstractMaxChildrenPlugin -) +from taccsite_cms.contrib.helpers import concat_classnames from .models import TaccsiteDataList, TaccsiteDataListItem from .constants import ORIENTATION_DICT, TYPE_STYLE_DICT, DENSITY_DICT @@ -24,7 +21,7 @@ def get_classname(dict, value): # Plugins @plugin_pool.register_plugin -class TaccsiteDataListPlugin(CMSPluginBase, AbstractMaxChildrenPlugin): +class TaccsiteDataListPlugin(CMSPluginBase): """ Components > "Data List" Plugin https://confluence.tacc.utexas.edu/x/EiIFDg From bb5a786a51386a79b033569bf6a159d38f9503af Mon Sep 17 00:00:00 2001 From: "W. Bomar" <62723358+tacc-wbomar@users.noreply.github.com> Date: Tue, 17 Aug 2021 16:41:57 -0500 Subject: [PATCH 14/15] GH-75: Bugfix: Fix typo in user-facing text Co-authored-by: Ian Park --- taccsite_cms/contrib/taccsite_data_list/cms_plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py index 0f53ee24d..fece7a03f 100644 --- a/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py +++ b/taccsite_cms/contrib/taccsite_data_list/cms_plugins.py @@ -110,7 +110,7 @@ class TaccsiteDataListItemPlugin(CMSPluginBase): plugin_name='Link' ) + '\
\ - The "Link" plugin\'s "Display name" field takes precedence over this plugin\'s "Label" field. If "Link" pluign is not rendered, then check "Advanced settings" of this plugin.', + The "Link" plugin\'s "Display name" field takes precedence over this plugin\'s "Label" field. If "Link" plugin is not rendered, then check "Advanced settings" of this plugin.', 'fields': (), }), (_('Advanced settings'), { From f2264ced5b7d77660ea5d0f5165ccf10c5a143f0 Mon Sep 17 00:00:00 2001 From: "W. Bomar" <62723358+tacc-wbomar@users.noreply.github.com> Date: Tue, 17 Aug 2021 16:46:35 -0500 Subject: [PATCH 15/15] GH-75: Noop: Fix consistent typo get_short_descritpion I consistently misspelled local function name. I did not misspell model method of the same name. Co-authored-by: Ian Park --- taccsite_cms/contrib/taccsite_data_list/models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/taccsite_cms/contrib/taccsite_data_list/models.py b/taccsite_cms/contrib/taccsite_data_list/models.py index 9b77c001f..750698739 100644 --- a/taccsite_cms/contrib/taccsite_data_list/models.py +++ b/taccsite_cms/contrib/taccsite_data_list/models.py @@ -13,7 +13,7 @@ # Helpers -def get_short_descritpion(dict, value): +def get_short_description(dict, value): """Get layout class based on value.""" return dict.get(value, {}).get('short_description') @@ -63,9 +63,9 @@ class TaccsiteDataList(CMSPlugin): attributes = fields.AttributesField() def get_short_description(self): - orientation = get_short_descritpion(ORIENTATION_DICT, self.orientation) - type_style = get_short_descritpion(TYPE_STYLE_DICT, self.type_style) - density = get_short_descritpion(DENSITY_DICT, self.density) + orientation = get_short_description(ORIENTATION_DICT, self.orientation) + type_style = get_short_description(TYPE_STYLE_DICT, self.type_style) + density = get_short_description(DENSITY_DICT, self.density) return density + ', ' + orientation + ' ' + type_style