- {% set form = filter_data.form %}
- {% set posts = filter_data.page_set %}
+ form: Django form that carries the fields that are to be rendered.
+
+ fragment_id: A unique ID for the filter list control.
+
+ has_active_filters: Whether the filter has active filters or not.
+
+ ========================================================================== #}
+{% macro render(value, form, fragment_id, has_active_filters) %}
+ {% from 'organisms/expandable.html' import expandable with context %}
+
{% endmacro %}
diff --git a/cfgov/jinja2/v1/_includes/organisms/filterable-list.html b/cfgov/jinja2/v1/_includes/organisms/filterable-list.html
new file mode 100644
index 00000000000..87521638e72
--- /dev/null
+++ b/cfgov/jinja2/v1/_includes/organisms/filterable-list.html
@@ -0,0 +1,202 @@
+{# ==========================================================================
+
+ Filterable list
+
+ ==========================================================================
+
+ Description:
+
+ Create a filter list that includes controls and results when given:
+
+ value: Data object from an instance of the FilterableList StreamField block.
+
+ value.no_posts_message: Message to show in "no posts" state.
+
+ value.no_posts_explanation: More info to show in "no posts" state.
+
+ value.form_type: What type of form this is.
+
+ value.categories.page_type: What kind of pages are being filtered,
+ e.g. 'final-rule', 'blog'.
+ This is used to determine what categories
+ to allow filtering on, as well as how the
+ post preview is displayed.
+
+ value.output_5050: Whether to render results as info-units or not.
+
+ value.link_image_and_heading: Whether to link the image and heading
+ in info-units.
+
+ filter_data.form: Django form that carries the fields to be rendered.
+
+ filter_data.page_set: Result set of posts from the filtered content.
+
+ ========================================================================== #}
+
+{% import 'organisms/filterable-list-controls.html' as filterable_list_controls with context %}
+{% import 'molecules/notification.html' as notification with context %}
+
+{# SHOW A NOTIFICATION IF THERE'S NOTHING TO FILTER. #}
+
+{% set has_unfiltered_results = filter_data.form.filterable_pages.first() %}
+
+{% if not has_unfiltered_results and value.no_posts_message %}
+ {{ notification.render(
+ 'default',
+ true,
+ value.no_posts_message,
+ value.no_posts_explanation
+ ) }}
+{% elif has_unfiltered_results %}
+
+
+{% endif %}
diff --git a/cfgov/jinja2/v1/activity-log/index.html b/cfgov/jinja2/v1/activity-log/index.html
index 29710cf5030..82dc575d930 100644
--- a/cfgov/jinja2/v1/activity-log/index.html
+++ b/cfgov/jinja2/v1/activity-log/index.html
@@ -12,10 +12,8 @@
{% for block in page.content %}
{% if 'filter_controls' in block.block_type %}
-
- {% import 'organisms/filterable-list-controls.html' as flc with context %}
- {{ flc.render(block.value) }}
+
+ {% include_block block %}
{% else %}
{% import 'templates/render_block.html' as render_block with context %}
diff --git a/cfgov/jinja2/v1/browse-filterable/index.html b/cfgov/jinja2/v1/browse-filterable/index.html
index d4014077c00..7f37a9677cd 100644
--- a/cfgov/jinja2/v1/browse-filterable/index.html
+++ b/cfgov/jinja2/v1/browse-filterable/index.html
@@ -1,7 +1,6 @@
{% extends 'layout-side-nav.html' %}
{% import 'form_block.html' as form_block with context %}
-{% import 'organisms/filterable-list-controls.html' as flc with context %}
{% import 'templates/render_block.html' as render_block with context %}
{% import 'templates/streamfield-sidefoot.html' as streamfield_sidefoot with context %}
@@ -24,7 +23,9 @@
{% endfor %}
{% for block in page.content %}
{% if 'filter_controls' in block.block_type %}
- {{ flc.render_if_any(block.value) }}
+
+ {% include_block block %}
+
{% elif block.block_type == 'feedback' %}
{{- form_block.render(block, 'content', loop.index0) -}}
{% else %}
diff --git a/cfgov/jinja2/v1/newsroom/index.html b/cfgov/jinja2/v1/newsroom/index.html
index 21d8952c9ab..75af955da6a 100644
--- a/cfgov/jinja2/v1/newsroom/index.html
+++ b/cfgov/jinja2/v1/newsroom/index.html
@@ -24,11 +24,8 @@
{% endfor %}
{% for block in page.content %}
{% if 'filter_controls' in block.block_type %}
-
-
- {% import 'organisms/filterable-list-controls.html' as flc with context %}
- {{ flc.render(block.value) }}
+
+ {% include_block block %}
{% else %}
{% import 'templates/render_block.html' as render_block with context %}
diff --git a/cfgov/jinja2/v1/sublanding-page/index.html b/cfgov/jinja2/v1/sublanding-page/index.html
index e815e268d96..96bfebedbd9 100644
--- a/cfgov/jinja2/v1/sublanding-page/index.html
+++ b/cfgov/jinja2/v1/sublanding-page/index.html
@@ -42,8 +42,7 @@
{% elif 'filter_controls' in block.block_type %}
- {% import 'organisms/filterable-list-controls.html' as flc with context %}
- {{ flc.render(block.value) }}
+ {% include_block block %}
{% elif 'text_introduction' not in block.block_type %}
{% import 'templates/render_block.html' as render_block with context %}
diff --git a/cfgov/scripts/_atomic_helpers.py b/cfgov/scripts/_atomic_helpers.py
index 66767795a25..57385e0c10e 100644
--- a/cfgov/scripts/_atomic_helpers.py
+++ b/cfgov/scripts/_atomic_helpers.py
@@ -119,28 +119,6 @@
'content': "this is well content"
}
}
-filter_controls = {
- 'type': 'filter_controls',
- 'value': {
- 'is_expanded': False,
- 'post_date_description': 'Published',
- 'link_image_and_heading': False,
- 'topics': True,
- 'title': True,
- 'label': '',
- 'date_range': True,
- 'is_midtone': False,
- 'authors': True,
- 'form_type': 'filterable-list',
- 'is_bordered': False,
- 'output_5050': False,
- 'categories': {
- 'show_preview_categories': True,
- 'page_type': 'blog',
- 'filter_category': True
- }
- }
-}
full_width_text = {
'type': 'full_width_text',
'value': [
@@ -463,7 +441,6 @@
filter_controls = {
'type': u'filter_controls',
'value': {
- 'form_type': u'filterable-list',
'categories': {
'page_type': '',
},
diff --git a/cfgov/unprocessed/css/main.less b/cfgov/unprocessed/css/main.less
index 0b7087c5f92..6292207f61d 100755
--- a/cfgov/unprocessed/css/main.less
+++ b/cfgov/unprocessed/css/main.less
@@ -115,7 +115,6 @@
@import (less) "organisms/chart.less";
@import (less) "organisms/email-popup.less";
@import (less) "organisms/email-signup.less";
-@import (less) "organisms/filterable-list-controls.less";
@import (less) "organisms/footer.less";
@import (less) "organisms/form.less";
@import (less) "organisms/form-input-group.less";
diff --git a/cfgov/unprocessed/css/organisms/filterable-list-controls.less b/cfgov/unprocessed/css/organisms/filterable-list-controls.less
deleted file mode 100644
index 05c861500bb..00000000000
--- a/cfgov/unprocessed/css/organisms/filterable-list-controls.less
+++ /dev/null
@@ -1,53 +0,0 @@
-/* topdoc
- name: Filterable List Controls
- family: cf-organisms
- patterns:
- - name: Filterable List Controls
- markup: |
-
- codenotes:
- - |
- Pattern structure
- -----------------
- .o-filterable-list-controls
- .o-expandable
- [...]
- .m-notification
- [...]
- tags:
- - cf-organisms
-*/
-
-.o-filterable-list-controls {
- // TODO: Ideally this would be in a block surrounding the notification.
- // However, that leads to a gap when the notification is hidden.
- // See https://github.com/cfpb/cfgov-refresh/pull/1274#discussion_r48609669
- // Add gap between expandable and notification.
- .m-notification {
- margin-top: unit( @grid_gutter-width / @base-font-size-px, em );
- margin-bottom: unit( @grid_gutter-width / @base-font-size-px, em );
- }
- // TODO: Same as notification, explore a better solution in the future
- .o-expandable {
- margin-bottom: unit( @grid_gutter-width / @base-font-size-px, em );
- }
-
- &.o-filterable-list-controls {
- .o-multiselect_fieldset {
- position: relative;
- }
- }
-}
-
-/* topdoc
- name: EOF
- eof: true
-*/
diff --git a/cfgov/unprocessed/js/organisms/FilterableList.js b/cfgov/unprocessed/js/organisms/FilterableList.js
new file mode 100644
index 00000000000..3a0912c1f33
--- /dev/null
+++ b/cfgov/unprocessed/js/organisms/FilterableList.js
@@ -0,0 +1,83 @@
+// Required modules.
+import { checkDom, setInitFlag } from '../modules/util/atomic-helpers';
+import FilterableListControls from './FilterableListControls';
+import Notification from '../molecules/Notification';
+import { UNDEFINED } from '../modules/util/standard-type';
+
+const BASE_CLASS = 'o-filterable-list';
+
+/**
+ * FilterableList
+ * @class
+ *
+ * @classdesc Initializes a new FilterableList organism.
+ * A FilterableList contains a FilterableListControls organism for filtering a
+ * set of results, any notifications for the filtered results, and a block
+ * of filtered results.
+ *
+ * @param {HTMLNode} element
+ * The DOM element within which to search for the organism.
+ * @returns {FilterableList} An instance.
+ */
+function FilterableList( element ) {
+ const _dom = checkDom( element, BASE_CLASS );
+
+ let _filterableListControls;
+ let _notificationContainer;
+ let _notification;
+ let _resultsContainer;
+
+ /**
+ * @returns {FilterableListControls|undefined} An instance,
+ * or undefined if it was already initialized.
+ */
+ function init() {
+ if ( !setInitFlag( _dom ) ) {
+ return UNDEFINED;
+ }
+
+ _filterableListControls = new FilterableListControls(
+ _dom.querySelector( `.${ FilterableListControls.BASE_CLASS }` )
+ );
+ _filterableListControls.addEventListener(
+ 'fieldInvalid',
+ _fieldInvalidHandler
+ );
+
+ _notificationContainer = _dom.querySelector(
+ `.${ BASE_CLASS }_notification`
+ );
+ const notificationDom = _notificationContainer.querySelector(
+ `.${ Notification.BASE_CLASS }`
+ );
+ _notification = new Notification( notificationDom );
+
+ _notification.init();
+ _filterableListControls.init();
+
+ _resultsContainer = _dom.querySelector( `.${ BASE_CLASS }_results` );
+
+ return this;
+ }
+
+ /**
+ * Handle a field marked as invalid in the FilterableListControl instance.
+ * @param {Object} event - Faux event object from EventObserver.
+ */
+ function _fieldInvalidHandler( event ) {
+ _notification.update(
+ Notification.ERROR,
+ event.message
+ );
+
+ _notification.show();
+ _notificationContainer.classList.remove( 'u-hidden' );
+ _resultsContainer.classList.add( 'u-hidden' );
+ }
+
+ this.init = init;
+
+ return this;
+}
+
+export default FilterableList;
diff --git a/cfgov/unprocessed/js/organisms/FilterableListControls.js b/cfgov/unprocessed/js/organisms/FilterableListControls.js
index 3fb563e3320..ca20e4b11ad 100644
--- a/cfgov/unprocessed/js/organisms/FilterableListControls.js
+++ b/cfgov/unprocessed/js/organisms/FilterableListControls.js
@@ -7,30 +7,29 @@ import {
} from '../modules/util/atomic-helpers';
import Analytics from '../modules/Analytics';
import ERROR_MESSAGES from '../config/error-messages-config';
+import EventObserver from '../modules/util/EventObserver';
import Expandable from 'cf-expandables/src/Expandable';
import FormModel from '../modules/util/FormModel';
import Multiselect from '../molecules/Multiselect';
-import Notification from '../molecules/Notification';
import { UNDEFINED } from '../modules/util/standard-type';
-// TODO: Reduce lines in FilterableListControls or convert to class.
+const BASE_CLASS = 'o-filterable-list-controls';
+
/**
* FilterableListControls
* @class
*
- * @classdesc Initializes a new Filterable-List-Controls organism.
+ * @classdesc Initializes a new FilterableListControls organism.
*
* @param {HTMLNode} element
* The DOM element within which to search for the organism.
* @returns {FilterableListControls} An instance.
*/
function FilterableListControls( element ) {
- const BASE_CLASS = 'o-filterable-list-controls';
const _dom = checkDom( element, BASE_CLASS );
const _form = _dom.querySelector( 'form' );
let _expandable;
let _formModel;
- let _notification;
/**
* @returns {FilterableListControls|undefined} An instance,
@@ -71,11 +70,8 @@ function FilterableListControls( element ) {
} );
} );
- _notification = new Notification( _dom );
- _notification.init();
-
_formModel.init();
- _initAnalyticsEvents();
+ _initAnalyticsEvents.bind( this )();
return this;
}
@@ -84,7 +80,7 @@ function FilterableListControls( element ) {
* Initialize FilterableListControls events.
*/
function _initAnalyticsEvents() {
- let label = _expandable.getLabelText();
+ const label = _expandable.getLabelText();
const getDataLayerOptions = Analytics.getDataLayerOptions;
let dataLayerArray = [];
const cachedFields = {};
@@ -109,13 +105,20 @@ function FilterableListControls( element ) {
cachedFields[field.name] = getDataLayerOptions( action, field.value );
} );
+ const formSubmittedBinded = _formSubmitted.bind( this );
_form.addEventListener( 'submit', function sendEvent( event ) {
event.preventDefault();
Object.keys( cachedFields ).forEach( function( key ) {
dataLayerArray.push( cachedFields[key] );
} );
- dataLayerArray.push( getDataLayerOptions( 'Filter:submit', label,
- '', _formSubmitted ) );
+ dataLayerArray.push(
+ getDataLayerOptions(
+ 'Filter:submit',
+ label,
+ '',
+ formSubmittedBinded
+ )
+ );
Analytics.sendEvents( dataLayerArray );
dataLayerArray = [];
} );
@@ -130,10 +133,9 @@ function FilterableListControls( element ) {
);
if ( validatedFields.invalid.length > 0 ) {
- _showNotification(
- Notification.ERROR,
- _buildErrorMessage( validatedFields.invalid )
- );
+ this.dispatchEvent( 'fieldInvalid', {
+ message: _buildErrorMessage( validatedFields.invalid )
+ } );
} else {
_form.submit();
}
@@ -153,16 +155,6 @@ function FilterableListControls( element ) {
return msg || ERROR_MESSAGES.DEFAULT;
}
- /**
- * Show the notification.
- * @param {string} type - The type of notification to display.
- * @param {string} msg - The message to display in the notification.
- */
- function _showNotification( type, msg ) {
- _notification.update( type, msg );
- _notification.show();
- }
-
/**
* Validate the fields of our form.
* @param {Array} fields A list of form fields.
@@ -235,7 +227,14 @@ function FilterableListControls( element ) {
this.init = init;
+ const eventObserver = new EventObserver();
+ this.addEventListener = eventObserver.addEventListener;
+ this.removeEventListener = eventObserver.removeEventListener;
+ this.dispatchEvent = eventObserver.dispatchEvent;
+
return this;
}
+FilterableListControls.BASE_CLASS = BASE_CLASS;
+
export default FilterableListControls;
diff --git a/cfgov/unprocessed/js/routes/on-demand/filterable-list-controls.js b/cfgov/unprocessed/js/routes/on-demand/filterable-list.js
similarity index 64%
rename from cfgov/unprocessed/js/routes/on-demand/filterable-list-controls.js
rename to cfgov/unprocessed/js/routes/on-demand/filterable-list.js
index 2c25bec04bf..244ec2d63d3 100644
--- a/cfgov/unprocessed/js/routes/on-demand/filterable-list-controls.js
+++ b/cfgov/unprocessed/js/routes/on-demand/filterable-list.js
@@ -3,6 +3,6 @@
========================================================================== */
import { instantiateAll } from '../../modules/util/atomic-helpers';
-import FilterableListControls from '../../organisms/FilterableListControls';
+import FilterableList from '../../organisms/FilterableList';
-instantiateAll( '.o-filterable-list-controls', FilterableListControls );
+instantiateAll( '.o-filterable-list', FilterableList );
diff --git a/cfgov/v1/atomic_elements/organisms.py b/cfgov/v1/atomic_elements/organisms.py
index 6fb2b3e0fc2..b57869fd88e 100644
--- a/cfgov/v1/atomic_elements/organisms.py
+++ b/cfgov/v1/atomic_elements/organisms.py
@@ -865,14 +865,7 @@ class Meta:
classname = 'block__flush-top'
-# TODO: FilterControls/Filterable List should be updated to use same
-# atomic name used on the frontend of FilterableListControls,
-# or vice versa.
-class FilterControls(BaseExpandable):
- form_type = blocks.ChoiceBlock(choices=[
- ('filterable-list', 'Filterable List'),
- ('pdf-generator', 'PDF Generator'),
- ], default='filterable-list')
+class FilterableList(BaseExpandable):
title = blocks.BooleanBlock(default=True, required=False,
label='Filter Title')
no_posts_message = blocks.CharBlock(
@@ -914,11 +907,12 @@ class FilterControls(BaseExpandable):
)
class Meta:
- label = 'Filter Controls'
+ label = 'Filterable List'
icon = 'form'
+ template = '_includes/organisms/filterable-list.html'
class Media:
- js = ['filterable-list-controls.js']
+ js = ['filterable-list.js']
class VideoPlayer(blocks.StructBlock):
diff --git a/cfgov/v1/migrations/0134_simplify_filterable_list.py b/cfgov/v1/migrations/0134_simplify_filterable_list.py
new file mode 100644
index 00000000000..3a7182b2df6
--- /dev/null
+++ b/cfgov/v1/migrations/0134_simplify_filterable_list.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.18 on 2019-01-18 14:28
+from __future__ import unicode_literals
+
+from django.db import migrations
+import v1.atomic_elements.organisms
+import v1.blocks
+import v1.util.ref
+import wagtail.wagtailcore.blocks
+import wagtail.wagtailcore.fields
+import wagtail.wagtailimages.blocks
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('v1', '0133_add_no_posts_notification_to_filter_controls'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='browsefilterablepage',
+ name='content',
+ field=wagtail.wagtailcore.fields.StreamField([(b'full_width_text', wagtail.wagtailcore.blocks.StreamBlock([(b'content', wagtail.wagtailcore.blocks.RichTextBlock(icon=b'edit')), (b'content_with_anchor', wagtail.wagtailcore.blocks.StructBlock([(b'content_block', wagtail.wagtailcore.blocks.RichTextBlock()), (b'anchor_link', wagtail.wagtailcore.blocks.StructBlock([(b'link_id', wagtail.wagtailcore.blocks.CharBlock(help_text=b'\n ID will be auto-generated on save.\n However, you may enter some human-friendly text that\n will be incorporated to make it easier to read.\n ', label=b'ID for this content block', required=False))]))])), (b'heading', wagtail.wagtailcore.blocks.StructBlock([(b'text', v1.blocks.HeadingTextBlock(required=False)), (b'level', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[(b'h2', b'H2'), (b'h3', b'H3'), (b'h4', b'H4')])), (b'icon', v1.blocks.HeadingIconBlock(help_text=b'Input the name of an icon to appear to the left of the heading. E.g., approved, help-round, etc.
See full list of icons', required=False))], required=False)), (b'image', wagtail.wagtailcore.blocks.StructBlock([(b'image', wagtail.wagtailcore.blocks.StructBlock([(b'upload', wagtail.wagtailimages.blocks.ImageChooserBlock(required=False)), (b'alt', wagtail.wagtailcore.blocks.CharBlock(help_text=b"If the image is decorative (i.e., if a screenreader wouldn't have anything useful to say about it), leave the Alt field blank.", required=False))])), (b'image_width', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[(b'full', b'full'), (470, b'470px'), (270, b'270px'), (170, b'170px')])), (b'image_position', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[(b'right', b'right'), (b'left', b'left')], help_text=b'Does not apply if the image is full-width')), (b'text', wagtail.wagtailcore.blocks.RichTextBlock(label=b'Caption', required=False)), (b'is_bottom_rule', wagtail.wagtailcore.blocks.BooleanBlock(default=True, help_text=b'Check to add a horizontal rule line to bottom of inset.', label=b'Has bottom rule line', required=False))])), (b'table_block', v1.atomic_elements.organisms.AtomicTableBlock(table_options={b'renderer': b'html'})), (b'quote', wagtail.wagtailcore.blocks.StructBlock([(b'body', wagtail.wagtailcore.blocks.TextBlock()), (b'citation', wagtail.wagtailcore.blocks.TextBlock(required=False)), (b'is_large', wagtail.wagtailcore.blocks.BooleanBlock(required=False))])), (b'cta', wagtail.wagtailcore.blocks.StructBlock([(b'slug_text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'paragraph_text', wagtail.wagtailcore.blocks.RichTextBlock(required=False)), (b'button', wagtail.wagtailcore.blocks.StructBlock([(b'text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'url', wagtail.wagtailcore.blocks.CharBlock(default=b'/', required=False)), (b'size', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[(b'regular', b'Regular'), (b'large', b'Large Primary')]))]))])), (b'related_links', wagtail.wagtailcore.blocks.StructBlock([(b'heading', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'paragraph', wagtail.wagtailcore.blocks.RichTextBlock(required=False)), (b'links', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.StructBlock([(b'text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'url', wagtail.wagtailcore.blocks.CharBlock(default=b'/', required=False))])))])), (b'reusable_text', v1.blocks.ReusableTextChooserBlock(b'v1.ReusableText')), (b'email_signup', wagtail.wagtailcore.blocks.StructBlock([(b'heading', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'default_heading', wagtail.wagtailcore.blocks.BooleanBlock(default=True, help_text=b'If selected, heading will be styled as an H5 with green top rule. Deselect to style header as H3.', label=b'Default heading style', required=False)), (b'text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'gd_code', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'form_field', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.StructBlock([(b'btn_text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'required', wagtail.wagtailcore.blocks.BooleanBlock(required=False)), (b'info', wagtail.wagtailcore.blocks.RichTextBlock(label=b'Disclaimer', required=False)), (b'inline_info', wagtail.wagtailcore.blocks.BooleanBlock(help_text=b'Show disclaimer on same line as button. Only select this option if the disclaimer text is a few words (ie, "Privacy Act statement") rather than a full sentence.', label=b'Inline disclaimer', required=False)), (b'label', wagtail.wagtailcore.blocks.CharBlock(required=True)), (b'type', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[(b'text', b'Text'), (b'checkbox', b'Checkbox'), (b'email', b'Email'), (b'number', b'Number'), (b'url', b'URL'), (b'radio', b'Radio')], required=False)), (b'placeholder', wagtail.wagtailcore.blocks.CharBlock(required=False))]), icon=b'mail', required=False))]))])), (b'filter_controls', wagtail.wagtailcore.blocks.StructBlock([(b'label', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'is_bordered', wagtail.wagtailcore.blocks.BooleanBlock(required=False)), (b'is_midtone', wagtail.wagtailcore.blocks.BooleanBlock(required=False)), (b'is_expanded', wagtail.wagtailcore.blocks.BooleanBlock(required=False)), (b'title', wagtail.wagtailcore.blocks.BooleanBlock(default=True, label=b'Filter Title', required=False)), (b'no_posts_message', wagtail.wagtailcore.blocks.CharBlock(help_text=b'Message for the
notification that will be displayed instead of filter controls if there are no posts to filter.', required=False)), (b'no_posts_explanation', wagtail.wagtailcore.blocks.CharBlock(help_text=b'Additional explanation for the notification that will be displayed if there are no posts to filter.', required=False)), (b'post_date_description', wagtail.wagtailcore.blocks.CharBlock(default=b'Published')), (b'categories', wagtail.wagtailcore.blocks.StructBlock([(b'filter_category', wagtail.wagtailcore.blocks.BooleanBlock(default=True, required=False)), (b'show_preview_categories', wagtail.wagtailcore.blocks.BooleanBlock(default=True, required=False)), (b'page_type', wagtail.wagtailcore.blocks.ChoiceBlock(choices=v1.util.ref.filterable_list_page_types, required=False))])), (b'topics', wagtail.wagtailcore.blocks.BooleanBlock(default=True, label=b'Filter Topics', required=False)), (b'authors', wagtail.wagtailcore.blocks.BooleanBlock(default=True, label=b'Filter Authors', required=False)), (b'date_range', wagtail.wagtailcore.blocks.BooleanBlock(default=True, label=b'Filter Date Range', required=False)), (b'output_5050', wagtail.wagtailcore.blocks.BooleanBlock(default=False, label=b'Render preview items as 50-50s', required=False)), (b'link_image_and_heading', wagtail.wagtailcore.blocks.BooleanBlock(default=False, help_text=b'Add links to post preview images and headings in filterable list results', required=False))])), (b'feedback', wagtail.wagtailcore.blocks.StructBlock([(b'was_it_helpful_text', wagtail.wagtailcore.blocks.CharBlock(default=b'Was this page helpful to you?', help_text=b'Use this field only for feedback forms that use "Was this helpful?" radio buttons.', required=False)), (b'intro_text', wagtail.wagtailcore.blocks.CharBlock(help_text=b'Optional feedback intro', required=False)), (b'question_text', wagtail.wagtailcore.blocks.CharBlock(help_text=b'Optional expansion on intro', required=False)), (b'radio_intro', wagtail.wagtailcore.blocks.CharBlock(help_text=b'Leave blank unless you are building a feedback form with extra radio-button prompts, as in /owning-a-home/help-us-improve/.', required=False)), (b'radio_text', wagtail.wagtailcore.blocks.CharBlock(default=b'This information helps us understand your question better.', required=False)), (b'radio_question_1', wagtail.wagtailcore.blocks.CharBlock(default=b'How soon do you expect to buy a home?', required=False)), (b'radio_question_2', wagtail.wagtailcore.blocks.CharBlock(default=b'Do you currently own a home?', required=False)), (b'button_text', wagtail.wagtailcore.blocks.CharBlock(default=b'Submit')), (b'contact_advisory', wagtail.wagtailcore.blocks.RichTextBlock(help_text=b'Use only for feedback forms that ask for a contact email', required=False))]))]),
+ ),
+ migrations.AlterField(
+ model_name='sublandingfilterablepage',
+ name='content',
+ field=wagtail.wagtailcore.fields.StreamField([(b'text_introduction', wagtail.wagtailcore.blocks.StructBlock([(b'eyebrow', wagtail.wagtailcore.blocks.CharBlock(help_text=b'Optional: Adds an H5 eyebrow above H1 heading text. Only use in conjunction with heading.', label=b'Pre-heading', required=False)), (b'heading', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'intro', wagtail.wagtailcore.blocks.RichTextBlock(required=False)), (b'body', wagtail.wagtailcore.blocks.RichTextBlock(required=False)), (b'links', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.StructBlock([(b'text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'url', wagtail.wagtailcore.blocks.CharBlock(default=b'/', required=False))]), required=False)), (b'has_rule', wagtail.wagtailcore.blocks.BooleanBlock(help_text=b'Check this to add a horizontal rule line to bottom of text introduction.', label=b'Has bottom rule', required=False))])), (b'full_width_text', wagtail.wagtailcore.blocks.StreamBlock([(b'content', wagtail.wagtailcore.blocks.RichTextBlock(icon=b'edit')), (b'content_with_anchor', wagtail.wagtailcore.blocks.StructBlock([(b'content_block', wagtail.wagtailcore.blocks.RichTextBlock()), (b'anchor_link', wagtail.wagtailcore.blocks.StructBlock([(b'link_id', wagtail.wagtailcore.blocks.CharBlock(help_text=b'\n ID will be auto-generated on save.\n However, you may enter some human-friendly text that\n will be incorporated to make it easier to read.\n ', label=b'ID for this content block', required=False))]))])), (b'heading', wagtail.wagtailcore.blocks.StructBlock([(b'text', v1.blocks.HeadingTextBlock(required=False)), (b'level', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[(b'h2', b'H2'), (b'h3', b'H3'), (b'h4', b'H4')])), (b'icon', v1.blocks.HeadingIconBlock(help_text=b'Input the name of an icon to appear to the left of the heading. E.g., approved, help-round, etc.
See full list of icons', required=False))], required=False)), (b'image', wagtail.wagtailcore.blocks.StructBlock([(b'image', wagtail.wagtailcore.blocks.StructBlock([(b'upload', wagtail.wagtailimages.blocks.ImageChooserBlock(required=False)), (b'alt', wagtail.wagtailcore.blocks.CharBlock(help_text=b"If the image is decorative (i.e., if a screenreader wouldn't have anything useful to say about it), leave the Alt field blank.", required=False))])), (b'image_width', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[(b'full', b'full'), (470, b'470px'), (270, b'270px'), (170, b'170px')])), (b'image_position', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[(b'right', b'right'), (b'left', b'left')], help_text=b'Does not apply if the image is full-width')), (b'text', wagtail.wagtailcore.blocks.RichTextBlock(label=b'Caption', required=False)), (b'is_bottom_rule', wagtail.wagtailcore.blocks.BooleanBlock(default=True, help_text=b'Check to add a horizontal rule line to bottom of inset.', label=b'Has bottom rule line', required=False))])), (b'table_block', v1.atomic_elements.organisms.AtomicTableBlock(table_options={b'renderer': b'html'})), (b'quote', wagtail.wagtailcore.blocks.StructBlock([(b'body', wagtail.wagtailcore.blocks.TextBlock()), (b'citation', wagtail.wagtailcore.blocks.TextBlock(required=False)), (b'is_large', wagtail.wagtailcore.blocks.BooleanBlock(required=False))])), (b'cta', wagtail.wagtailcore.blocks.StructBlock([(b'slug_text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'paragraph_text', wagtail.wagtailcore.blocks.RichTextBlock(required=False)), (b'button', wagtail.wagtailcore.blocks.StructBlock([(b'text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'url', wagtail.wagtailcore.blocks.CharBlock(default=b'/', required=False)), (b'size', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[(b'regular', b'Regular'), (b'large', b'Large Primary')]))]))])), (b'related_links', wagtail.wagtailcore.blocks.StructBlock([(b'heading', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'paragraph', wagtail.wagtailcore.blocks.RichTextBlock(required=False)), (b'links', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.StructBlock([(b'text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'url', wagtail.wagtailcore.blocks.CharBlock(default=b'/', required=False))])))])), (b'reusable_text', v1.blocks.ReusableTextChooserBlock(b'v1.ReusableText')), (b'email_signup', wagtail.wagtailcore.blocks.StructBlock([(b'heading', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'default_heading', wagtail.wagtailcore.blocks.BooleanBlock(default=True, help_text=b'If selected, heading will be styled as an H5 with green top rule. Deselect to style header as H3.', label=b'Default heading style', required=False)), (b'text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'gd_code', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'form_field', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.StructBlock([(b'btn_text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'required', wagtail.wagtailcore.blocks.BooleanBlock(required=False)), (b'info', wagtail.wagtailcore.blocks.RichTextBlock(label=b'Disclaimer', required=False)), (b'inline_info', wagtail.wagtailcore.blocks.BooleanBlock(help_text=b'Show disclaimer on same line as button. Only select this option if the disclaimer text is a few words (ie, "Privacy Act statement") rather than a full sentence.', label=b'Inline disclaimer', required=False)), (b'label', wagtail.wagtailcore.blocks.CharBlock(required=True)), (b'type', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[(b'text', b'Text'), (b'checkbox', b'Checkbox'), (b'email', b'Email'), (b'number', b'Number'), (b'url', b'URL'), (b'radio', b'Radio')], required=False)), (b'placeholder', wagtail.wagtailcore.blocks.CharBlock(required=False))]), icon=b'mail', required=False))]))])), (b'filter_controls', wagtail.wagtailcore.blocks.StructBlock([(b'label', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'is_bordered', wagtail.wagtailcore.blocks.BooleanBlock(required=False)), (b'is_midtone', wagtail.wagtailcore.blocks.BooleanBlock(required=False)), (b'is_expanded', wagtail.wagtailcore.blocks.BooleanBlock(required=False)), (b'title', wagtail.wagtailcore.blocks.BooleanBlock(default=True, label=b'Filter Title', required=False)), (b'no_posts_message', wagtail.wagtailcore.blocks.CharBlock(help_text=b'Message for the
notification that will be displayed instead of filter controls if there are no posts to filter.', required=False)), (b'no_posts_explanation', wagtail.wagtailcore.blocks.CharBlock(help_text=b'Additional explanation for the notification that will be displayed if there are no posts to filter.', required=False)), (b'post_date_description', wagtail.wagtailcore.blocks.CharBlock(default=b'Published')), (b'categories', wagtail.wagtailcore.blocks.StructBlock([(b'filter_category', wagtail.wagtailcore.blocks.BooleanBlock(default=True, required=False)), (b'show_preview_categories', wagtail.wagtailcore.blocks.BooleanBlock(default=True, required=False)), (b'page_type', wagtail.wagtailcore.blocks.ChoiceBlock(choices=v1.util.ref.filterable_list_page_types, required=False))])), (b'topics', wagtail.wagtailcore.blocks.BooleanBlock(default=True, label=b'Filter Topics', required=False)), (b'authors', wagtail.wagtailcore.blocks.BooleanBlock(default=True, label=b'Filter Authors', required=False)), (b'date_range', wagtail.wagtailcore.blocks.BooleanBlock(default=True, label=b'Filter Date Range', required=False)), (b'output_5050', wagtail.wagtailcore.blocks.BooleanBlock(default=False, label=b'Render preview items as 50-50s', required=False)), (b'link_image_and_heading', wagtail.wagtailcore.blocks.BooleanBlock(default=False, help_text=b'Add links to post preview images and headings in filterable list results', required=False))])), (b'featured_content', wagtail.wagtailcore.blocks.StructBlock([(b'heading', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'body', wagtail.wagtailcore.blocks.RichTextBlock(required=False)), (b'category', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[(b'featured-event', b'Featured event'), (b'featured-blog', b'Featured blog'), (b'featured-video', b'Featured video'), (b'featured-tool', b'Featured tool'), (b'featured-news', b'Featured news'), (b'featured', b'Featured')], required=False)), (b'post', wagtail.wagtailcore.blocks.PageChooserBlock(required=False)), (b'show_post_link', wagtail.wagtailcore.blocks.BooleanBlock(label=b'Render post link?', required=False)), (b'post_link_text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'image', wagtail.wagtailcore.blocks.StructBlock([(b'upload', wagtail.wagtailimages.blocks.ImageChooserBlock(required=False)), (b'alt', wagtail.wagtailcore.blocks.CharBlock(help_text=b"If the image is decorative (i.e., if a screenreader wouldn't have anything useful to say about it), leave the Alt field blank.", required=False))])), (b'links', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.StructBlock([(b'text', wagtail.wagtailcore.blocks.CharBlock(required=False)), (b'url', wagtail.wagtailcore.blocks.CharBlock(default=b'/', required=False))]), label=b'Additional Links')), (b'video', wagtail.wagtailcore.blocks.StructBlock([(b'id', wagtail.wagtailcore.blocks.CharBlock(help_text=b'E.g., in "https://www.youtube.com/watch?v=en0Iq8II4fA", the ID is everything after the "?v=".', label=b'ID', required=False)), (b'url', wagtail.wagtailcore.blocks.CharBlock(help_text=b'You must use the embed URL, e.g., https://www.youtube.com/embed/JPTg8ZB3j5c?autoplay=1&enablejsapi=1', label=b'URL', required=False)), (b'height', wagtail.wagtailcore.blocks.CharBlock(default=b'320', required=False)), (b'width', wagtail.wagtailcore.blocks.CharBlock(default=b'568', required=False))]))])), (b'feedback', wagtail.wagtailcore.blocks.StructBlock([(b'was_it_helpful_text', wagtail.wagtailcore.blocks.CharBlock(default=b'Was this page helpful to you?', help_text=b'Use this field only for feedback forms that use "Was this helpful?" radio buttons.', required=False)), (b'intro_text', wagtail.wagtailcore.blocks.CharBlock(help_text=b'Optional feedback intro', required=False)), (b'question_text', wagtail.wagtailcore.blocks.CharBlock(help_text=b'Optional expansion on intro', required=False)), (b'radio_intro', wagtail.wagtailcore.blocks.CharBlock(help_text=b'Leave blank unless you are building a feedback form with extra radio-button prompts, as in /owning-a-home/help-us-improve/.', required=False)), (b'radio_text', wagtail.wagtailcore.blocks.CharBlock(default=b'This information helps us understand your question better.', required=False)), (b'radio_question_1', wagtail.wagtailcore.blocks.CharBlock(default=b'How soon do you expect to buy a home?', required=False)), (b'radio_question_2', wagtail.wagtailcore.blocks.CharBlock(default=b'Do you currently own a home?', required=False)), (b'button_text', wagtail.wagtailcore.blocks.CharBlock(default=b'Submit')), (b'contact_advisory', wagtail.wagtailcore.blocks.RichTextBlock(help_text=b'Use only for feedback forms that ask for a contact email', required=False))]))]),
+ ),
+ ]
diff --git a/cfgov/v1/models/browse_filterable_page.py b/cfgov/v1/models/browse_filterable_page.py
index 596a05d440f..08ac240cddf 100644
--- a/cfgov/v1/models/browse_filterable_page.py
+++ b/cfgov/v1/models/browse_filterable_page.py
@@ -21,7 +21,7 @@ class BrowseFilterableContent(StreamBlock):
Pages can have at most one filterable list.
"""
full_width_text = organisms.FullWidthText()
- filter_controls = organisms.FilterControls()
+ filter_controls = organisms.FilterableList()
feedback = v1_blocks.Feedback()
class Meta:
diff --git a/cfgov/v1/models/sublanding_filterable_page.py b/cfgov/v1/models/sublanding_filterable_page.py
index f3901633767..5bc0ea62e39 100644
--- a/cfgov/v1/models/sublanding_filterable_page.py
+++ b/cfgov/v1/models/sublanding_filterable_page.py
@@ -20,7 +20,7 @@ class SublandingFilterableContent(StreamBlock):
"""
text_introduction = molecules.TextIntroduction()
full_width_text = organisms.FullWidthText()
- filter_controls = organisms.FilterControls()
+ filter_controls = organisms.FilterableList()
featured_content = organisms.FeaturedContent()
feedback = v1_blocks.Feedback()
diff --git a/test/browser_tests/cucumber/features/suites/default/filterable-list-controls.feature b/test/browser_tests/cucumber/features/suites/default/filterable-list-controls.feature
index e20115e2755..430b7f1d788 100644
--- a/test/browser_tests/cucumber/features/suites/default/filterable-list-controls.feature
+++ b/test/browser_tests/cucumber/features/suites/default/filterable-list-controls.feature
@@ -33,17 +33,15 @@ Scenario: Select multiple categories
@undefined
Scenario: Date range to present
- When I enter “01/01/2017” in the From date entry field
+ When I enter “1/1/2017” in the From date entry field
And I apply filters
- Then I should see only results dated 01/01/2017 or later
-
-# It’s a usability issue that currently the filter won’t work if you don’t put leading zeroes in the date range field. There's a plan to update that behavior at some point, and the test should be updated then too.
+ Then I should see only results dated 1/1/2017 or later
@undefined
Scenario: Date range in past
- When I enter “01/01/2016” in the From date entry field
- And I enter “01/01/2017” in the To date entry field
- Then I should see only results between 01/01/2016 and 01/01/2017, inclusive
+ When I enter “1/1/2016” in the From date entry field
+ And I enter “1/1/2017” in the To date entry field
+ Then I should see only results between 1/1/2016 and 1/1/2017, inclusive
@undefined
Scenario: Select a topic
@@ -118,9 +116,9 @@ Scenario: Name search plus topic
@undefined
Scenario: Name search plus date range
When I type “loans” in the item name input box
- And I type “01/01/2017” in the From date entry field
+ And I type “1/1/2017” in the From date entry field
And I apply filters
- Then I should see only results dated 01/01/2017 or later with “loans” in the post title
+ Then I should see only results dated 1/1/2017 or later with “loans” in the post title
@undefined
Scenario: Name search plus author