diff --git a/app/assets/stylesheets/components/pill.scss b/app/assets/stylesheets/components/pill.scss index 8258a2738..5139c9632 100644 --- a/app/assets/stylesheets/components/pill.scss +++ b/app/assets/stylesheets/components/pill.scss @@ -57,11 +57,11 @@ border: 2px solid $black; outline: 1px solid rgba($white, 0.1); position: relative; - z-index: 1000; + z-index: 10; color: $text-colour; &:focus { - z-index: 10; + z-index: 1000; outline: 3px solid $yellow; } diff --git a/app/assets/stylesheets/components/radio-select.scss b/app/assets/stylesheets/components/radio-select.scss deleted file mode 100644 index 59586121a..000000000 --- a/app/assets/stylesheets/components/radio-select.scss +++ /dev/null @@ -1,59 +0,0 @@ -.radio-select { - - min-height: 39px; - - &-column { - - display: inline-block; - vertical-align: top; - - .multiple-choice { - margin-right: 5px; - padding-right: 10px; - padding-left: 54px - 10px; - } - - } - - .js-reset-button, - .js-category-button { - - background: none; - text-decoration: underline; - color: $link-colour; - border: none; - display: inline-block; - vertical-align: top; - width: auto; - padding: 7px 20px 7px 10px; - margin-right: 5px; - cursor: pointer; - - &:hover { - color: $link-hover-colour; - } - - } - - .js-reset-button-block { - display: block; - width: 100%; - text-align: left; - padding: 20px 20px $gutter 57px; - } - - .js-enabled & { - - overflow: visible; - - .multiple-choice { - display: none; - } - - .js-multiple-choice { - display: block; - } - - } - -} diff --git a/app/assets/stylesheets/components/radios.scss b/app/assets/stylesheets/components/radios.scss new file mode 100644 index 000000000..bd0de4268 --- /dev/null +++ b/app/assets/stylesheets/components/radios.scss @@ -0,0 +1,118 @@ +.radio-select { + + min-height: 39px; + + &-column { + + display: inline-block; + vertical-align: top; + + .multiple-choice { + margin-right: 5px; + padding-right: 10px; + padding-left: 54px - 10px; + } + + } + + .js-reset-button, + .js-category-button { + + background: none; + text-decoration: underline; + color: $link-colour; + border: none; + display: inline-block; + vertical-align: top; + width: auto; + padding: 7px 20px 7px 10px; + margin-right: 5px; + cursor: pointer; + + &:hover { + color: $link-hover-colour; + } + + } + + .js-reset-button-block { + display: block; + width: 100%; + text-align: left; + padding: 20px 20px $gutter 57px; + } + + .js-enabled & { + + overflow: visible; + + .multiple-choice { + display: none; + } + + .js-multiple-choice { + display: block; + } + + } + +} + +.radios-nested { + + margin-bottom: 10px; + + .multiple-choice { + + $circle-diameter: 39px; + $border-thickness: 4px; + $border-indent: ($circle-diameter / 2) - ($border-thickness / 2); + $border-colour: $border-colour; + + float: none; + position: relative; + + &:before { + content: ""; + position: absolute; + bottom: 0; + left: $border-indent; + width: $border-thickness; + height: 100%; + background: $border-colour; + } + + label { + float: none; + } + + [type=radio]+label::before { + // To overlap the grey inset line + background: $white; + } + + ul { + // To equalise the spacing between the line and the top/bottom of + // the radio + margin-top: 5px; + margin-bottom: -5px; + padding-left: 12px; + } + + .block-label-hint { + &:after { + // Adds an little extra segment of line alongside the ‘current folder’ + // hint so that it extends all the way down to the next radio + content: ""; + position: absolute; + top: $circle-diameter + 5px; + left: $border-indent; + width: $border-thickness; + height: 25px; + background: $border-colour; + } + } + + } + +} diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index f4944ecac..f8fc5787c 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -46,7 +46,7 @@ $path: '/static/images/'; @import 'components/email-message'; @import 'components/api-key'; @import 'components/vendor/previous-next-navigation'; -@import 'components/radio-select'; +@import 'components/radios'; @import 'components/pill'; @import 'components/secondary-button'; @import 'components/show-more'; diff --git a/app/main/forms.py b/app/main/forms.py index 79a935ae5..5c66f3a6c 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -742,6 +742,33 @@ class RadioFieldWithNoneOption(FieldWithNoneOption, RadioField): pass +class NestedRadioField(RadioFieldWithNoneOption): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def children(self): + # start map with root option as a single child entry + child_map = {None: [option for option in self + if option.data == self.NONE_OPTION_VALUE]} + + # add entries for all other children + for option in self: + if option.data == self.NONE_OPTION_VALUE: + child_ids = [ + folder['id'] for folder in self.all_template_folders + if folder['parent_id'] is None] + key = self.NONE_OPTION_VALUE + else: + child_ids = [ + folder['id'] for folder in self.all_template_folders + if folder['parent_id'] == option.data] + key = option.data + + child_map[key] = [option for option in self if option.data in child_ids] + + return child_map + + class HiddenFieldWithNoneOption(FieldWithNoneOption, HiddenField): pass @@ -1199,7 +1226,7 @@ class TemplateAndFoldersSelectionForm(Form): """ ALL_TEMPLATES_FOLDER = { - 'name': 'All templates', + 'name': 'Templates', 'id': RadioFieldWithNoneOption.NONE_OPTION_VALUE, } @@ -1207,7 +1234,6 @@ class TemplateAndFoldersSelectionForm(Form): self, all_template_folders, template_list, - current_folder_id, allow_adding_letter_template, allow_adding_copy_of_template, *args, @@ -1221,13 +1247,10 @@ class TemplateAndFoldersSelectionForm(Form): self.op = None self.is_move_op = self.is_add_folder_op = self.is_add_template_op = False - if current_folder_id is None: - current_folder_id = RadioFieldWithNoneOption.NONE_OPTION_VALUE - + self.move_to.all_template_folders = all_template_folders self.move_to.choices = [ (item['id'], item['name']) for item in ([self.ALL_TEMPLATES_FOLDER] + all_template_folders) - if item['id'] != current_folder_id ] self.add_template_by_template_type.choices = list(filter(None, [ @@ -1262,10 +1285,16 @@ class TemplateAndFoldersSelectionForm(Form): templates_and_folders = MultiCheckboxField('Choose templates or folders', validators=[ required_for_ops('move-to-new-folder', 'move-to-existing-folder') ]) - move_to = RadioFieldWithNoneOption('Choose a folder', validators=[ - Optional(), - required_for_ops('move-to-new-folder', 'move-to-existing-folder') - ]) + # if no default set, it is set to None, which process_data transforms to '__NONE__' + # this means '__NONE__' (self.ALL_TEMPLATES option) is selected when no form data has been submitted + # set default to empty string so process_data method doesn't perform any transformation + move_to = NestedRadioField( + 'Choose a folder', + default='', + validators=[ + required_for_ops('move-to-existing-folder'), + Optional() + ]) add_new_folder_name = StringField('Folder name', validators=[required_for_ops('add-new-folder')]) move_to_new_folder_name = StringField('Folder name', validators=[required_for_ops('move-to-new-folder')]) diff --git a/app/main/views/templates.py b/app/main/views/templates.py index 191cac718..ba12244dc 100644 --- a/app/main/views/templates.py +++ b/app/main/views/templates.py @@ -116,13 +116,14 @@ def choose_template(service_id, template_type='all', template_folder_id=None): all_template_folders=current_service.all_template_folders, template_list=template_list, template_type=template_type, - current_folder_id=template_folder_id, allow_adding_letter_template=current_service.has_permission('letter'), allow_adding_copy_of_template=( current_service.all_templates or len(user_api_client.get_service_ids_for_user(current_user)) > 1 ), ) + option_hints = {template_folder_id: 'current folder'} + if request.method == 'POST' and templates_and_folders_form.validate_on_submit(): if not can_manage_folders(): abort(403) @@ -149,6 +150,8 @@ def choose_template(service_id, template_type='all', template_folder_id=None): template_type=template_type, search_form=SearchTemplatesForm(), templates_and_folders_form=templates_and_folders_form, + move_to_children=templates_and_folders_form.move_to.children(), + option_hints=option_hints ) diff --git a/app/templates/components/radios.html b/app/templates/components/radios.html index 8b3ee19dc..351158acb 100644 --- a/app/templates/components/radios.html +++ b/app/templates/components/radios.html @@ -14,6 +14,44 @@ {% endcall %} {% endmacro %} + +{% macro radio_list( + options, + child_map, + disable=[], + option_hints={} +) %} +