diff --git a/README.md b/README.md index ee5ca41..23f35fc 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,8 @@ JavaScript. Normal form submission in modals has its own problems. This Flask extension eases the process of using forms in (Bootstrap 4) modals. No JavaScript coding is required on your part. The ajax calls are handled behind -the scenes with html-over-the-wire Turbo library and the Turbo-Flask -extension. You can code in pure Python - flashing messages and rendering -templates. +the scenes with html-over-the-wire Turbo library. You can code in pure Python - +flashing messages and rendering templates. ### Installation @@ -62,12 +61,13 @@ it instead of `render_template` in the route handler for the page with the modal form. It takes the same arguments as `render_template`, apart from `modal` (the modal `id`), and optionally `turbo` (`False` if modal is not to be displayed) and `redirect` (`False` if you are not redirecting). See the next examples for use of -`turbo` and `redirect`. +`turbo` and `redirect`. Use `redirect_to` function if redirecting to a page +without modal forms. Example route handler: ```Python - from flask_modals import render_template_modal + from flask_modals import render_template_modal, redirect_to @app.route('/', methods=['GET', 'POST']) def index(): @@ -82,7 +82,7 @@ modal `id`), and optionally `turbo` (`False` if modal is not to be displayed) an login_user(user, remember=form.remember_me.data) flash('You have logged in!', 'success') - return redirect(url_for('home')) + return redirect_to(url_for('home')) return render_template_modal('index.html', form=form, modal='modal-form') ``` diff --git a/example/app/routes.py b/example/app/routes.py index 327895a..55edab3 100644 --- a/example/app/routes.py +++ b/example/app/routes.py @@ -1,6 +1,7 @@ from flask import redirect, url_for, flash, session from flask_login import login_user, logout_user -from flask_modals import render_template_modal, render_template_redirect +from flask_modals import (render_template_modal, render_template_redirect, + redirect_to) from app import app, user from app.forms import LoginForm, NewsletterForm @@ -16,7 +17,8 @@ def index(): by default) and `redirect` (which should be False if you are not redirecting). Only the `modal` argument is required and is used below. See the commented out code below for usage of `turbo` and - `redirect`. + `redirect`. If redirecting to a page without modal forms, use + `redirect_to` function. ''' form = LoginForm() @@ -29,7 +31,7 @@ def index(): login_user(user, remember=form.remember_me.data) flash('You have logged in!', 'success') - return redirect(url_for('home')) + return redirect_to(url_for('home')) return render_template_modal('index.html', title='Index page', form=form, modal='modal-form') diff --git a/flask_modals/__init__.py b/flask_modals/__init__.py index 2286d80..b0dc503 100644 --- a/flask_modals/__init__.py +++ b/flask_modals/__init__.py @@ -1,5 +1,6 @@ from flask_modals.modal import ( Modal, render_template_modal, - render_template_redirect + render_template_redirect, + redirect_to ) diff --git a/flask_modals/modal.py b/flask_modals/modal.py index 92e4bf4..ef8d0d5 100644 --- a/flask_modals/modal.py +++ b/flask_modals/modal.py @@ -1,9 +1,9 @@ from functools import partial from flask import (Blueprint, render_template, get_flashed_messages, - _app_ctx_stack, session, request) + _app_ctx_stack, session, redirect) from jinja2 import Markup -from turbo_flask import Turbo +from flask_modals.turbo import Turbo from flask_modals.parser import add_turbo_stream_ids @@ -32,9 +32,6 @@ def render_template_modal(*args, **kwargs): ctx = _app_ctx_stack.top ctx._include = True # used in extension templates - - session['_cond_flashes'] = True # used in after_app_request function - modal = kwargs.pop('modal', None) replace = kwargs.pop('turbo', True) update = False @@ -67,6 +64,15 @@ def render_template_modal(*args, **kwargs): return html +def redirect_to(*args, **kwargs): + '''Use this function instead of Flask's `redirect` if you are + redirecting to a page without modal forms. + ''' + + session['_keep_flashes'] = True + return redirect(*args, **kwargs) + + def render_template_redirect(*args, **kwargs): '''Reload the page to unload the Turbo library. See template `turbo.html`. Flashes need to be saved so that they are again @@ -94,7 +100,6 @@ def init_app(self, app): globals for app. ''' - turbo.init_app(app) self.register_blueprint(app) app.add_template_global(modal_messages) app.jinja_env.globals['modals'] = self.load @@ -107,21 +112,6 @@ def register_blueprint(self, app): static_folder='static', static_url_path='/modals/static') - @bp.after_app_request - def handle_session_vars(response): - - session.pop('_keep_flashes', None) - - if session.get('_cond_flashes'): - session['_cond_flashes'] = False - elif session.get('_cond_flashes') is False: - if request.method == 'POST': - if response.status_code in range(300, 309): - session['_keep_flashes'] = True - del session['_cond_flashes'] - - return response - app.register_blueprint(bp) @staticmethod @@ -137,7 +127,7 @@ def show_flashed_messages(*args, **kwargs): return get_flashed_messages(*args, **kwargs) - def load(self): + def load(self, url=None): '''Load the following markup only if page has a modal form: 1. turbo.html - Hotwire Turbo library @@ -150,7 +140,7 @@ def load(self): inc = getattr(ctx, '_include', None) render = partial(render_template, include=inc) - html = (Markup(render('modals/turbo.html') + + html = (Markup(render('modals/turbo.html', turbo=turbo.load, url=url) + render('modals/nprogress.html') + render('modals/jstemplate.html'))) diff --git a/flask_modals/templates/modals/turbo.html b/flask_modals/templates/modals/turbo.html index f1cdbf5..a4a491a 100644 --- a/flask_modals/templates/modals/turbo.html +++ b/flask_modals/templates/modals/turbo.html @@ -1,5 +1,5 @@ {% if include %} -{{ turbo() }} +{{ turbo(url=url) }} {% elif include is false %} {% endif %} diff --git a/flask_modals/turbo.py b/flask_modals/turbo.py new file mode 100644 index 0000000..746f4f6 --- /dev/null +++ b/flask_modals/turbo.py @@ -0,0 +1,45 @@ +'''Copyright notice - The code below is adapted from the Turbo-Flask +extension by Miguel Grinberg (https://github.com/miguelgrinberg/turbo-flask), +which is under MIT license. +''' + +from flask import request, current_app +from jinja2 import Markup + + +_CDN = 'https://cdn.skypack.dev' +_PKG = '@hotwired/turbo' +_VER = 'v7.0.0-beta.5-LhgiwOUjafYu3bb8VbTv' + + +class Turbo: + + def load(self, version=_VER, url=None): + + if url is None: + url = f'{_CDN}/pin/{_PKG}@{version}/min/{_PKG}.js' + return Markup(f'') + + def can_stream(self): + '''Returns `True` if the client accepts turbo streams.''' + + stream_mimetype = 'text/vnd.turbo-stream.html' + best = request.accept_mimetypes.best_match([ + stream_mimetype, 'text/html']) + return best == stream_mimetype + + def _make_stream(self, action, content, target): + return (f'' + f'') + + def replace(self, content, target): + return self._make_stream('replace', content, target) + + def update(self, content, target): + return self._make_stream('update', content, target) + + def stream(self, response_stream): + '''Create a turbo stream response.''' + + return current_app.response_class( + response_stream, mimetype='text/vnd.turbo-stream.html') diff --git a/setup.py b/setup.py index ac818ef..70c942e 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name='Flask-Modals', - version='0.2.5', + version='0.2.6', author='Debashish Palit', author_email='dpalit17@outlook.com', description='Use forms in Bootstrap 4 modals with Flask.', @@ -16,10 +16,7 @@ package_data={'flask_modals': ['templates/modals/*.html', 'static/js/main.js']}, include_package_data=True, - install_requires=[ - 'flask>=1.1.0', - 'turbo-flask', - ], + install_requires=['Flask'], zip_safe=False, classifiers=[ 'Programming Language :: Python :: 3',