Skip to content

Commit 4e280e9

Browse files
committed
Use beautiful soup
1 parent 9373a82 commit 4e280e9

File tree

12 files changed

+234
-208
lines changed

12 files changed

+234
-208
lines changed

README.md

Lines changed: 51 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ flashing messages and rendering templates.
1818
pip install Flask-Modals
1919
```
2020

21-
### Usage
21+
### Setup
2222

2323
1. Import the `Modal` class and instantiate it in your `app.py` file.
2424

@@ -55,55 +55,42 @@ pip install Flask-Modals
5555
<form method="post">
5656
...
5757
```
58-
<br>
59-
5. Import the function `render_template_modal` in your `routes.py` file and use
60-
it instead of `render_template` in the route handler for the page with the modal
61-
form. It takes the same arguments as `render_template`, apart from `modal` (the
62-
modal `id`), and optionally `turbo` (`False` if modal is not to be displayed) and
63-
`redirect` (`False` if you are not redirecting). See the next examples for use of
64-
`turbo` and `redirect`. Use `redirect_to` function if redirecting to a page
65-
without modal forms.
6658

67-
Example route handler:
59+
### Basic usage
6860

69-
```Python
70-
from flask_modals import render_template_modal, redirect_to
61+
You only need to import the function `render_template_modal` in your `routes.py`
62+
file. Use it instead of `render_template` in the route handler for the page with
63+
the modal form. It takes as arguments `modal` (the modal `id`), and optionally
64+
`turbo` and `redirect` (discussed next), in addition to the arguments passed to
65+
`render_template`.
7166

72-
@app.route('/', methods=['GET', 'POST'])
73-
def index():
67+
Example route handler:
7468

75-
form = LoginForm()
76-
if form.validate_on_submit():
77-
if form.username.data != 'test' or form.password.data != 'pass':
78-
flash('Invalid username or password', 'danger')
79-
# You can use `render_template_modal` here
80-
return redirect(url_for('index'))
69+
```Python
70+
from flask_modals import render_template_modal
8171

82-
login_user(user, remember=form.remember_me.data)
72+
@app.route('/', methods=['GET', 'POST'])
73+
def index():
8374

84-
flash('You have logged in!', 'success')
85-
return redirect_to(url_for('home'))
75+
form = LoginForm()
76+
if form.validate_on_submit():
77+
if form.username.data != 'test' or form.password.data != 'pass':
78+
flash('Invalid username or password', 'danger')
79+
# You can use `render_template_modal` here
80+
return redirect(url_for('index'))
8681

87-
return render_template_modal('index.html', form=form, modal='modal-form')
88-
```
89-
90-
In the target route, use `render_template_redirect` with the same arguments
91-
as `render_template`.
92-
93-
```Python
94-
from flask_modals import render_template_redirect
82+
login_user(user, remember=form.remember_me.data)
9583

96-
@app.route('/home')
97-
def home():
98-
...
99-
...
100-
return render_template_redirect('home.html', ...)
101-
```
102-
See the example folder in the repo for more details.
103-
<br>
84+
flash('You have logged in!', 'success')
85+
return redirect(url_for('home'))
86+
87+
return render_template_modal('index.html', form=form, modal='modal-form')
88+
```
89+
90+
### Other usage
10491

105-
6. If you want to redirect to the same page outside the modal, use Flask's
106-
`session` proxy as follows:
92+
1. If you want to redirect to the same page outside the modal, use Flask's
93+
`session` proxy and the `turbo` argument as follows:
10794

10895
```Python
10996
@app.route('/', methods=['GET', 'POST'])
@@ -127,8 +114,8 @@ without modal forms.
127114
modal='modal-form', turbo=flag)
128115
```
129116
<br>
130-
7. If you want to render a template and not redirect, then use the following
131-
pattern:
117+
2. If you want to render a template and not redirect, then use the `turbo` and
118+
`redirect` arguments as follows:
132119

133120
```Python
134121
@app.route('/', methods=['GET', 'POST'])
@@ -150,11 +137,28 @@ pattern:
150137
return render_template_modal('index.html', form=form,
151138
modal='modal-form', redirect=False)
152139
```
140+
If the above looks verbose, you can use the `response` decorator and
141+
return a context dictionary, like so:
142+
143+
```Python
144+
from flask_modals import response
145+
146+
@app.route('/', methods=['GET', 'POST'])
147+
@response('index.html')
148+
def index():
149+
...
150+
...
151+
return {'form': form, 'modal': 'modal-form', 'redirect': False}
152+
```
153+
<br>
154+
3. If you want to reload the page on form submit (for example, to refresh the
155+
`head` tag), you can use `redirect_to` function in the modal route and
156+
`render_template_redirect` function in the target route. They take in the same
157+
arguments as Flask's `redirect` and `render_template` functions respectively.
153158

154159
### Note
155160

156-
1. The extension loads the Turbo library only in pages that have a modal
157-
form.
161+
1. See the example folder for more details.
158162

159-
2. It loads the NProgress js library to display a progress bar during form
160-
submission.
163+
2. The extension loads the NProgress js library to display a progress bar during
164+
form submission.

example/app/routes.py

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from flask import redirect, url_for, flash, session
1+
from flask import redirect, url_for, flash, session, render_template
22
from flask_login import login_user, logout_user
33
from flask_modals import (render_template_modal, render_template_redirect,
4-
redirect_to)
4+
redirect_to, response)
55

66
from app import app, user
77
from app.forms import LoginForm, NewsletterForm
@@ -17,8 +17,7 @@ def index():
1717
by default) and `redirect` (which should be False if you are not
1818
redirecting). Only the `modal` argument is required and is used
1919
below. See the commented out code below for usage of `turbo` and
20-
`redirect`. If redirecting to a page without modal forms, use
21-
`redirect_to` function.
20+
`redirect`.
2221
'''
2322

2423
form = LoginForm()
@@ -31,11 +30,33 @@ def index():
3130
login_user(user, remember=form.remember_me.data)
3231

3332
flash('You have logged in!', 'success')
34-
return redirect_to(url_for('home'))
33+
return redirect(url_for('home'))
3534

3635
return render_template_modal('index.html', title='Index page', form=form,
3736
modal='modal-form')
3837

38+
# @app.route('/', methods=['GET', 'POST'])
39+
# def index():
40+
# '''Use `redirect_to` function if you want a full page reload. Pair
41+
# it with `render_template_redirect` function if the target route
42+
# has no modal forms.
43+
# '''
44+
45+
# form = LoginForm()
46+
# if form.validate_on_submit():
47+
# if form.username.data != 'test' or form.password.data != 'pass':
48+
# flash('Invalid username or password', 'danger')
49+
# # You can use `render_template_modal` here
50+
# return redirect(url_for('index'))
51+
52+
# login_user(user, remember=form.remember_me.data)
53+
54+
# flash('You have logged in!', 'success')
55+
# return redirect_to(url_for('home'))
56+
57+
# return render_template_modal('index.html', title='Index page', form=form,
58+
# modal='modal-form')
59+
3960
# Use the following code if you want to redirect to the same page that
4061
# contained the modal.
4162
#
@@ -83,22 +104,55 @@ def index():
83104
# return render_template_modal('index.html', title='Index page', form=form,
84105
# modal='modal-form', redirect=False)
85106

107+
# Use the following code if you want to render a template instead of
108+
# redirecting and make the code less verbose.
109+
#
110+
# @app.route('/', methods=['GET', 'POST'])
111+
# @response('index.html')
112+
# def index():
113+
114+
# form = LoginForm()
115+
# if form.validate_on_submit():
116+
# if form.username.data != 'test' or form.password.data != 'pass':
117+
# flash('Invalid username or password', 'danger')
118+
# return {'title': 'Index page', 'form': form,
119+
# 'modal': 'modal-form', 'redirect': False}
120+
121+
# login_user(user, remember=form.remember_me.data)
122+
123+
# flash('You have logged in!', 'success')
124+
# return {'title': 'Index page', 'form': form, 'turbo': False,
125+
# 'modal': 'modal-form', 'redirect': False}
126+
127+
# return {'title': 'Index page', 'form': form, 'modal': 'modal-form',
128+
# 'redirect': False}
129+
86130

87131
@app.route('/home', methods=['GET', 'POST'])
88132
def home():
89-
'''This is a normal route without a modal form. As it is
90-
redirected to from a modal form route, call
91-
`render_template_redirect` here with the same arguments as
92-
`render_template`.
93-
'''
133+
'''This is a normal route without a modal form.'''
94134

95135
form = NewsletterForm()
96136

97137
if form.validate_on_submit():
98138
flash('You have subscribed to the newsletter!', 'success')
99139
return redirect(url_for('home'))
100140

101-
return render_template_redirect('home.html', title='Home page', form=form)
141+
return render_template('home.html', title='Home page', form=form)
142+
143+
# @app.route('/home', methods=['GET', 'POST'])
144+
# def home():
145+
# '''To do a full page reload, call `render_template_redirect`
146+
# here with the same arguments as `render_template`.
147+
# '''
148+
149+
# form = NewsletterForm()
150+
151+
# if form.validate_on_submit():
152+
# flash('You have subscribed to the newsletter!', 'success')
153+
# return redirect(url_for('home'))
154+
155+
# return render_template_redirect('home.html', title='Home page', form=form)
102156

103157

104158
@app.route('/logout')

flask_modals/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
Modal,
33
render_template_modal,
44
render_template_redirect,
5-
redirect_to
5+
redirect_to,
6+
response
67
)

flask_modals/modal.py

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
from functools import partial
1+
from functools import wraps
22

33
from flask import (Blueprint, render_template, get_flashed_messages,
4-
_app_ctx_stack, session, redirect)
4+
_app_ctx_stack, session, redirect, request)
55
from jinja2 import Markup
66
from flask_modals.turbo import Turbo
77

8-
from flask_modals.parser import add_turbo_stream_ids
8+
from flask_modals.parser import parse_html
99

1010
turbo = Turbo()
1111

@@ -14,7 +14,7 @@ def modal_messages():
1414
'''This will be available in the app templates for use in the modal
1515
body.
1616
'''
17-
return Markup(render_template('modals/modal_messages.html'))
17+
return Markup(render_template('modals/modalMessages.html'))
1818

1919

2020
def render_template_modal(*args, **kwargs):
@@ -31,7 +31,6 @@ def render_template_modal(*args, **kwargs):
3131
'''
3232

3333
ctx = _app_ctx_stack.top
34-
ctx._include = True # used in extension templates
3534
modal = kwargs.pop('modal', None)
3635
replace = kwargs.pop('turbo', True)
3736
update = False
@@ -47,7 +46,9 @@ def render_template_modal(*args, **kwargs):
4746
else:
4847
update = False if redirect else True
4948

50-
html, stream, target = add_turbo_stream_ids(
49+
setup_for_reload()
50+
51+
html, stream, target = parse_html(
5152
render_template(*args, **kwargs),
5253
modal,
5354
redirect,
@@ -79,13 +80,34 @@ def render_template_redirect(*args, **kwargs):
7980
available on reload.
8081
'''
8182

83+
setup_for_reload()
84+
return render_template(*args, **kwargs)
85+
86+
87+
def setup_for_reload():
88+
8289
if '_keep_flashes' in session:
8390
del session['_keep_flashes']
8491
ctx = _app_ctx_stack.top
85-
ctx._include = False
92+
ctx._reload = True
8693
session['_flashes'] = get_flashed_messages(with_categories=True)
8794

88-
return render_template(*args, **kwargs)
95+
96+
def response(template=None):
97+
def decorator(f):
98+
@wraps(f)
99+
def decorated_function(*args, **kwargs):
100+
template_name = template
101+
if template_name is None:
102+
template_name = f"{request.endpoint.replace('.', '/')}.html"
103+
ctx = f(*args, **kwargs)
104+
if ctx is None:
105+
ctx = {}
106+
elif not isinstance(ctx, dict):
107+
return ctx
108+
return render_template_modal(template_name, **ctx)
109+
return decorated_function
110+
return decorator
89111

90112

91113
class Modal:
@@ -128,20 +150,27 @@ def show_flashed_messages(*args, **kwargs):
128150
return get_flashed_messages(*args, **kwargs)
129151

130152
def load(self, url=None):
131-
'''Load the following markup only if page has a modal form:
153+
'''Load the following markup:
132154
133155
1. turbo.html - Hotwire Turbo library
134156
2. nprogress.html - NProgress js library for progress bar
135-
3. jstemplate.html - Remove extra modal-backdrop divs and
136-
control progress bar.
157+
3. jstemplate.html - Remove extra modal-backdrop divs, control
158+
progress bar, add body attribute
159+
`data-turbo="false"`.
137160
'''
138161

139162
ctx = _app_ctx_stack.top
140-
inc = getattr(ctx, '_include', None)
141-
render = partial(render_template, include=inc)
142-
143-
html = (Markup(render('modals/turbo.html', turbo=turbo.load, url=url) +
144-
render('modals/nprogress.html') +
145-
render('modals/jstemplate.html')))
163+
reload = getattr(ctx, '_reload', None)
164+
165+
turbo_html = render_template(
166+
'modals/turbo.html',
167+
turbo=turbo.load,
168+
url=url,
169+
reload=reload
170+
)
171+
nprogress_html = render_template('modals/nprogress.html')
172+
main_html = render_template('modals/jstemplate.html')
173+
174+
html = Markup(turbo_html + nprogress_html + main_html)
146175

147176
return html

0 commit comments

Comments
 (0)