### Install Dependencies and Start Development Server Source: https://github.com/thibaudcolas/curlylint/blob/main/website/README.md Navigate to the website directory, install its dependencies using npm, and then start the development server to preview changes. ```bash cd website # Install website dependencies. npm install # Start the development server. npm run start ``` -------------------------------- ### Install and Run Curlylint Source: https://github.com/thibaudcolas/curlylint/blob/main/README.md Install curlylint using pip and then run it on a directory containing your templates. ```bash # Assuming you’re using Python 3.6+, pip install curlylint # Now time to lint those templates! curlylint template-directory/ ``` -------------------------------- ### Component Usage Example (Commented Out) Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2-nunjucks/components/components.html Illustrates how to import and use a component macro. This example is commented out in the source and shows a typical import and invocation pattern. ```html {# Usage example: #} {# {% import "components.html" as components %} #} {# {{ components.icon(icon="logo", class="icon-logo") }} #} ``` -------------------------------- ### Verify Curlylint Installation Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/getting-started.md Check if curlylint has been installed correctly by running the --version and --help commands. This confirms the installation and shows available options. ```bash curlylint --version curlylint --help ``` -------------------------------- ### Example of inline code Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/django/wagtailstyleguide/base.html Demonstrates how to format inline code within text. ```html `This is an example of code` ``` -------------------------------- ### Jinja2 ask-search Macro Usage Example Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/organisms/ask-search.html Example of how to call the `render` macro, passing a `value` object which contains parameters for the search bar. Defaults are used if not explicitly provided. ```html {% if value %} {{ render( '', value.language | default( 'en' ), value.show_label | default( True ), value.autocomplete | default( True ), value.placeholder | default( '' ) ) }} {% endif %} ``` -------------------------------- ### Button link example Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/django/wagtailstyleguide/base.html Illustrates how to create a button link using a Django template tag. ```django [button link](#) button element ``` -------------------------------- ### Install Curlylint Development Environment Source: https://github.com/thibaudcolas/curlylint/blob/main/CONTRIBUTING.md Installs Curlylint and its development dependencies using pyenv and virtualenv. Ensure you have pyenv and virtualenv installed. ```bash git clone git@github.com:thibaudcolas/curlylint.git cd curlylint/ # Install required Python versions pyenv install --skip-existing 3.6.8 # Make required Python versions available globally. pyenv global system 3.6.8 # Install the Python environment. virtualenv .venv -p python3.6 source ./.venv/bin/activate make init ``` -------------------------------- ### Poetry Lockfile Dependency Example Source: https://github.com/thibaudcolas/curlylint/blob/main/website/blog/2021-04-25-quality-of-life-improvements.md An excerpt from a poetry.lock file showing package details and development dependencies. ```ini [[package]] name = "curlylint" version = "0.12.2" description = "{{ 🎀}} Experimental HTML templates linting for Jinja, Nunjucks, Django templates, Twig, Liquid" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] attrs = ">=17.2.0" click = ">=6.5" dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} parsy = "1.1.0" pathspec = ">=0.6,<1" toml = ">=0.9.4" [package.extras] dev = ["black (==19.10b0)", "flake8 (==3.8.4)", "mypy (==0.812)", "pytest (==6.2.2)", "coverage (==5.4)"] ``` -------------------------------- ### Example pyproject.toml Configuration Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/configuration.md This TOML file configures Curlylint's include and exclude patterns, and sets specific rule values like indentation and language. ```toml [tool.curlylint] include = ".*\\.(html|jinja)$" exclude = """ ( /( \.eggs # exclude a few common directories in the root of the project | \.git | \.venv )/ | webpack-stats.html # also separately exclude a file named webpack-stats.html in the root of the project ) """ [tool.curlylint.rules] indent = 4 html_has_lang = "en-GB" ``` -------------------------------- ### Optional Jinja Containers Support Source: https://github.com/thibaudcolas/curlylint/blob/main/CHANGELOG.md This example demonstrates support for optional Jinja containers, a pattern common in real-world projects. It shows how to handle conditional opening and closing of tags. ```html {% if something %}{% endif %}

something

{% if something %}
{% endif %} ``` -------------------------------- ### Show Curlylint Version Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/command-line-usage.md Use the `--version` flag to display the installed version of Curlylint and exit the program. ```bash curlylint --version ``` -------------------------------- ### No Site Setup Prompt Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/django/wagtailadmin/pages/listing/_list_explore.html Displays a message and a link to configure a site when the current location has no associated site and the user has permissions to add a site. It explains that pages created here will not be accessible until a site is configured. ```html {% url 'wagtailsites:index' as wagtailsites_index_url %} {% blocktrans %} There is no site set up for this location. Pages created here will not be accessible at any URL until a site is associated with this location. {% endblocktrans %} {% if wagtailsites_index_url %} [{% trans "Configure a site now." }]({{ wagtailsites_index_url }}) {% endif %} ``` -------------------------------- ### Paginate tag example Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/django/wagtailstyleguide/base.html Shows the usage of the paginate tag for pagination in Django templates. ```django {% paginate example_page %} ``` -------------------------------- ### Basic Template Syntax Examples Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/template-languages.md Demonstrates the common syntax patterns used across various curly brace template languages, including variable interpolation, special blocks, and filters. ```twig {{ pretty_cool_variable }} {% my_special_tag %} {{ pretty_cool_list|length }} ``` -------------------------------- ### Valid HTML with no tabindex or tabindex=-1 (CLI example) Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/tabindex_no_positive.mdx Demonstrates valid HTML structures that adhere to the `tabindex_no_positive` rule when using the command-line interface for linting. ```html
ARIA button
I can receive focus via JS
``` -------------------------------- ### Progress Bar Example Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/django/wagtailstyleguide/base.html This JavaScript code initializes a progress bar animation. It uses `setTimeout` to create a delayed and sequential update of the progress bar's width. ```javascript $(function(){ (function runprogress(){ var to = setTimeout(function(){ runprogress(); clearTimeout(to); setTimeout(function(){ $('#progress-example .bar').css('width', '20%'); }, 2000); }, 3000); $('#progress-example .bar').css('width', '80%'); })(); }) ``` -------------------------------- ### Importing and Rendering Form Blocks Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/form_block.html This example shows how to import the `form_block.html` macro and then iterate through a page's streamfield, rendering each block using the `render` macro. It passes the block, its field name, and the loop index. ```html {% import 'form_block.html' as form_block with context %} {% for block in page.streamfield %} {{ form_block.render(block, 'streamfield', loop.index0) }} {% endfor %} ``` -------------------------------- ### Enable Verbose Mode Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/command-line-usage.md Activate verbose mode with the `--verbose` flag to get detailed output for troubleshooting configuration and linting processes. ```bash curlylint --verbose template-directory/ ``` -------------------------------- ### Override file matching in pre-commit Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/reference/integrations.md Customize the file patterns Curlylint checks within your pre-commit configuration. This example shows how to include .sls files in addition to the default .html and .jinja files. ```yaml - id: curlylint files: \.(html|sls)$ ``` -------------------------------- ### Valid HTML with lang attribute (CLI config) Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/html_has_lang.mdx Examples of valid HTML structures when the `html_has_lang` rule is configured via the command line. These demonstrate correct usage for checking presence, specific language, and multiple allowed languages. ```html ``` -------------------------------- ### Valid ARIA Role Usage (Shell) Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/aria_role.mdx Examples of correct ARIA role usage when the rule is configured via shell commands. Demonstrates a valid role and a role matching a custom list. ```html
``` -------------------------------- ### Install Curlylint with Pip Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/getting-started.md Install the curlylint package using pip. This is the primary method for adding curlylint to your Python environment. ```bash pip install curlylint ``` -------------------------------- ### Jinja2 & Nunjucks Component Import and Rendering Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2-nunjucks/templates/code-sample.html Demonstrates importing a component from a separate file and rendering it with dynamic data in Jinja2 or Nunjucks. ```html {% raw %}{% import "components.html" as components %} {{ components.{% endraw %}{{ component.id }}({% for key, value in state.data %}{% if value != None %} {{ key }}={{ value|python_value }}{% if not loop.last %}, {% endif %}{% endif %}{% endfor %}{% raw %} ) }}{% endraw %} ``` -------------------------------- ### React Component Rendering with Props Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2-nunjucks/templates/code-sample.html Demonstrates importing and rendering a React component, dynamically passing props based on state data. ```javascript import {{ reactComponentName }} from 'components/{{ component.id}}'; <{{ reactComponentName }} {% for key, value in state.data %} {{ key }}={{ value|reactProp }} {% endfor %} /> ``` -------------------------------- ### User Iteration Loop Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/django/wagtailusers/users/list.html A basic Django template loop to iterate over a collection of users. The body of the loop is empty in this example. ```html {% for user in users %}{% endfor %} ``` -------------------------------- ### Iterating Over Schema Properties Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2-nunjucks/templates/partials/data-table.html This snippet demonstrates how to iterate over schema properties in a Jinja2/Nunjucks template to display key, type, example, and description for each property. ```html {% for key, val in component.schema %} {% endfor %} Property Type Example Description `{{ key }}` `{{ val.type }}` {% if val.component %}of [{{ val.component }}](/component/{{ val.component }}){% endif %} {% if val.example %} `{{ val.example|python_value }}` {% endif %} {{ val.description|markdown|safe }} ``` -------------------------------- ### Item Introduction Macro Definition Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/organisms/item-introduction.html Defines the `render` macro for the Item Introduction molecule. It accepts a `value` object containing various properties to customize the introduction's content and appearance. ```html {# ========================================================================== Item Introduction ========================================================================== Description: Create an Item Introduction molecule. See [GHE]/flapjack/Modules-V1/wiki/Item-Introduction value: An object with the following options for value. value.show_category: Whether to show the category or not. value.heading: Heading text. value.paragraph.source: Body introduction text. value.authors: Array of author names and associated URLs. value.date: A datetime for the post. value.has_social: Whether to show the share icons or not. ========================================================================== #} {% import 'molecules/social-media.html' as social_media with context %} {% import 'macros/category-slug.html' as category_slug %} {% macro render(value) %} {% set filter_page = page.get_filter_data() %} {% set filter_page_url = pageurl(filter_page) if filter_page else none %} {% set published_date = value.date %} {% set has_authors = page.authors.exists() %} {% if filter_page_url and page.categories.count() > 0 and value.show_category %} {{ category_slug.render(category=page.categories.first().name, href=page_url) }} {% endif %} {{ value.heading | safe }} ========================== {% if value.paragraph %} {{ value.paragraph | safe }} {% endif %} {% if published_date or has_authors %} {% endif %} {% if filter_page_url and has_authors %} {%- for author in page.get_authors() -%} {% if loop.first %}By {% elif loop.last %}and {% endif %} [{{ author.name }}]({{ filter_page_url }}?authors={{ author.slug }}) {%- if loop.length > 2 and loop.index < loop.length %}, {% endif %} {% endfor %} – {% endif %} {% if published_date %} {% import 'macros/time.html' as time %} {{ time.render(published_date, {'date':true}) }} {% endif %} {% if published_date or has_authors %} {% endif %} {% if value.has_social %} {{ social_media.render() }} {% endif %} {% endmacro %} ``` -------------------------------- ### Render Event Details Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/organisms/post-preview.html Conditionally renders event-specific details like venue city, state, name, and start time if the post is an 'EventPage'. ```jinja2 {% if 'EventPage' in post.specific_class.__name__ %} {% set event = post.specific %} {% if event.start_dt %} {% if event.venue_city and event.venue_state %} {{ event.venue_city }}, {{ event.venue_state }} {% endif %} {{ event.venue_name if event.venue_name else '' }} {{ 'Livecast' if event.live_stream_url else '' }} - {{ time.render(event.start_dt) }} {% endif %} {% endif %} ``` -------------------------------- ### Configure Rules with JSON Values Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/command-line-usage.md Specify individual rules and their configurations using the `--rule` flag. Rule values must be valid JSON. ```bash curlylint --rule 'indent: 2' --rule 'html_has_lang: true' template-directory/ ``` ```bash curlylint --rule 'html_has_lang: "en"' template-directory/ ``` ```bash curlylint --rule 'html_has_lang: ["en", "en-US"]' template-directory/ ``` -------------------------------- ### Print Configuration Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/command-line-usage.md Display the effective configuration for a specific file using the `--print-config` flag. ```bash curlylint --print-config some-file.html ``` -------------------------------- ### Valid viewport meta tags Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/meta_viewport.mdx Examples of viewport meta tags that comply with the meta_viewport rule. These tags do not use `user-scalable=no` and have appropriate `maximum-scale` values. ```html ``` ```html ``` -------------------------------- ### Root Level Site Configuration Prompt Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/django/wagtailadmin/pages/listing/_list_explore.html Displays a message and a link to configure a site when the root level is selected and the user has permissions to add a site. This is shown when no sites are configured. ```html {% url 'wagtailsites:index' as wagtailsites_index_url %} {% blocktrans %} The root level is where you can add new sites to your Wagtail installation. Pages created here will not be accessible at any URL until they are associated with a site. {% endblocktrans %} {% if wagtailsites_index_url %} [{% trans "Configure a site now." }]({{ wagtailsites_index_url }}) {% endif %} ``` -------------------------------- ### Invalid Image Tag Missing Alt Attribute Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/image_alt.mdx An example of an `` tag that violates the `image_alt` rule by omitting the `alt` attribute. This will be flagged by the linter. ```html ``` -------------------------------- ### Invalid viewport meta tags Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/meta_viewport.mdx Examples of viewport meta tags that violate the meta_viewport rule. These tags either use `user-scalable=no` or have a `maximum-scale` less than 2. ```html ``` ```html ``` -------------------------------- ### HTML Template Rendering with Filter Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2-nunjucks/templates/code-sample.html Illustrates rendering an HTML template with a 'pretty' filter in a Jinja2-like context, managing component state. ```html {% set component_save=component %} {% set component=state.data %} {% filter pretty -%}{% include template %}{% endfilter %} {% set component=component_save %} ``` -------------------------------- ### Rendering Success Alert with To-Do Items Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/youth_employment_success/route/notifications.html Renders a success alert that also indicates remaining to-do items. This is useful for guiding users through a multi-step process. ```html {{ alert.render({ 'background': true, 'fill': 'success', 'content': 'Looks like this option fits your budget, but you still have items left in your to-do list to complete.' }) }} ``` -------------------------------- ### Render Video Player Macro Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/organisms/video-player.html This snippet demonstrates how to import and render the video player macro. It takes a dictionary containing the video URL as input. ```html {# ========================================================================== Video Player ========================================================================== Description: Create a video player for the Wagtail Video Player module when given: value: Object defined from a StreamField block. value.video_url: A string containing the YouTube embed URL to use. ========================================================================== #} {% import 'macros/video-player.html' as player with context %} {{ player.render({ 'video': { 'url': value.video_url } }) }} ``` -------------------------------- ### Invalid HTML with positive tabindex (TOML config) Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/tabindex_no_positive.mdx An example of HTML that violates the `tabindex_no_positive` rule when configured via TOML, due to the presence of a positive `tabindex` value. ```html ``` -------------------------------- ### Text Introduction Molecule Template Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/molecules/text-introduction.html This Jinja2 template renders the Text Introduction molecule. It conditionally displays eyebrow text, a heading, an introduction, and body text. It also iterates through a list of links, formatting them as a bulleted list. ```jinja2 {# ========================================================================= Text Introduction ========================================================================= Description: Create a Text Introduction molecule. See [GHE]/flapjack/Modules-V1/wiki/Text-Introduction value: Object defined from a StreamField block. value.eyebrow: (Optional) Text to display above heading. value.heading: (Optional) String for heading text. value.intro: (Optional) String for body introduction text. value.intro.source: TODO: add type and description. value.body: (Optional) String for body text. value.links: A tuple of items to create a list of links, containing: value.links[i].text: (Optional) A string for the text of the link. value.links[i].url: A string for the URL of the link. value.has_rule: Whether or not to render a rule line (border-bottom) at the bottom of the molecule. ========================================================================== #} {% if value.eyebrow %} {{ value.eyebrow }} {% endif %} {% if value.heading %} {{ value.heading }} =================== {% endif %} {% if value.intro.source %} {{ value.intro | safe }} {% endif %} {% if value.body %} {{ value.body | safe }} {% endif %} {% for link in value.links %} {% if link.text %} {% if loop.first %} {% endif %}* [{{ link.text }}]({{ link.url }}) {% if loop.last %} {% endif %} {% endif %} {% endfor %} ``` -------------------------------- ### Render Individual Link Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/owning-a-home/_templates/brand-footer.html Renders a single link with an image, introductory text, and a clickable text label. Supports jump links with a download icon. The `link` object should contain `intro`, `img`, `text`, `label`, and `url` properties. ```html {# ========================================================================== render_link( link ) ========================================================================== Description: Render a link. link: An object, containing: - intro (req): text of link section - img: img for link section - text: link text - label: link accessible label - url: link url ========================================================================== #} {% macro render_link( link ) %} [![{{ link.label }}]({{ link.img }})]({{ link.url }}) {{ link.intro | safe }} {% if link.is_jump_link %} [{{ link.text | safe }} {{ svg_icon('download') }}]({{ link.url }}) {% else %} [{{ link.text | safe }}]({{ link.url }}) {% endif %} {% endmacro %} ``` -------------------------------- ### Invalid ARIA Role Usage (TOML) Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/aria_role.mdx Examples of incorrect ARIA role usage when the rule is configured in TOML. Shows an invalid role and a role not matching a custom list. ```html
``` -------------------------------- ### Valid Image Tags with Alt Attribute Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/image_alt.mdx Examples of correctly implemented `` tags. This includes images with meaningful `alt` text and those with an empty `alt` attribute for decorative purposes. ```html Foo eating a sandwich. ``` -------------------------------- ### Render Resource List with Optional Image and Heading Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/organisms/resource-list.html This snippet demonstrates how to conditionally render an image and heading for a resource list. It uses the 'info_unit' macro to format the output. ```html {# ========================================================================== resource_list.render(value) ========================================================================== Description: Outputs a resource list when given: value: Object defined from a StreamField block. valure.has_top_rule_line: Boolean for whether or not to add top border to resource-list. Used in 'render_block.html' to modify classes on wrapping 'div.block'. value.heading: The heading for the resource list intro. value.body: A description for the resource list intro. value.image: An image for the resource list intro. If set, the resource list intro will format as a 25/75 Image and Text module. value.snippet_type: The type of snippet being listed. Options defined in ref.py. value.show_thumbnails: A boolean for whether the template should render a thumbnail image for each snippet in the list. value.actions: A list of actions with two fields each: link_label and snippet_field value.actions[i].link_label: A string for the text of the action link. value.actions[i].snippet_field: The snippet field to which the action will link. Options defined in ref.py. value.tags: A list of tag names by which the snippet list will be filtered. Returned resources must match all tag names in this list. ========================================================================== #} {% from 'molecules/info-unit.html' import info_unit with context %} {% set img = image(value.image.upload, 'original') if value.image.upload else '/' %} {% set info_unit_image = { 'url': img.url, 'alt': image_alt_value(value.image), 'is_square': true, 'is_decorative': image_alt_value(value.image) == '' } if value.image.upload else null %} {% set modifier = 'inline' if value.image.upload else '' %} {% set heading = '### ' ~ value.heading ~ ' ' if value.heading else '' %} {{ info_unit( { 'modifier': modifier, 'image': info_unit_image, 'heading': heading, 'body': value.body | safe } ) }} ``` -------------------------------- ### Specify Configuration File Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/command-line-usage.md Point Curlylint to a specific configuration file using the `--config` flag. ```bash curlylint --config test_pyproject.toml template-directory/ ``` -------------------------------- ### Valid ARIA Role Usage (TOML) Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/aria_role.mdx Examples of correct ARIA role usage when the rule is configured in TOML. Shows a valid role and a role matching a custom list. ```html
``` -------------------------------- ### Specify Output Format Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/command-line-usage.md Control the output format with the `--format` flag. Supported formats include 'stylish', 'compact', and 'json'. ```bash curlylint --format json some-file.html ``` -------------------------------- ### Valid HTML without autofocus attribute (CLI example) Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/no_autofocus.mdx This HTML snippet is a 'success' case for the no_autofocus rule when checked via the command line. It correctly omits the autofocus attribute. ```html ``` -------------------------------- ### Conditional Rendering in Jinja2/Nunjucks Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2-nunjucks/templates/partials/usage.html Use if/else statements to conditionally render content based on a variable's value. This example shows how to display 'Yes' or 'No' based on a 'required' flag. ```jinja2 {% if row.required %}Yes{% endif %} {% if not row.required %}No, optional{% endif %} ``` -------------------------------- ### Welcome Branding Message Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/django/wagtailadmin/home.html Displays a customizable welcome message including the site name. ```html {% block branding_welcome %}{% blocktrans %}Welcome to the {{ site_name }} Wagtail CMS{% endblocktrans %}{% endblock %} ``` -------------------------------- ### Valid HTML with no tabindex or tabindex=-1 Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/tabindex_no_positive.mdx Examples of valid HTML where positive `tabindex` values are avoided. This includes elements without `tabindex` and those using `tabindex="-1"` for programmatic focus. ```html
ARIA button
I can receive focus via JS
``` -------------------------------- ### Include Site-Wide JavaScript Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/owning-a-home/loan-estimate/index.html This snippet includes common JavaScript files for the owning-a-home application, specifically for the form explainer functionality. It ensures necessary scripts are loaded when the page is interactive. ```html {% block javascript %} {{ super() }} if ( document.body.parentElement.className.indexOf( 'no-js' ) === -1 ) { !function(){ {# Include site-wide JavaScript. #} var s = [ '{{ static('apps/owning-a-home/js/common.js') }}', '{{ static('apps/owning-a-home/js/form-explainer/index.js') }}' ]; jsl(s); }() } {% endblock javascript %} ``` -------------------------------- ### Invalid ARIA Role Usage (Shell) Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/aria_role.mdx Examples of incorrect ARIA role usage when the rule is configured via shell commands. Highlights an invalid role and a role not matching a custom list. ```html
``` -------------------------------- ### Root Level Alternative Prompt Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/django/wagtailadmin/pages/listing/_list_explore.html Displays a message for the root level when the user does not have permissions to add a site, or when a site is already configured. It advises creating pages as children of the homepage. ```html {% blocktrans %} If you just want to add pages to an existing site, create them as children of the homepage instead. {% endblocktrans %} ``` -------------------------------- ### Render Video Player Macro Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/macros/video-player.html Builds the HTML markup for a video player. Accepts an options object for customization, including video ID, URL, image URL, and button position. Handles default values and URL parameter construction. ```jinja2 {% macro render(options={}) -%} {% set video_url = options.video.url | default('/') %} {% set image_url = static( 'img/cfpb_video_cover_card_1380x776.png' ) %} {% set video_id = options.video.id | default('') %} {# TODO: Move the advanced Jinja logic into Django. #} {% if video_url.find( '?' ) == -1 -%} {% set video_url = video_url ~ '?' %} {% endif %} {% if video_url.find( 'autoplay=1' ) != -1 -%} {% set video_url = video_url | replace('autoplay=1', '') %} {% endif %} {% set video_id = video_url.split('?')[0].split('/') | last if video_id == '' else video_id %} {% if video_url.find( 'enablejsapi=' ) == -1 -%} {% set video_url = _buildParam( video_url, 'enablejsapi=1' ) %} {% endif -%} {% if video_url.find( 'origin=' ) == -1 -%} {% set video_url = _buildParam( video_url, 'origin=' ~ request.scheme ~ '://' ~ request.get_host() ) %} {% endif %} {% set button_pos = options.button_pos or 'center' %} {% set is_flexible = ( options.video.width or options.video.height ) is not defined %} {{ caller() | safe if caller else '' }} Close {{ svg_icon('close-round') }} {% if not options.video.is_fcm %} {% import 'molecules/social-media.html' as social_media with context %} {{ social_media.render( { 'is_share_view': true, 'linkedin_title': 'Consumer Financial Protection Bureau', 'linkedin_text': 'Check out this video from the @CFPB', 'twitter_text': 'Check out this video from the @CFPB', 'email_title': page.title if page else 'Consumer Financial Protection Bureau' } ) }} {% endif %} {# This link is for the default, no-js, state of the video player. #} [{{ svg_icon('play') }}]({{ video_url }}) {# This button is for when the video player has loaded. #} {# TODO: Figure out how to pull video title from API and put it in aria-label below for screen readers. #} {{ svg_icon('play') }} ![]({{ image_url }}) {%- endmacro %} ``` -------------------------------- ### Lint from Standard Input Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/command-line-usage.md Pipe template content to Curlylint using `cat` and specify the input path as `-`. ```bash cat some-file.html | curlylint - ``` -------------------------------- ### Render Event Agenda Item Details Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/events/_macros.html Iterates through agenda items and renders their bound blocks for start time, end time, description, and location. Requires the 'time' macro for rendering time values. ```html+jinja {% for block in event.agenda_items %} {% set bound = block.value.bound_blocks %} {% endfor %} Time Agenda Location Speakers {% import 'macros/time.html' as time %} {% if bound.start_time.value is not none %} {{ time.render( bound.start_time.render(), {'date':false,'time':true,'timezone':false} ) }} {% endif %} {% if bound.end_time.value is not none %} – {{ time.render(bound.end_time.render(), {'time':true, 'timezone':true}) }} {% endif %} {{ bound.description.render() }} {% if bound.location.render() %} {{ bound.location.render() }} {% endif %} {% for speaker in bound.speakers.value %} {%- if speaker.bound_blocks.url.render() -%} [{{- speaker.bound_blocks.name.render() -}}]({{ speaker.bound_blocks.url.render() }}) {%- else -%} {{- speaker.bound_blocks.name.render() -}} {%- endif -%} {{ '; ' if loop.index < loop.length else '' }} {%- endfor -%} ``` -------------------------------- ### Jinja2 Post Preview Snapshot Rendering Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/organisms/post-preview-snapshot.html Renders a list of post previews. It fetches posts using `page.get_browsefilterable_posts` and then renders each post using the `post_preview.render` macro. ```html {# ========================================================================== Post preview snapshot ========================================================================== Description: Render a list of post previews for a page when given: value: Data object from an instance of the PostPreviewControls StreamField block. value.limit: Number of posts to show. value.post_date_description: Text to display next to date, e.g. "Published". ========================================================================== #} {% import 'organisms/post-preview.html' as post_preview with context %} {% set num_posts = value.limit | int %} {% set posts = page.get_browsefilterable_posts(num_posts) if page else [] %} {% for post in posts %} {{ post_preview.render( post, controls=none, url=pageurl(post.parent()), post_date_description=value.post_date_description ) }} {% endfor %} ``` -------------------------------- ### Render Post Preview Title and Link Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/organisms/post-preview.html Displays the post's preview title (or main title if preview title is absent) and links to the post. ```jinja2 [{{ post.preview_title | safe if post.preview_title else post.title }}]({{ post_url }}) ``` -------------------------------- ### Using string_length Macro with int Filter Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/macros/util/text.html Demonstrates how to use the string_length macro and apply the int filter to get the numerical length of the string 'foo bar' after whitespace removal. The expected output is 6. ```html string_length('foo bar')|int ``` -------------------------------- ### JSON test case for 'lang' attribute presence Source: https://github.com/thibaudcolas/curlylint/blob/main/website/blog/2020-07-18-brand-new-rules-documentation.md A JSON object representing a test case for the `html_has_lang` rule, demonstrating a successful check when the `lang` attribute is present. The `example: true` flag marks it for documentation. ```json { "label": "Check lang is present", "template": "", "example": true, "config": true, "output": [] } ``` -------------------------------- ### Configure Image Upload Options Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/django/wagtailimages/multiple/add.html Sets up global JavaScript options for image file uploads, including the upload URL, accepted file types, and maximum file size. This configuration is essential for the client-side handling of image uploads. ```javascript window.fileupload_opts = { simple_upload_url: "{% url 'wagtailimages:add' %}", accepted_file_types: /\.({{ allowed_extensions|join:"|" }})$/i, //must be regex max_file_size: {{ max_filesize|stringformat:"s"|default:"null" }}, errormessages: { max_file_size: "{{ error_max_file_size }}", accepted_file_types: "{{ error_accepted_file_types }}" } } ``` -------------------------------- ### Render List Markup Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/molecules/enforcement-action-metadata.html Creates markup for a list of links. It iterates through provided links, displaying them as clickable links if a URL is present, otherwise as plain text. ```Jinja2 {# ========================================================================== _list() ========================================================================== Description: Creates related metadata list markup when given: list: A list of dictionaries containing links. is_related_topics: Boolean indicating whether the list is a Related Topics list. Defaults to false. ========================================================================== #} {% macro _list(list, is_related_topics=false) %} {% for link in list.links %}* {% if link.url %} [{{ link.text }}]({{ link.url }}) {% else %} {{ link.text }} {% endif %} {% endfor %} {% endmacro %} ``` -------------------------------- ### Invalid HTML missing or with incorrect lang attribute (TOML config) Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/html_has_lang.mdx Examples of invalid HTML structures that violate the `html_has_lang` rule when configured via TOML. These show cases where the `lang` attribute is missing or has an incorrect value. ```html ``` -------------------------------- ### Valid HTML with lang attribute (TOML config) Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/html_has_lang.mdx Examples of valid HTML structures when the `html_has_lang` rule is configured using TOML. These demonstrate correct usage for checking presence, specific language, and multiple allowed languages. ```html ``` -------------------------------- ### Include Files with Custom Extension Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/command-line-usage.md Use the `--include` flag with a regular expression to specify which files or directories should be included in recursive searches, overriding the default. ```bash curlylint --parse-only --include .njk nunjucks-templates/ ``` -------------------------------- ### Render Post Description Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/organisms/post-preview.html Displays the post's preview description, allowing for safe HTML rendering. ```jinja2 {% if post.preview_description %} {{ post.preview_description | safe }} {% endif %} ``` -------------------------------- ### Invalid HTML missing or with incorrect lang attribute (CLI config) Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/html_has_lang.mdx Examples of invalid HTML structures that violate the `html_has_lang` rule when configured via the command line. These show cases where the `lang` attribute is missing or has an incorrect value. ```html ``` -------------------------------- ### Enable All Rules via Shell Command Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/all.mdx This shell command demonstrates how to enable all Curlylint rules directly from the command line using the --rule flag for each rule. This is useful for quick testing or CI environments. ```shell curlylint --rule 'aria_role: true' --rule 'django_forms_rendering: true' --rule 'html_has_lang: true' --rule 'image_alt: true' --rule 'indent: "tab"' --rule 'meta_viewport: true' --rule 'no_autofocus: true' --rule 'tabindex_no_positive: true' . ``` -------------------------------- ### Avoid Inaccessible Django Form Rendering Helpers Source: https://github.com/thibaudcolas/curlylint/blob/main/website/docs/rules/django_forms_rendering.mdx Shows examples of disallowed Django form rendering methods (`as_table`, `as_ul`, `as_p`) when the `django_forms_rendering` rule is set to `true`. These methods can negatively impact screen reader accessibility. ```html {{ form.as_table }} {{ form.as_ul }} {{ form.as_p }} ``` ```html {{ form.as_table }} {{ form.as_ul }} {{ form.as_p }} ``` -------------------------------- ### Render Brand Footer Content Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/owning-a-home/_templates/brand-footer.html Renders brand footer content, including up to three link sections and an email signup. Pass an array of link objects to the `links` parameter. If more than three links are provided, only the first three are displayed. If no links are passed, only the email signup is shown. ```html {# ========================================================================== render( links ) ========================================================================== Description: Renders all the brand footer content: 3 link sections and email section. links: An array of three link objects, each containing: - text (req): text of link section - img: img for link section - label: link label - url: link url Macro will display max of three link sections. If there are more than three link objects, only the first three will be shown. If no links are passed in, only the email signup will be shown. ========================================================================== #} {% macro render( links=\[\] ) %} ### {{ svg_icon('house') }} Check out other tools and resources from [Buying a House](/owning-a-home) {% for link in links %} {% if loop.index < 4 %} {{ render_link( link ) }} {% endif %} {% endfor %} {% set value = { 'heading': 'Buying a house?', 'default_heading': True, 'text': 'Sign up for our 2-week Get Homebuyer Ready boot camp. We’ll take you step-by-step through the entire homebuying process.', 'gd_code': 'USCFPB_127', 'disclaimer_url': '/owning-a-home/privacy-act-statement/' } %} {% include '_includes/organisms/email-signup.html' %} {% endmacro %} ``` -------------------------------- ### Curlylint Development Commands Source: https://github.com/thibaudcolas/curlylint/blob/main/CONTRIBUTING.md Common make commands for development tasks such as linting, formatting, testing, and building. ```bash make help # See what commands are available. ``` ```bash make init # Install dependencies and initialise for development. ``` ```bash make lint # Lint the project. ``` ```bash make format # Format project files. ``` ```bash make test # Test the project. ``` ```bash make benchmark # Runs a one-off performance (speed, memory) benchmark. ``` ```bash make clean-pyc # Remove Python file artifacts. ``` ```bash make sdist # Builds package version ``` ```bash make publish # Publishes a new version to pypi. ``` ```bash make publish-test # Publishes a new version to test pypi. ``` -------------------------------- ### Calling the Expandable Macro Source: https://github.com/thibaudcolas/curlylint/blob/main/tests/jinja2/_includes/organisms/expandable.html Demonstrates how to invoke the `expandable` macro with a `value` object. This is typically used to render the molecule on the page. ```Jinja2 {% if value %} {{ expandable(value) }} {% endif %} ```