Skip to content

Commit

Permalink
Use beautiful soup
Browse files Browse the repository at this point in the history
  • Loading branch information
deb17 committed May 22, 2021
1 parent 9373a82 commit 4e280e9
Show file tree
Hide file tree
Showing 12 changed files with 234 additions and 208 deletions.
98 changes: 51 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ flashing messages and rendering templates.
pip install Flask-Modals
```

### Usage
### Setup

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

Expand Down Expand Up @@ -55,55 +55,42 @@ pip install Flask-Modals
<form method="post">
...
```
<br>
5. Import the function `render_template_modal` in your `routes.py` file and use
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`. Use `redirect_to` function if redirecting to a page
without modal forms.

Example route handler:
### Basic usage

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

@app.route('/', methods=['GET', 'POST'])
def index():
Example route handler:

form = LoginForm()
if form.validate_on_submit():
if form.username.data != 'test' or form.password.data != 'pass':
flash('Invalid username or password', 'danger')
# You can use `render_template_modal` here
return redirect(url_for('index'))
```Python
from flask_modals import render_template_modal

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

flash('You have logged in!', 'success')
return redirect_to(url_for('home'))
form = LoginForm()
if form.validate_on_submit():
if form.username.data != 'test' or form.password.data != 'pass':
flash('Invalid username or password', 'danger')
# You can use `render_template_modal` here
return redirect(url_for('index'))

return render_template_modal('index.html', form=form, modal='modal-form')
```

In the target route, use `render_template_redirect` with the same arguments
as `render_template`.

```Python
from flask_modals import render_template_redirect
login_user(user, remember=form.remember_me.data)

@app.route('/home')
def home():
...
...
return render_template_redirect('home.html', ...)
```
See the example folder in the repo for more details.
<br>
flash('You have logged in!', 'success')
return redirect(url_for('home'))

return render_template_modal('index.html', form=form, modal='modal-form')
```

### Other usage

6. If you want to redirect to the same page outside the modal, use Flask's
`session` proxy as follows:
1. If you want to redirect to the same page outside the modal, use Flask's
`session` proxy and the `turbo` argument as follows:

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

```Python
@app.route('/', methods=['GET', 'POST'])
Expand All @@ -150,11 +137,28 @@ pattern:
return render_template_modal('index.html', form=form,
modal='modal-form', redirect=False)
```
If the above looks verbose, you can use the `response` decorator and
return a context dictionary, like so:

```Python
from flask_modals import response

@app.route('/', methods=['GET', 'POST'])
@response('index.html')
def index():
...
...
return {'form': form, 'modal': 'modal-form', 'redirect': False}
```
<br>
3. If you want to reload the page on form submit (for example, to refresh the
`head` tag), you can use `redirect_to` function in the modal route and
`render_template_redirect` function in the target route. They take in the same
arguments as Flask's `redirect` and `render_template` functions respectively.

### Note

1. The extension loads the Turbo library only in pages that have a modal
form.
1. See the example folder for more details.

2. It loads the NProgress js library to display a progress bar during form
submission.
2. The extension loads the NProgress js library to display a progress bar during
form submission.
76 changes: 65 additions & 11 deletions example/app/routes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from flask import redirect, url_for, flash, session
from flask import redirect, url_for, flash, session, render_template
from flask_login import login_user, logout_user
from flask_modals import (render_template_modal, render_template_redirect,
redirect_to)
redirect_to, response)

from app import app, user
from app.forms import LoginForm, NewsletterForm
Expand All @@ -17,8 +17,7 @@ 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`. If redirecting to a page without modal forms, use
`redirect_to` function.
`redirect`.
'''

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

flash('You have logged in!', 'success')
return redirect_to(url_for('home'))
return redirect(url_for('home'))

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

# @app.route('/', methods=['GET', 'POST'])
# def index():
# '''Use `redirect_to` function if you want a full page reload. Pair
# it with `render_template_redirect` function if the target route
# has no modal forms.
# '''

# form = LoginForm()
# if form.validate_on_submit():
# if form.username.data != 'test' or form.password.data != 'pass':
# flash('Invalid username or password', 'danger')
# # You can use `render_template_modal` here
# return redirect(url_for('index'))

# login_user(user, remember=form.remember_me.data)

# flash('You have logged in!', 'success')
# return redirect_to(url_for('home'))

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

# Use the following code if you want to redirect to the same page that
# contained the modal.
#
Expand Down Expand Up @@ -83,22 +104,55 @@ def index():
# return render_template_modal('index.html', title='Index page', form=form,
# modal='modal-form', redirect=False)

# Use the following code if you want to render a template instead of
# redirecting and make the code less verbose.
#
# @app.route('/', methods=['GET', 'POST'])
# @response('index.html')
# def index():

# form = LoginForm()
# if form.validate_on_submit():
# if form.username.data != 'test' or form.password.data != 'pass':
# flash('Invalid username or password', 'danger')
# return {'title': 'Index page', 'form': form,
# 'modal': 'modal-form', 'redirect': False}

# login_user(user, remember=form.remember_me.data)

# flash('You have logged in!', 'success')
# return {'title': 'Index page', 'form': form, 'turbo': False,
# 'modal': 'modal-form', 'redirect': False}

# return {'title': 'Index page', 'form': form, 'modal': 'modal-form',
# 'redirect': False}


@app.route('/home', methods=['GET', 'POST'])
def home():
'''This is a normal route without a modal form. As it is
redirected to from a modal form route, call
`render_template_redirect` here with the same arguments as
`render_template`.
'''
'''This is a normal route without a modal form.'''

form = NewsletterForm()

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

return render_template_redirect('home.html', title='Home page', form=form)
return render_template('home.html', title='Home page', form=form)

# @app.route('/home', methods=['GET', 'POST'])
# def home():
# '''To do a full page reload, call `render_template_redirect`
# here with the same arguments as `render_template`.
# '''

# form = NewsletterForm()

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

# return render_template_redirect('home.html', title='Home page', form=form)


@app.route('/logout')
Expand Down
3 changes: 2 additions & 1 deletion flask_modals/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
Modal,
render_template_modal,
render_template_redirect,
redirect_to
redirect_to,
response
)
63 changes: 46 additions & 17 deletions flask_modals/modal.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from functools import partial
from functools import wraps

from flask import (Blueprint, render_template, get_flashed_messages,
_app_ctx_stack, session, redirect)
_app_ctx_stack, session, redirect, request)
from jinja2 import Markup
from flask_modals.turbo import Turbo

from flask_modals.parser import add_turbo_stream_ids
from flask_modals.parser import parse_html

turbo = Turbo()

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


def render_template_modal(*args, **kwargs):
Expand All @@ -31,7 +31,6 @@ def render_template_modal(*args, **kwargs):
'''

ctx = _app_ctx_stack.top
ctx._include = True # used in extension templates
modal = kwargs.pop('modal', None)
replace = kwargs.pop('turbo', True)
update = False
Expand All @@ -47,7 +46,9 @@ def render_template_modal(*args, **kwargs):
else:
update = False if redirect else True

html, stream, target = add_turbo_stream_ids(
setup_for_reload()

html, stream, target = parse_html(
render_template(*args, **kwargs),
modal,
redirect,
Expand Down Expand Up @@ -79,13 +80,34 @@ def render_template_redirect(*args, **kwargs):
available on reload.
'''

setup_for_reload()
return render_template(*args, **kwargs)


def setup_for_reload():

if '_keep_flashes' in session:
del session['_keep_flashes']
ctx = _app_ctx_stack.top
ctx._include = False
ctx._reload = True
session['_flashes'] = get_flashed_messages(with_categories=True)

return render_template(*args, **kwargs)

def response(template=None):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
template_name = template
if template_name is None:
template_name = f"{request.endpoint.replace('.', '/')}.html"
ctx = f(*args, **kwargs)
if ctx is None:
ctx = {}
elif not isinstance(ctx, dict):
return ctx
return render_template_modal(template_name, **ctx)
return decorated_function
return decorator


class Modal:
Expand Down Expand Up @@ -128,20 +150,27 @@ def show_flashed_messages(*args, **kwargs):
return get_flashed_messages(*args, **kwargs)

def load(self, url=None):
'''Load the following markup only if page has a modal form:
'''Load the following markup:
1. turbo.html - Hotwire Turbo library
2. nprogress.html - NProgress js library for progress bar
3. jstemplate.html - Remove extra modal-backdrop divs and
control progress bar.
3. jstemplate.html - Remove extra modal-backdrop divs, control
progress bar, add body attribute
`data-turbo="false"`.
'''

ctx = _app_ctx_stack.top
inc = getattr(ctx, '_include', None)
render = partial(render_template, include=inc)

html = (Markup(render('modals/turbo.html', turbo=turbo.load, url=url) +
render('modals/nprogress.html') +
render('modals/jstemplate.html')))
reload = getattr(ctx, '_reload', None)

turbo_html = render_template(
'modals/turbo.html',
turbo=turbo.load,
url=url,
reload=reload
)
nprogress_html = render_template('modals/nprogress.html')
main_html = render_template('modals/jstemplate.html')

html = Markup(turbo_html + nprogress_html + main_html)

return html
Loading

0 comments on commit 4e280e9

Please sign in to comment.