diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fb47eed..036d47e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Release notes +## v0.133 + +#### Fix + +- HOTFIX: Fix the use of URLs in `Component.Media.js` and `Component.Media.css` + ## v0.132 #### Feat diff --git a/pyproject.toml b/pyproject.toml index 88d0dfb7..6bda9c44 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "django_components" -version = "0.132" +version = "0.133" requires-python = ">=3.8, <4.0" description = "A way to create simple reusable template components in Django." keywords = ["django", "components", "css", "js", "html"] diff --git a/src/django_components/component_media.py b/src/django_components/component_media.py index 2070dc95..eeefc15d 100644 --- a/src/django_components/component_media.py +++ b/src/django_components/component_media.py @@ -865,9 +865,14 @@ def resolve_media_file( filepath_abs_or_glob = os.path.join(media_root_dir, filepath) + # If the path is a URL, don't resolve it + # (e.g. https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.0.2/chart.min.js) + # This is defined based on Django's `Media.absolute_path()` method. + is_url_path = filepath.startswith(("http://", "https", "/")) + # The path may be a glob. So before we check if the file exists, # we need to resolve the glob. - if allow_glob and is_glob(filepath_abs_or_glob): + if allow_glob and is_glob(filepath_abs_or_glob) and not is_url_path: matched_abs_filepaths = glob.glob(filepath_abs_or_glob) else: matched_abs_filepaths = [filepath_abs_or_glob] diff --git a/tests/test_component_media.py b/tests/test_component_media.py index eb71e51d..165d2c06 100644 --- a/tests/test_component_media.py +++ b/tests/test_component_media.py @@ -414,6 +414,44 @@ class TestComponentMedia: assertInHTML('', rendered) assertInHTML('', rendered) + def test_glob_pattern_does_not_break_urls(self): + class MyComponent(Component): + template = """ + {% load component_tags %} + {% component_js_dependencies %} + {% component_css_dependencies %} + """ + + class Media: + css = [ + "https://cdnjs.cloudflare.com/example/style.min.css", + "http://cdnjs.cloudflare.com/example/style.min.css", + # :// is not a valid URL - will be resolved as static path + "://cdnjs.cloudflare.com/example/style.min.css", + "/path/to/style.css", + ] + js = [ + "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.0.2/chart.min.js", + "http://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.0.2/chart.min.js", + # :// is not a valid URL - will be resolved as static path + "://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.0.2/chart.min.js", + "/path/to/script.js", + ] + + rendered = MyComponent.render() + + assertInHTML('', rendered) + assertInHTML('', rendered) + # `://` is escaped because the path was resolved with Django's `static()` + assertInHTML('', rendered) + assertInHTML('', rendered) + + assertInHTML('', rendered) + assertInHTML('', rendered) + # `://` is escaped because the path was resolved with Django's `static()` + assertInHTML('', rendered) + assertInHTML('', rendered) + @djc_test class TestMediaPathAsObject: