Repository: shuup/shuup

Issue:
Add option for extra class in xtheme layout cell
Plan is that after this merchant can define some css at snippet admin.

Tip: https://github.com/shuup/shuup/blob/master/shuup/xtheme/views/forms.py#L15


Discussion:

Resolving patch:
diff --git a/shuup/xtheme/layout/_base.py b/shuup/xtheme/layout/_base.py
--- a/shuup/xtheme/layout/_base.py
+++ b/shuup/xtheme/layout/_base.py
@@ -19,7 +19,7 @@ class LayoutCell(object):
     A single cell in a layout. Maps to Bootstrap's `col-XX-XX` classes.
     """
 
-    def __init__(self, theme, plugin_identifier, config=None, sizes=None, align=""):
+    def __init__(self, theme, plugin_identifier, config=None, sizes=None, align="", extra_classes=""):
         """
         Initialize a layout cell with a given plugin, config and sizing configuration.
 
@@ -37,6 +37,7 @@ def __init__(self, theme, plugin_identifier, config=None, sizes=None, align=""):
         self.plugin_identifier = plugin_identifier
         self.config = config or {}
         self.align = align
+        self.extra_classes = extra_classes
 
     @property
     def plugin_class(self):
@@ -105,7 +106,8 @@ def unserialize(cls, theme, data):
             plugin_identifier=data.get("plugin"),
             config=data.get("config"),
             sizes=data.get("sizes"),
-            align=data.get("align", "")
+            align=data.get("align", ""),
+            extra_classes=data.get("extra_classes", "")
         )
 
     def serialize(self):
@@ -119,7 +121,8 @@ def serialize(self):
             ("plugin", self.plugin_identifier),
             ("config", self.config),
             ("sizes", self.sizes),
-            ("align", self.align)
+            ("align", self.align),
+            ("extra_classes", self.extra_classes),
         ) if k and v)
 
 
diff --git a/shuup/xtheme/rendering.py b/shuup/xtheme/rendering.py
--- a/shuup/xtheme/rendering.py
+++ b/shuup/xtheme/rendering.py
@@ -213,6 +213,8 @@ def _render_cell(self, write, layout, x, cell):
                 classes.append(layout.cell_class_template % {"breakpoint": breakpoint, "width": width})
 
         classes.append(cell.align)
+        if cell.extra_classes:
+            classes.append(cell.extra_classes)
 
         cell_attrs = {
             "class": classes
diff --git a/shuup/xtheme/views/forms.py b/shuup/xtheme/views/forms.py
--- a/shuup/xtheme/views/forms.py
+++ b/shuup/xtheme/views/forms.py
@@ -52,6 +52,14 @@ def populate(self):
             self.fields["cell_align"] = forms.ChoiceField(
                 label=_("Cell align"), choices=self.CELL_ALIGN_CHOICES, initial=initial_cell_align)
 
+            initial_cell_style = self.layout_cell.extra_classes or ""
+            self.fields["cell_extra_classes"] = forms.CharField(
+                label=_("Extra classes"),
+                help_text=_("Add extra CSS classes names to the cell"),
+                initial=initial_cell_style,
+                required=False
+            )
+
         if self.theme:
             plugin_choices = self.theme.get_all_plugin_choices(empty_label=_("No Plugin"))
             plugin_field = self.fields["plugin"]
@@ -73,6 +81,7 @@ def save(self):
             self.layout_cell.sizes[size] = int(data["cell_width"])
 
         self.layout_cell.align = data["cell_align"]
+        self.layout_cell.extra_classes = data["cell_extra_classes"].strip()
 
 
 class LayoutCellFormGroup(FormGroup):


Test patch:
diff --git a/shuup_tests/browser/front/test_gdpr_consent.py b/shuup_tests/browser/front/test_gdpr_consent.py
--- a/shuup_tests/browser/front/test_gdpr_consent.py
+++ b/shuup_tests/browser/front/test_gdpr_consent.py
@@ -12,7 +12,7 @@
 
 from shuup.gdpr.models import GDPRSettings
 from shuup.testing.browser_utils import (
-    click_element, wait_until_appeared
+    click_element, wait_until_appeared, wait_until_condition
 )
 from shuup.testing.factories import get_default_shop
 from shuup.testing.utils import initialize_front_browser_test
@@ -23,8 +23,6 @@
 @pytest.mark.browser
 @pytest.mark.djangodb
 def test_gdpr_consent(browser, live_server, settings):
-    browser = initialize_front_browser_test(browser, live_server)
-
     shop = get_default_shop()
     index_url = reverse("shuup:index")
 
@@ -35,10 +33,11 @@ def test_gdpr_consent(browser, live_server, settings):
     shop_gdpr.enabled = True
     shop_gdpr.save() # Enable GDPR
 
+    browser = initialize_front_browser_test(browser, live_server)
     browser.visit("%s%s" % (live_server, index_url))
     wait_until_appeared(browser, ".gdpr-consent-warn-bar")
     assert (len(browser.find_by_css(".gdpr-consent-preferences")) == 1)
     click_element(browser, "#agree-btn")
 
-    assert len(browser.find_by_css(".gdpr-consent-warn-bar")) == 0
-    assert len(browser.find_by_css(".gdpr-consent-preferences")) == 0
+    wait_until_condition(browser, lambda x: len(x.find_by_css(".gdpr-consent-warn-bar")) == 0)
+    wait_until_condition(browser, lambda x: len(x.find_by_css(".gdpr-consent-preferences")) == 0)
diff --git a/shuup_tests/xtheme/test_editor_forms.py b/shuup_tests/xtheme/test_editor_forms.py
--- a/shuup_tests/xtheme/test_editor_forms.py
+++ b/shuup_tests/xtheme/test_editor_forms.py
@@ -41,7 +41,8 @@ def test_formless_plugin_in_lcfg(rf):
             lcfg = LayoutCellFormGroup(
                 data={
                     "general-cell_width": "%d" % two_thirds,
-                    "general-cell_align": "pull-right"
+                    "general-cell_align": "pull-right",
+                    "general-cell_extra_classes" : "newClass",
                 },
                 layout_cell=cell,
                 theme=theme,
@@ -51,6 +52,7 @@ def test_formless_plugin_in_lcfg(rf):
             assert "plugin" not in lcfg.forms
             assert lcfg.is_valid()
             lcfg.save()
+            assert cell.extra_classes == "newClass"
             assert cell.sizes["md"] == two_thirds  # Something got saved even if the plugin doesn't need config
 
 
@@ -70,6 +72,7 @@ def test_lcfg(rf):
                 data={
                     "general-cell_width": "%d" % two_thirds,
                     "general-cell_align": " ",
+                    "general-cell_extra_classes" : "newClass",
                     "plugin-text_*": "Hello, world!"
                 },
                 layout_cell=cell,
@@ -79,4 +82,5 @@ def test_lcfg(rf):
             assert lcfg.is_valid()  # Let's see now!
             lcfg.save()
             assert cell.sizes["md"] == two_thirds
+            assert cell.extra_classes == "newClass"
             assert cell.config["text"] == {FALLBACK_LANGUAGE_CODE: "Hello, world!"}