Source code for flask_htmx.responses

from __future__ import annotations

import json
import typing

from flask import Response
from flask import make_response as flask_make_response

from flask_htmx.constants import HTMX_STOP_POLLING, HX_FALSE, HX_TRUE, RESWAPS


class HTMXResponseClientRedirect(Response):
    """Flask response to instruct HTMX to perform a client-side redirect."""

    def __init__(self, redirect_to: str, status: int = 200):
        super().__init__(None, status=status, headers={"HX-Redirect": redirect_to})


class HTMXResponseStopPolling(Response):
    """Flask response to instruct HTMX to stop polling."""

    def __init__(
        self,
        response=None,
        headers=None,
        mimetype="text/html",
        direct_passthrough=False,
    ):
        super().__init__(
            response=response,
            status=HTMX_STOP_POLLING,
            headers=headers,
            mimetype=mimetype,
            direct_passthrough=direct_passthrough,
        )


def _stringify(val):
    return val if isinstance(val, str) else json.dumps(val)


[docs]def make_response( *args: typing.Any, location: str | dict | None = None, push_url: str | False | None = None, redirect: str | None = None, refresh: bool = False, replace_url: str | False | None = None, reswap: str | None = None, retarget: str | None = None, trigger: str | dict | None = None, trigger_after_settle: str | dict | None = None, trigger_after_swap: str | dict | None = None, ) -> Response: """ This function can be used as a replacement from :code:`flask.make_response` to easily add htmx response headers to the request. See https://htmx.org/reference/#response_headers for more details about the headers. :param args: Arguments you would normally use with :code:`flask.make_response`. :param location: Allows you to do a client-side redirect that does not do a full page reload. Accepts a string or a dict (:code:`HX-Location`). :param push_url: Pushes a new url into the history stack. Accepts a string—the URL to be pushed into the location bar—or :py:obj:`False`—prevents the browser’s history from being updated—(:code:`HX-Push-URL`). :param redirect: Can be used to do a client-side redirect to a new location (:code:`HX-Redirect`). :param refresh: If set to :py:obj:`True` the client side will do a full refresh of the page (:code:`HX-Refresh`). :param replace_url: Replaces the current URL in the location bar. Accepts a string—the URL to replace the current URL in the location bar—or :py:obj:False:—prevents the browser’s current URL from being updated—(:code:`HX-Replace-URL`). :param reswap: Allows you to specify how the response will be swapped. Possible values: "innerHTML", "outerHTML", "beforebegin" "afterbegin", "beforeend", "afterend", "delete", "none". Notice :py:obj:`None` means to not send the header, which is different from "none" (:code:`HX-Reswap`). :param retarget: A CSS selector that updates the target of the content update to a different element on the page (:code:`HX-Retarget`). :param trigger: Allows you to trigger client side events. Accepts a string or a dict (:code:`HX-Trigger`). :param trigger_after_settle: Allows you to trigger client side events. Accepts a string or a dict (:code:`HT-Trigger-After-Settle`). :param trigger_after_swap: Allows you to trigger client side events. Accepts a string or a dict (:code:`HT-Trigger-After-Swap`). :return: A Flask Response with htmx headers. """ if reswap and reswap not in RESWAPS: raise ValueError( f"Invalid reswap value. Must be one of {RESWAPS} (or None to ignore)." ) resp = flask_make_response(*args) if location: resp.headers["HX-Location"] = _stringify(location) if push_url: resp.headers["HX-Push-Url"] = push_url elif push_url is False: resp.headers["HX-Push-Url"] = HX_FALSE if redirect: resp.headers["HX-Redirect"] = redirect if refresh: resp.headers["HX-Refresh"] = HX_TRUE if replace_url: resp.headers["HX-Replace-Url"] = replace_url elif replace_url is False: resp.headers["HX-Replace-Url"] = HX_FALSE if reswap: resp.headers["HX-Reswap"] = reswap if retarget: resp.headers["HX-Retarget"] = retarget if trigger: resp.headers["HX-Trigger"] = _stringify(trigger) if trigger_after_settle: resp.headers["HX-Trigger-After-Settle"] = _stringify(trigger_after_settle) if trigger_after_swap: resp.headers["HX-Trigger-After-Swap"] = _stringify(trigger_after_swap) return resp