Coverage for /Users/davegaeddert/Development/dropseed/plain/plain-htmx/plain/htmx/views.py: 38%

39 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-10-16 22:04 -0500

1import re 

2 

3from plain.utils.cache import patch_vary_headers 

4 

5from .jinja import render_template_fragment 

6 

7 

8class HTMXViewMixin: 

9 htmx_template_name = "" 

10 

11 def render_template(self): 

12 template = self.get_template() 

13 context = self.get_template_context() 

14 

15 if self.is_htmx_request and self.htmx_fragment_name: 

16 return render_template_fragment( 

17 template=template._jinja_template, 

18 fragment_name=self.htmx_fragment_name, 

19 context=context, 

20 ) 

21 

22 return template.render(context) 

23 

24 def get_response(self): 

25 response = super().get_response() 

26 # Tell browser caching to also consider the fragment header, 

27 # not just the url/cookie. 

28 patch_vary_headers( 

29 response, ["HX-Request", "Plain-HX-Fragment", "Plain-HX-Action"] 

30 ) 

31 return response 

32 

33 def get_request_handler(self): 

34 if self.is_htmx_request: 

35 # You can use an htmx_{method} method on views 

36 # (or htmx_{method}_{action} for specific actions) 

37 method = f"htmx_{self.request.method.lower()}" 

38 if self.htmx_action_name: 

39 method += f"_{self.htmx_action_name}" 

40 

41 if handler := getattr(self, method, None): 

42 return handler 

43 

44 return super().get_request_handler() 

45 

46 def get_template_names(self): 

47 # TODO is this part necessary anymore?? can I replace those with fragments now? 

48 if self.is_htmx_request: 

49 if self.htmx_template_name: 

50 return [self.htmx_template_name] 

51 

52 default_template_names = super().get_template_names() 

53 return ( 

54 [ 

55 re.sub(r"\.html$", "_htmx.html", template_name) 

56 for template_name in default_template_names 

57 ] 

58 + default_template_names 

59 ) # Fallback to the defaults so you don't need _htmx.html 

60 

61 return super().get_template_names() 

62 

63 @property 

64 def is_htmx_request(self): 

65 return self.request.headers.get("HX-Request") == "true" 

66 

67 @property 

68 def htmx_fragment_name(self): 

69 # A custom header that we pass with the {% htmxfragment %} tag 

70 return self.request.headers.get("Plain-HX-Fragment", "") 

71 

72 @property 

73 def htmx_action_name(self): 

74 return self.request.headers.get("Plain-HX-Action", "")