diff --git a/corehq/apps/app_execution/forms.py b/corehq/apps/app_execution/forms.py index 317500f3c30e..7e6e40f0d1db 100644 --- a/corehq/apps/app_execution/forms.py +++ b/corehq/apps/app_execution/forms.py @@ -57,7 +57,6 @@ def __init__(self, request, *args, **kwargs): if self.instance.id: self.fields["username"].initial = self.instance.django_user.username self.helper = hqcrispy.HQFormHelper() - self.helper.form_class = "form-horizontal" fields = [ "name", diff --git a/corehq/apps/domain/forms.py b/corehq/apps/domain/forms.py index 536a229e0115..68584dbbd973 100644 --- a/corehq/apps/domain/forms.py +++ b/corehq/apps/domain/forms.py @@ -1275,7 +1275,6 @@ def __init__(self, domain, can_edit_eula, *args, user, **kwargs): ) self.helper = hqcrispy.HQFormHelper() - self.helper.form_class = "form-horizontal" self.helper.layout = crispy.Layout( crispy.Fieldset( _("Basic Information"), diff --git a/corehq/apps/hqwebapp/crispy.py b/corehq/apps/hqwebapp/crispy.py index fceb944f7fa9..f86d05b17762 100644 --- a/corehq/apps/hqwebapp/crispy.py +++ b/corehq/apps/hqwebapp/crispy.py @@ -1,4 +1,3 @@ -import re from contextlib import contextmanager from django.forms.widgets import DateTimeInput from django.template.loader import render_to_string @@ -13,11 +12,9 @@ from crispy_forms.layout import LayoutObject from crispy_forms.utils import flatatt, get_template_pack, render_field -CSS_LABEL_CLASS = 'col-xs-12 col-sm-4 col-md-4 col-lg-2' -CSS_LABEL_CLASS_BOOTSTRAP5 = 'col-xs-12 col-sm-4 col-md-4 col-lg-3' -CSS_FIELD_CLASS = 'col-xs-12 col-sm-8 col-md-8 col-lg-6' -CSS_FIELD_CLASS_BOOTSTRAP5 = 'col-xs-12 col-sm-8 col-md-8 col-lg-9' -CSS_ACTION_CLASS = CSS_FIELD_CLASS + ' col-sm-offset-4 col-md-offset-4 col-lg-offset-2' +CSS_LABEL_CLASS = 'field-label' +CSS_FIELD_CLASS = 'field-control' +CSS_ACTION_CLASS = CSS_FIELD_CLASS class HQFormHelper(FormHelper): @@ -28,13 +25,7 @@ class HQFormHelper(FormHelper): def __init__(self, *args, **kwargs): super(HQFormHelper, self).__init__(*args, **kwargs) from corehq.apps.hqwebapp.utils.bootstrap import get_bootstrap_version, BOOTSTRAP_5 - bootstrap_version = get_bootstrap_version() - use_bootstrap5 = bootstrap_version == BOOTSTRAP_5 - if use_bootstrap5: - self.label_class = CSS_LABEL_CLASS_BOOTSTRAP5 - self.field_class = CSS_FIELD_CLASS_BOOTSTRAP5 - self.use_bootstrap5 = use_bootstrap5 - self.form_class = 'form' + self.use_bootstrap5 = get_bootstrap_version() == BOOTSTRAP_5 if 'autocomplete' not in self.attrs: self.attrs.update({ @@ -76,15 +67,7 @@ class ErrorsOnlyField(Field): def get_form_action_class(): - """This is only valid for bootstrap 5""" - return CSS_LABEL_CLASS_BOOTSTRAP5.replace('col', 'offset') + ' ' + CSS_FIELD_CLASS_BOOTSTRAP5 - - -def _get_offsets(context): - label_class = context.get('label_class', '') - use_bootstrap5 = context.get('use_bootstrap5') - return (label_class.replace('col', 'offset') if use_bootstrap5 - else re.sub(r'(xs|sm|md|lg)-', r'\g<1>-offset-', label_class)) + return CSS_FIELD_CLASS class FormActions(OriginalFormActions): @@ -102,11 +85,9 @@ def render(self, form, context, template_pack=None, **kwargs): template_pack=template_pack, ) fields_html = mark_safe(fields_html) # nosec: just concatenated safe fields - offsets = _get_offsets(context) context.update({ 'formactions': self, 'fields_output': fields_html, - 'offsets': offsets, 'field_class': context.get('field_class', '') }) return render_to_string(self.template, context.flatten()) diff --git a/corehq/apps/hqwebapp/static/hqwebapp/less/_hq/includes/extensions.less b/corehq/apps/hqwebapp/static/hqwebapp/less/_hq/includes/extensions.less new file mode 100644 index 000000000000..80394fb674dc --- /dev/null +++ b/corehq/apps/hqwebapp/static/hqwebapp/less/_hq/includes/extensions.less @@ -0,0 +1,16 @@ +.field-label { + &:extend(.col-xs-12, .col-sm-4, .col-md-4, .col-lg-2); +} + +.field-label + .field-control { + &:extend(.col-xs-12, .col-sm-8, .col-md-8, .col-lg-6); +} + +:not(.field-label) + .field-control, +.form-actions > .field-control:first-child, +.form-group > .field-control:first-child { + &:extend( + .col-sm-offset-4, .col-md-offset-4, .col-lg-offset-2, + .col-xs-12, .col-sm-8, .col-md-8, .col-lg-6 + ); +} diff --git a/corehq/apps/hqwebapp/static/hqwebapp/less/bootstrap.less b/corehq/apps/hqwebapp/static/hqwebapp/less/bootstrap.less index 29e6b786ecdd..f801d1b4b988 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/less/bootstrap.less +++ b/corehq/apps/hqwebapp/static/hqwebapp/less/bootstrap.less @@ -9,6 +9,7 @@ // Core variables and mixins @import "_hq/includes/variables.less"; @import "_hq/includes/mixins.less"; +@import "_hq/includes/extensions.less"; // Reset and dependencies @import "../../../../../../node_modules/bootstrap/less/normalize.less"; diff --git a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_forms.scss b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_forms.scss index 481acf947bd2..2f7aef91a69d 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_forms.scss +++ b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_forms.scss @@ -1,3 +1,16 @@ +.field-label { + @extend .col-form-label, .col-12, .col-sm-4, .col-md-3, .col-lg-2; +} + +.field-label + .field-control { + @extend .col-12, .col-sm-8, .col-md-9, .col-lg-10; +} + +:not(.field-label) + .field-control, +.row > .field-control:first-child { + @extend .offset-sm-4, .offset-md-3, .offset-lg-2; +} + .row > div > .form-check:first-child, .row > div > .input-group > .form-check:first-child { padding-top: add($input-padding-y, $input-border-width); diff --git a/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap3/form_actions.html b/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap3/form_actions.html index 00f51a85d933..1849503aa48d 100644 --- a/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap3/form_actions.html +++ b/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap3/form_actions.html @@ -1,5 +1,5 @@
-
+
{{ fields_output }}
diff --git a/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap5/field_with_addons.html b/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap5/field_with_addons.html index 2274c2b8f84a..4f3d98e148e7 100644 --- a/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap5/field_with_addons.html +++ b/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap5/field_with_addons.html @@ -5,7 +5,7 @@ {% else %}
{% if field.label and form_show_labels %}
diff --git a/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap5/form_actions.html b/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap5/form_actions.html index fe52406f6134..1c56acebb3e6 100644 --- a/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap5/form_actions.html +++ b/corehq/apps/hqwebapp/templates/hqwebapp/crispy/bootstrap5/form_actions.html @@ -1,5 +1,5 @@
-
+
{{ fields_output }}
diff --git a/corehq/apps/hqwebapp/templatetags/hq_shared_tags.py b/corehq/apps/hqwebapp/templatetags/hq_shared_tags.py index 70533be19c8f..c17a36543abc 100644 --- a/corehq/apps/hqwebapp/templatetags/hq_shared_tags.py +++ b/corehq/apps/hqwebapp/templatetags/hq_shared_tags.py @@ -246,19 +246,13 @@ def can_use_restore_as(request): @register.simple_tag def css_label_class(): - from corehq.apps.hqwebapp.crispy import CSS_LABEL_CLASS, CSS_LABEL_CLASS_BOOTSTRAP5 - from corehq.apps.hqwebapp.utils.bootstrap import get_bootstrap_version, BOOTSTRAP_5 - if get_bootstrap_version() == BOOTSTRAP_5: - return CSS_LABEL_CLASS_BOOTSTRAP5 + from corehq.apps.hqwebapp.crispy import CSS_LABEL_CLASS return CSS_LABEL_CLASS @register.simple_tag def css_field_class(): - from corehq.apps.hqwebapp.crispy import CSS_FIELD_CLASS, CSS_FIELD_CLASS_BOOTSTRAP5 - from corehq.apps.hqwebapp.utils.bootstrap import get_bootstrap_version, BOOTSTRAP_5 - if get_bootstrap_version() == BOOTSTRAP_5: - return CSS_FIELD_CLASS_BOOTSTRAP5 + from corehq.apps.hqwebapp.crispy import CSS_FIELD_CLASS return CSS_FIELD_CLASS diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/hqwebapp/crispy/field_with_addons.html.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/hqwebapp/crispy/field_with_addons.html.diff.txt index 849121b011e5..9fc37e2fb1ad 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/hqwebapp/crispy/field_with_addons.html.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/hqwebapp/crispy/field_with_addons.html.diff.txt @@ -5,7 +5,7 @@
{% if field.label and form_show_labels %}
diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/hqwebapp/crispy/form_actions.html.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/hqwebapp/crispy/form_actions.html.diff.txt index ffe8bfd29c8e..c719c0d4debd 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/hqwebapp/crispy/form_actions.html.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/hqwebapp/crispy/form_actions.html.diff.txt @@ -2,11 +2,11 @@ +++ @@ -1,5 +1,5 @@ -
--
+-
- {{ fields_output }} -
+
-+
++
+ {{ fields_output }} +
diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/forms._forms.style.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/forms._forms.style.diff.txt index 920cf155f13e..d123abd6edd2 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/forms._forms.style.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/forms._forms.style.diff.txt @@ -1,20 +1,19 @@ --- +++ -@@ -1,356 +1,7 @@ +@@ -1,356 +1,20 @@ -// FORM ACTIONS from TWBS 2 -// ------------ - -[ng\:cloak],[ng-cloak],.ng-cloak{ - display:none !important --} -- ++.field-label { ++ @extend .col-form-label, .col-12, .col-sm-4, .col-md-3, .col-lg-2; + } + -.form-actions { - padding: (@line-height-base * @font-size-base - 1px) 0px @line-height-base * @font-size-base; - margin-top: @line-height-base * 1em; -+.row > div > .form-check:first-child, -+.row > div > .input-group > .form-check:first-child { -+ padding-top: add($input-padding-y, $input-border-width); - margin-bottom: 0; +- margin-bottom: 0; - background-color: @navbar-default-bg; - border-top: 1px solid @legend-border-color; - .border-bottom-radius(@border-radius-base); @@ -31,12 +30,17 @@ - margin-left: 0; - } - } --} -- ++.field-label + .field-control { ++ @extend .col-12, .col-sm-8, .col-md-9, .col-lg-10; + } + -.form-horizontal .control-label { - text-align: left; // override bootstrap --} -- ++:not(.field-label) + .field-control, ++.row > .field-control:first-child { ++ @extend .offset-sm-4, .offset-md-3, .offset-lg-2; + } + -legend .subtext { - font-size: .8em; - color: lighten(@cc-text, 40%); @@ -357,10 +361,14 @@ - -.controls-text { - padding-top: 7px; ++.row > div > .form-check:first-child, ++.row > div > .input-group > .form-check:first-child { ++ padding-top: add($input-padding-y, $input-border-width); ++ margin-bottom: 0; } .form-hide-actions .form-actions { -@@ -361,21 +12,34 @@ +@@ -361,21 +25,34 @@ .validationMessage { display: block; padding-top: 8px; diff --git a/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/crispy.md b/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/crispy.md index d0a43896efe3..0bc4db071091 100644 --- a/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/crispy.md +++ b/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/crispy.md @@ -6,9 +6,6 @@ section of the style guide. A few useful things to know about crispy forms in Bootstrap 5: -* Checkboxes, typically based on a `BooleanField`, need to be updated to use the `BootstrapCheckboxInput` as their -`widget`, as shown in this style guide example. * As described in this section of the style guide, best practice is to use one of HQ's standard helper classes for layout. Doing so means you can delete form_class, label_class, diff --git a/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/css-form-group.md b/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/css-form-group.md index 7b6ac9575df2..b16cdcaa9098 100644 --- a/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/css-form-group.md +++ b/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/css-form-group.md @@ -1,10 +1,10 @@ `form-group` has been dropped. Use grid utilities instead. -Since we are opting for vertical forms (where the label is directly above the field), take the following actions: +Take the following actions: * Remove the `div` wrapper from the `form-group`'s first child, which contains the field's label. -* Remove the column classes (`col-lg-2`, etc.) from the `form-group`'s first child, usually a `