Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
flask-admin
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Python-Dev
flask-admin
Commits
7037aac0
Commit
7037aac0
authored
Jul 01, 2015
by
Petrus Janse van Rensburg
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #919 from pawl/add_edit_modal2
Add modal for edit_view
parents
706dfff3
955271ef
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
202 additions
and
33 deletions
+202
-33
base.py
flask_admin/model/base.py
+4
-0
admin.css
flask_admin/static/admin/css/bootstrap3/admin.css
+10
-1
lib.html
flask_admin/templates/bootstrap2/admin/lib.html
+25
-7
edit.html
flask_admin/templates/bootstrap2/admin/model/edit.html
+35
-8
list.html
flask_admin/templates/bootstrap2/admin/model/list.html
+11
-3
lib.html
flask_admin/templates/bootstrap3/admin/lib.html
+21
-4
edit.html
flask_admin/templates/bootstrap3/admin/model/edit.html
+38
-7
list.html
flask_admin/templates/bootstrap3/admin/model/list.html
+11
-3
test_model.py
flask_admin/tests/test_model.py
+47
-0
No files found.
flask_admin/model/base.py
View file @
7037aac0
...
@@ -99,6 +99,10 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -99,6 +99,10 @@ class BaseModelView(BaseView, ActionsMixin):
create_template
=
'admin/model/create.html'
create_template
=
'admin/model/create.html'
"""Default create template"""
"""Default create template"""
# Modals
edit_modal
=
False
"""Setting this to true will display the edit_view as a modal dialog."""
# Customizations
# Customizations
column_list
=
ObsoleteAttr
(
'column_list'
,
'list_columns'
,
None
)
column_list
=
ObsoleteAttr
(
'column_list'
,
'list_columns'
,
None
)
"""
"""
...
...
flask_admin/static/admin/css/bootstrap3/admin.css
View file @
7037aac0
...
@@ -69,8 +69,9 @@ table.filters tr td {
...
@@ -69,8 +69,9 @@ table.filters tr td {
}
}
/* Forms */
/* Forms */
/* adds spacing between navbar and edit/create form (non-modal only) */
/* required because form-horizontal removes top padding */
/* required because form-horizontal removes top padding */
.admin-form
{
div
.container
>
.admin-form
{
margin-top
:
35px
;
margin-top
:
35px
;
}
}
...
@@ -79,4 +80,12 @@ table.filters tr td {
...
@@ -79,4 +80,12 @@ table.filters tr td {
/* prevents awkward gap after help-block - This is default for bootstrap2 */
/* prevents awkward gap after help-block - This is default for bootstrap2 */
.admin-form
.help-block
{
.admin-form
.help-block
{
margin-bottom
:
0px
;
margin-bottom
:
0px
;
}
/* Modals */
/* hack to prevent cut-off left side of select2 inside of modal */
/* may be able to remove this after Bootstrap v3.3.5 */
body
.modal-open
{
overflow-y
:
scroll
;
padding-right
:
0
!important
;
}
}
\ No newline at end of file
flask_admin/templates/bootstrap2/admin/lib.html
View file @
7037aac0
...
@@ -101,6 +101,24 @@
...
@@ -101,6 +101,24 @@
</div>
</div>
{%- endmacro %}
{%- endmacro %}
{# ---------------------- Modal Window -------------------------- #}
{% macro add_modal_window(modal_window_id='fa_modal_window') %}
<div
id=
"{{ modal_window_id }}"
class=
"modal hide fade"
tabindex=
"-1"
role=
"dialog"
aria-hidden=
"true"
>
<div
class=
"modal-header"
>
<button
type=
"button"
class=
"close"
data-dismiss=
"modal"
aria-hidden=
"true"
>
×
</button>
<h3>
Loading...
</h3>
</div>
<div
class=
"modal-body"
>
</div>
</div>
{% endmacro %}
{% macro add_modal_button(url='', title='', content='', modal_window_id='fa_modal_window') %}
<a
class=
"icon"
href=
"#"
data-toggle=
"modal"
title=
"{{ title }}"
data-target=
"#{{ modal_window_id }}"
data-remote=
"{{ url }}"
>
{{ content|safe }}
</a>
{% endmacro %}
{# ---------------------- Forms -------------------------- #}
{# ---------------------- Forms -------------------------- #}
{% macro render_field(form, field, kwargs={}, caller=None) %}
{% macro render_field(form, field, kwargs={}, caller=None) %}
{% set direct_error = h.is_field_error(field.errors) %}
{% set direct_error = h.is_field_error(field.errors) %}
...
@@ -167,15 +185,15 @@
...
@@ -167,15 +185,15 @@
{% endif %}
{% endif %}
{% endmacro %}
{% endmacro %}
{% macro form_tag(form=None) %}
{% macro form_tag(form=None
, action=None
) %}
<form
action=
""
method=
"POST"
class=
"admin-form form-horizontal"
enctype=
"multipart/form-data"
>
<form
action=
"
{{ action or '' }}
"
method=
"POST"
class=
"admin-form form-horizontal"
enctype=
"multipart/form-data"
>
<fieldset>
<fieldset>
{{ caller() }}
{{ caller() }}
</fieldset>
</fieldset>
</form>
</form>
{% endmacro %}
{% endmacro %}
{% macro render_form_buttons(cancel_url, extra=None) %}
{% macro render_form_buttons(cancel_url, extra=None
, is_modal=False
) %}
<div
class=
"control-group"
>
<div
class=
"control-group"
>
<div
class=
"controls"
>
<div
class=
"controls"
>
<input
type=
"submit"
class=
"btn btn-primary btn-large"
value=
"{{ _gettext('Save') }}"
/>
<input
type=
"submit"
class=
"btn btn-primary btn-large"
value=
"{{ _gettext('Save') }}"
/>
...
@@ -183,16 +201,16 @@
...
@@ -183,16 +201,16 @@
{{ extra }}
{{ extra }}
{% endif %}
{% endif %}
{% if cancel_url %}
{% if cancel_url %}
<a
href=
"{{ cancel_url }}"
class=
"btn btn-large btn-danger"
>
{{ _gettext('Cancel') }}
</a>
<a
href=
"{{ cancel_url }}"
class=
"btn btn-large btn-danger"
{%
if
is_modal
%}
data-dismiss=
"modal"
{%
endif
%}
>
{{ _gettext('Cancel') }}
</a>
{% endif %}
{% endif %}
</div>
</div>
</div>
</div>
{% endmacro %}
{% endmacro %}
{% macro render_form(form, cancel_url, extra=None, form_opts=None) -%}
{% macro render_form(form, cancel_url, extra=None, form_opts=None
, action=None, is_modal=False
) -%}
{% call form_tag() %}
{% call form_tag(
action=action
) %}
{{ render_form_fields(form, form_opts=form_opts) }}
{{ render_form_fields(form, form_opts=form_opts) }}
{{ render_form_buttons(cancel_url, extra) }}
{{ render_form_buttons(cancel_url, extra
, is_modal
) }}
{% endcall %}
{% endcall %}
{% endmacro %}
{% endmacro %}
...
...
flask_admin/templates/bootstrap2/admin/model/edit.html
View file @
7037aac0
{% extends 'admin/master.html' %}
{%- if not admin_view.edit_modal -%}
{% extends 'admin/master.html' %}
{%- endif -%}
{% import 'admin/lib.html' as lib with context %}
{% import 'admin/lib.html' as lib with context %}
{% macro extra() %}
{% macro extra() %}
...
@@ -6,18 +8,43 @@
...
@@ -6,18 +8,43 @@
{% endmacro %}
{% endmacro %}
{% block head %}
{% block head %}
{%- if not admin_view.edit_modal -%}
{{ super() }}
{{ super() }}
{{ lib.form_css() }}
{{ lib.form_css() }}
{%- endif -%}
{% endblock %}
{% endblock %}
{% block body %}
{% block body %}
{% call lib.form_tag(form) %}
{%- if admin_view.edit_modal -%}
{{ lib.render_form_fields(form, form_opts=form_opts) }}
{# remove save and continue button for modal (it won't function properly) #}
{{ lib.render_form_buttons(return_url, extra()) }}
{{ lib.render_form(form, return_url, extra=None, form_opts=form_opts,
{% endcall %}
action=url_for('.edit_view', id=request.args.get('id'), url=return_url),
is_modal=admin_view.edit_modal) }}
{%- else -%}
{{ lib.render_form(form, return_url, extra(), form_opts,
action=url_for('.edit_view', id=request.args.get('id'), url=return_url),
is_modal=admin_view.edit_modal) }}
{%- endif -%}
{% endblock %}
{% endblock %}
{% block tail %}
{% block tail %}
{{ super() }}
{%- if admin_view.edit_modal -%}
{{ lib.form_js() }}
<script>
{% endblock %}
// fill the header of modal dynamically
$
(
'.modal-header h3'
).
html
(
'{% block modal_header %}<h3>Edit Record #{{ request.args.get('
id
') }}</h3>{% endblock %}'
);
// fixes "remote modal shows same content every time"
$
(
'.modal'
).
on
(
'hidden'
,
function
()
{
$
(
this
).
removeData
(
'modal'
);
});
$
(
function
()
{
// Apply flask-admin global styles after the modal is loaded
window
.
faForm
.
applyGlobalStyles
(
document
);
});
</script>
{%- else -%}
{{ super() }}
{{ lib.form_js() }}
{%- endif -%}
{% endblock %}
\ No newline at end of file
flask_admin/templates/bootstrap2/admin/model/list.html
View file @
7037aac0
...
@@ -102,9 +102,13 @@
...
@@ -102,9 +102,13 @@
<td>
<td>
{% block list_row_actions scoped %}
{% block list_row_actions scoped %}
{%- if admin_view.can_edit -%}
{%- if admin_view.can_edit -%}
<a
class=
"icon"
href=
"{{ get_url('.edit_view', id=get_pk_value(row), url=return_url) }}"
title=
"{{ _gettext('Edit record') }}"
>
{%- if admin_view.edit_modal -%}
<i
class=
"fa fa-pencil icon-pencil"
></i>
{{ lib.add_modal_button(url=get_url('.edit_view', id=get_pk_value(row), url=return_url), title=_gettext('Edit record'), content='
<i
class=
"fa fa-pencil icon-pencil"
></i>
') }}
</a>
{% else %}
<a
class=
"icon"
href=
"{{ get_url('.edit_view', id=get_pk_value(row), url=return_url) }}"
title=
"{{ _gettext('Edit record') }}"
>
<i
class=
"fa fa-pencil icon-pencil"
></i>
</a>
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- if admin_view.can_delete -%}
{%- if admin_view.can_delete -%}
<form
class=
"icon"
method=
"POST"
action=
"{{ get_url('.delete_view') }}"
>
<form
class=
"icon"
method=
"POST"
action=
"{{ get_url('.delete_view') }}"
>
...
@@ -161,6 +165,10 @@
...
@@ -161,6 +165,10 @@
{% endblock %}
{% endblock %}
{{ actionlib.form(actions, get_url('.action_view')) }}
{{ actionlib.form(actions, get_url('.action_view')) }}
{%- if admin_view.edit_modal -%}
{{ lib.add_modal_window() }}
{%- endif -%}
{% endblock %}
{% endblock %}
{% block tail %}
{% block tail %}
...
...
flask_admin/templates/bootstrap3/admin/lib.html
View file @
7037aac0
...
@@ -97,6 +97,23 @@
...
@@ -97,6 +97,23 @@
</ul>
</ul>
{%- endmacro %}
{%- endmacro %}
{# ---------------------- Modal Window ------------------- #}
{% macro add_modal_window(modal_window_id='fa_modal_window', modal_label_id='fa_modal_label') %}
<div
class=
"modal fade"
id=
"{{ modal_window_id }}"
tabindex=
"-1"
role=
"dialog"
aria-labelledby=
"{{ modal_label_id }}"
>
<div
class=
"modal-dialog"
role=
"document"
>
{# bootstrap version > 3.1.0 required for this to work #}
<div
class=
"modal-content"
>
</div>
</div>
</div>
{% endmacro %}
{% macro add_modal_button(url='', title='', content='', modal_window_id='fa_modal_window') %}
<a
class=
"icon"
data-target=
"#{{ modal_window_id }}"
title=
"{{ title }}"
href=
"{{ url }}"
data-backdrop=
"false"
data-toggle=
"modal"
>
{{ content|safe }}
</a>
{% endmacro %}
{# ---------------------- Forms -------------------------- #}
{# ---------------------- Forms -------------------------- #}
{% macro render_field(form, field, kwargs={}, caller=None) %}
{% macro render_field(form, field, kwargs={}, caller=None) %}
{% set direct_error = h.is_field_error(field.errors) %}
{% set direct_error = h.is_field_error(field.errors) %}
...
@@ -166,7 +183,7 @@
...
@@ -166,7 +183,7 @@
</form>
</form>
{% endmacro %}
{% endmacro %}
{% macro render_form_buttons(cancel_url, extra=None) %}
{% macro render_form_buttons(cancel_url, extra=None
, is_modal=False
) %}
<hr>
<hr>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<div
class=
"col-md-offset-2 col-md-10 submit-row"
>
<div
class=
"col-md-offset-2 col-md-10 submit-row"
>
...
@@ -175,16 +192,16 @@
...
@@ -175,16 +192,16 @@
{{ extra }}
{{ extra }}
{% endif %}
{% endif %}
{% if cancel_url %}
{% if cancel_url %}
<a
href=
"{{ cancel_url }}"
class=
"btn btn-danger"
role=
"button"
>
{{ _gettext('Cancel') }}
</a>
<a
href=
"{{ cancel_url }}"
class=
"btn btn-danger"
role=
"button"
{%
if
is_modal
%}
data-dismiss=
"modal"
{%
endif
%}
>
{{ _gettext('Cancel') }}
</a>
{% endif %}
{% endif %}
</div>
</div>
</div>
</div>
{% endmacro %}
{% endmacro %}
{% macro render_form(form, cancel_url, extra=None, form_opts=None, action=None) -%}
{% macro render_form(form, cancel_url, extra=None, form_opts=None, action=None
, is_modal=False
) -%}
{% call form_tag(action=action) %}
{% call form_tag(action=action) %}
{{ render_form_fields(form, form_opts=form_opts) }}
{{ render_form_fields(form, form_opts=form_opts) }}
{{ render_form_buttons(cancel_url, extra) }}
{{ render_form_buttons(cancel_url, extra
, is_modal
) }}
{% endcall %}
{% endcall %}
{% endmacro %}
{% endmacro %}
...
...
flask_admin/templates/bootstrap3/admin/model/edit.html
View file @
7037aac0
{% extends 'admin/master.html' %}
{%- if not admin_view.edit_modal -%}
{% extends 'admin/master.html' %}
{%- endif -%}
{% import 'admin/lib.html' as lib with context %}
{% import 'admin/lib.html' as lib with context %}
{% macro extra() %}
{% macro extra() %}
...
@@ -6,18 +8,47 @@
...
@@ -6,18 +8,47 @@
{% endmacro %}
{% endmacro %}
{% block head %}
{% block head %}
{%- if not admin_view.edit_modal -%}
{{ super() }}
{{ super() }}
{{ lib.form_css() }}
{{ lib.form_css() }}
{%- endif -%}
{% endblock %}
{% endblock %}
{% block body %}
{% block body %}
{% call lib.form_tag(form) %}
{%- if admin_view.edit_modal -%}
{{ lib.render_form_fields(form, form_opts=form_opts) }}
{# content added to modal-content #}
{{ lib.render_form_buttons(return_url, extra()) }}
<div
class=
"modal-header"
>
{% endcall %}
<button
type=
"button"
class=
"close"
data-dismiss=
"modal"
aria-label=
"Close"
><span
aria-hidden=
"true"
>
×
</span></button>
{% block modal_header %}
<h3>
Edit Record #{{ request.args.get('id') }}
</h3>
{% endblock %}
</div>
<div
class=
"modal-body"
>
{# remove save and continue button for modal (it won't function properly) #}
{{ lib.render_form(form, return_url, extra=None, form_opts=form_opts,
action=url_for('.edit_view', id=request.args.get('id'), url=return_url),
is_modal=admin_view.edit_modal) }}
</div>
{%- else -%}
{{ lib.render_form(form, return_url, extra(), form_opts,
action=url_for('.edit_view', id=request.args.get('id'), url=return_url),
is_modal=admin_view.edit_modal) }}
{%- endif -%}
{% endblock %}
{% endblock %}
{% block tail %}
{% block tail %}
{{ super() }}
{%- if admin_view.edit_modal -%}
{{ lib.form_js() }}
<script>
// fixes "remote modal shows same content every time", avoiding the flicker
$
(
'body'
).
on
(
'hidden.bs.modal'
,
'.modal'
,
function
()
{
$
(
this
).
removeData
(
'bs.modal'
).
find
(
".modal-content"
).
empty
();
});
$
(
function
()
{
// Apply flask-admin global styles after the modal is loaded
window
.
faForm
.
applyGlobalStyles
(
document
);
});
</script>
{%- else -%}
{{ super() }}
{{ lib.form_js() }}
{%- endif -%}
{% endblock %}
{% endblock %}
flask_admin/templates/bootstrap3/admin/model/list.html
View file @
7037aac0
...
@@ -102,9 +102,13 @@
...
@@ -102,9 +102,13 @@
<td>
<td>
{% block list_row_actions scoped %}
{% block list_row_actions scoped %}
{%- if admin_view.can_edit -%}
{%- if admin_view.can_edit -%}
<a
class=
"icon"
href=
"{{ get_url('.edit_view', id=get_pk_value(row), url=return_url) }}"
title=
"{{ _gettext('Edit record') }}"
>
{%- if admin_view.edit_modal -%}
<span
class=
"fa fa-pencil glyphicon glyphicon-pencil"
></span>
{{ lib.add_modal_button(url=get_url('.edit_view', id=get_pk_value(row), url=return_url), title=_gettext('Edit record'), content='
<span
class=
"fa fa-pencil glyphicon glyphicon-pencil"
></span>
') }}
</a>
{% else %}
<a
class=
"icon"
href=
"{{ get_url('.edit_view', id=get_pk_value(row), url=return_url) }}"
title=
"{{ _gettext('Edit record') }}"
>
<span
class=
"fa fa-pencil glyphicon glyphicon-pencil"
></span>
</a>
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- if admin_view.can_delete -%}
{%- if admin_view.can_delete -%}
<form
class=
"icon"
method=
"POST"
action=
"{{ get_url('.delete_view') }}"
>
<form
class=
"icon"
method=
"POST"
action=
"{{ get_url('.delete_view') }}"
>
...
@@ -160,6 +164,10 @@
...
@@ -160,6 +164,10 @@
{% endblock %}
{% endblock %}
{{ actionlib.form(actions, get_url('.action_view')) }}
{{ actionlib.form(actions, get_url('.action_view')) }}
{%- if admin_view.edit_modal -%}
{{ lib.add_modal_window() }}
{%- endif -%}
{% endblock %}
{% endblock %}
{% block tail %}
{% block tail %}
...
...
flask_admin/tests/test_model.py
View file @
7037aac0
...
@@ -452,6 +452,53 @@ def test_custom_form():
...
@@ -452,6 +452,53 @@ def test_custom_form():
ok_
(
not
hasattr
(
view
.
_create_form_class
,
'col1'
))
ok_
(
not
hasattr
(
view
.
_create_form_class
,
'col1'
))
def
test_modal_edit
():
# bootstrap 2 - test edit_modal
app_bs2
=
Flask
(
__name__
)
admin_bs2
=
Admin
(
app_bs2
,
template_mode
=
"bootstrap2"
)
modal_view
=
MockModelView
(
Model
,
edit_modal
=
True
,
endpoint
=
"modal_on"
)
no_modal_view
=
MockModelView
(
Model
,
edit_modal
=
False
,
endpoint
=
"modal_off"
)
admin_bs2
.
add_view
(
modal_view
)
admin_bs2
.
add_view
(
no_modal_view
)
client_bs2
=
app_bs2
.
test_client
()
# bootstrap 2 - ensure modal window is added when edit_modal is enabled
rv
=
client_bs2
.
get
(
'/admin/modal_on/'
)
eq_
(
rv
.
status_code
,
200
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'fa_modal_window'
in
data
)
# bootstrap 2 - test modal disabled
rv
=
client_bs2
.
get
(
'/admin/modal_off/'
)
eq_
(
rv
.
status_code
,
200
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'fa_modal_window'
not
in
data
)
# bootstrap 3
app_bs3
=
Flask
(
__name__
)
admin_bs3
=
Admin
(
app_bs3
,
template_mode
=
"bootstrap3"
)
admin_bs3
.
add_view
(
modal_view
)
admin_bs3
.
add_view
(
no_modal_view
)
client_bs3
=
app_bs3
.
test_client
()
# bootstrap 3 - ensure modal window is added when edit_modal is enabled
rv
=
client_bs3
.
get
(
'/admin/modal_on/'
)
eq_
(
rv
.
status_code
,
200
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'fa_modal_window'
in
data
)
# bootstrap 3 - test modal disabled
rv
=
client_bs3
.
get
(
'/admin/modal_off/'
)
eq_
(
rv
.
status_code
,
200
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'fa_modal_window'
not
in
data
)
def
check_class_name
():
def
check_class_name
():
class
DummyView
(
MockModelView
):
class
DummyView
(
MockModelView
):
pass
pass
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment