diff --git a/html_to_django/formatters/__init__.py b/html_to_django/formatters/__init__.py index e9f926e..edd704e 100644 --- a/html_to_django/formatters/__init__.py +++ b/html_to_django/formatters/__init__.py @@ -6,10 +6,10 @@ Each formatter module contains a `format` function that performs a specific modi The `formatters` list in this package contains all the formatter modules for easy access and usage. """ from . import (for_formatter, if_formatter, var_formatter, block_formatter, static_formatter, attr_formatter, - for_wrap_formatter, unwrap_formatter, include_formatter, remove_default_formatter, command_formatter, - style_formatter, style_raw_formatter) + for_wrap_formatter, unwrap_formatter, remove_formatter, include_formatter, assets_formatter, + remove_default_formatter, command_formatter, style_formatter, style_raw_formatter) formatters = [for_formatter, if_formatter, var_formatter, block_formatter, static_formatter, attr_formatter, - for_wrap_formatter, unwrap_formatter, include_formatter, remove_default_formatter, command_formatter, - style_formatter, style_raw_formatter] + for_wrap_formatter, unwrap_formatter, remove_formatter, include_formatter, assets_formatter, + remove_default_formatter, command_formatter, style_formatter, style_raw_formatter] diff --git a/html_to_django/formatters/assets_formatter.py b/html_to_django/formatters/assets_formatter.py new file mode 100644 index 0000000..aa63ae4 --- /dev/null +++ b/html_to_django/formatters/assets_formatter.py @@ -0,0 +1,32 @@ +""" +This module contains a function `format` that modifies a BeautifulSoup object in place. The function searches for +the "html" element with the attribute "dj-assets". The value of "dj-assets" is expected to be a string with two parts +separated by a semicolon (;), the first part being the asset identifier and the second part being the asset prefix. + +For each element in the BeautifulSoup object with a "href" or "src" attribute that starts with the asset identifier, +it adds the asset prefix to the attribute value and wraps it in a Django static command. + + +After processing all elements, it removes the "dj-assets" attribute from the "html" element. + +Example: + If the "html" element is ..., + and there is an element , + after processing, the "img" element becomes . +""" +from bs4 import BeautifulSoup, Tag + + +def format(soup: BeautifulSoup) -> None: + if html := soup.find("html"): + if isinstance(html, Tag): + if html.has_attr("dj-assets"): + if isinstance(html["dj-assets"], str): + asset_identifier, asset_prefix = html["dj-assets"].split(";") + for element in soup.find_all(attrs={"href": True}): + if element["href"].startswith(asset_identifier): + element["href"] = f"{{% static '{asset_prefix}/{element['href']}' %}}" + for element in soup.find_all(attrs={"src": True}): + if element["src"].startswith(asset_identifier): + element["src"] = f"{{% static '{asset_prefix}/{element['src']}' %}}" + del html["dj-assets"] diff --git a/html_to_django/formatters/remove_formatter.py b/html_to_django/formatters/remove_formatter.py new file mode 100644 index 0000000..a75fd1b --- /dev/null +++ b/html_to_django/formatters/remove_formatter.py @@ -0,0 +1,15 @@ +""" +This module contains a function `format` that modifies a BeautifulSoup object in place. The function searches for +all elements with the attribute "dj-remove". For each found element, it calls the `decompose` method, which removes +the element from the parse tree. This effectively removes all elements marked with "dj-remove" from the HTML document. + +Example: + If an element is
, + after processing, it will be removed from the BeautifulSoup object. +""" +from bs4 import BeautifulSoup + + +def format(soup: BeautifulSoup) -> None: + for element in soup.find_all(attrs={"dj-remove": True}): + element.decompose() diff --git a/tests/formatters/tests_assets_formatter.py b/tests/formatters/tests_assets_formatter.py new file mode 100644 index 0000000..6e99170 --- /dev/null +++ b/tests/formatters/tests_assets_formatter.py @@ -0,0 +1,31 @@ +from unittest import TestCase +from bs4 import BeautifulSoup +from html_to_django.formatters import assets_formatter + + +class AssetsTests(TestCase): + def test_basic(self) -> None: + soup = BeautifulSoup('', 'html.parser') + assets_formatter.format(soup) + expected_result = '' + self.assertEqual(expected_result, str(soup)) + + def test_empty(self) -> None: + soup = BeautifulSoup('', 'html.parser') + assets_formatter.format(soup) + expected_result = '' + self.assertEqual(expected_result, str(soup)) + + def test_no_assets(self) -> None: + soup = BeautifulSoup('

Test

', 'html.parser') + assets_formatter.format(soup) + expected_result = '

Test

' + self.assertEqual(expected_result, str(soup)) + + def test_with_multiple_assets(self) -> None: + soup = BeautifulSoup('', 'html.parser') + assets_formatter.format(soup) + expected_result = ('') + self.assertEqual(expected_result, str(soup)) diff --git a/tests/formatters/tests_remove_formatter.py b/tests/formatters/tests_remove_formatter.py new file mode 100644 index 0000000..8cd4138 --- /dev/null +++ b/tests/formatters/tests_remove_formatter.py @@ -0,0 +1,23 @@ +from unittest import TestCase +from bs4 import BeautifulSoup +from html_to_django.formatters import remove_formatter + + +class RemoveTests(TestCase): + def test_basic(self) -> None: + soup = BeautifulSoup('
Test
', "html.parser") + remove_formatter.format(soup) + expected_result = "" + self.assertEqual(expected_result, str(soup)) + + def test_empty(self) -> None: + soup = BeautifulSoup('
', "html.parser") + remove_formatter.format(soup) + expected_result = "" + self.assertEqual(expected_result, str(soup)) + + def test_with_remove_inside(self) -> None: + soup = BeautifulSoup('
Inner Test
', "html.parser") + remove_formatter.format(soup) + expected_result = "" + self.assertEqual(expected_result, str(soup)) diff --git a/tests/formatters/tests_unwrap_formatter.py b/tests/formatters/tests_unwrap_formatter.py index b9adaf8..2084b0d 100644 --- a/tests/formatters/tests_unwrap_formatter.py +++ b/tests/formatters/tests_unwrap_formatter.py @@ -5,19 +5,19 @@ from html_to_django.formatters import unwrap_formatter class UnwrapTests(TestCase): def test_basic(self) -> None: - soup = BeautifulSoup('
Test
', "html.parser") + soup = BeautifulSoup('
Test
', "html.parser") unwrap_formatter.format(soup) expected_result = "
Test
" self.assertEqual(expected_result, str(soup)) def test_empty(self) -> None: - soup = BeautifulSoup('
', "html.parser") + soup = BeautifulSoup('
', "html.parser") unwrap_formatter.format(soup) expected_result = "" self.assertEqual(expected_result, str(soup)) def test_with_unwrap_inside(self) -> None: - soup = BeautifulSoup('
Inner Test
', "html.parser") + soup = BeautifulSoup('
Inner Test
', "html.parser") unwrap_formatter.format(soup) expected_result = "Inner Test" self.assertEqual(expected_result, str(soup))