Adds client-side templating capabilities.
Includes and example implementation for modal dialog confirmations of dangerous actions. Implements blueprint client-side-templating. Change-Id: I275e6fa973653268882bca6beb2637a82ca1d4ff
This commit is contained in:
5
horizon/horizon/static/horizon/js/hogan-1.0.5.min.js
vendored
Normal file
5
horizon/horizon/static/horizon/js/hogan-1.0.5.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -20,6 +20,15 @@ var Horizon = function() {
|
|||||||
|
|
||||||
/* Call all initialization functions and clear the queue. */
|
/* Call all initialization functions and clear the queue. */
|
||||||
horizon.init = function() {
|
horizon.init = function() {
|
||||||
|
// Load client-side template fragments and compile them.
|
||||||
|
horizon.templates.compile_templates();
|
||||||
|
|
||||||
|
// Bind event handlers to confirm dangerous actions.
|
||||||
|
$("body").on("click", "form .btn.danger", function (evt) {
|
||||||
|
horizon.datatables.confirm(this);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
$.each(initFunctions, function(ind, fn) {
|
$.each(initFunctions, function(ind, fn) {
|
||||||
fn();
|
fn();
|
||||||
});
|
});
|
||||||
@@ -28,6 +37,7 @@ var Horizon = function() {
|
|||||||
initFunctions = [];
|
initFunctions = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Namespace for core functionality related to DataTables. */
|
||||||
horizon.datatables = {
|
horizon.datatables = {
|
||||||
update: function () {
|
update: function () {
|
||||||
var rows_to_update = $('tr.status_unknown');
|
var rows_to_update = $('tr.status_unknown');
|
||||||
@@ -41,6 +51,50 @@ var Horizon = function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Generates a confirmation modal dialog for the given action. */
|
||||||
|
horizon.datatables.confirm = function (action) {
|
||||||
|
var $action = $(action),
|
||||||
|
action_string, title, body, modal, form;
|
||||||
|
action_string = $action.text();
|
||||||
|
title = "Confirm " + action_string;
|
||||||
|
body = "Please confirm your selection. This action cannot be undone.";
|
||||||
|
modal = horizon.modals.create(title, body, action_string);
|
||||||
|
modal.modal('show');
|
||||||
|
modal.find('.btn.primary').click(function (evt) {
|
||||||
|
form = $action.closest('form');
|
||||||
|
form.append("<input type='hidden' name='" + $action.attr('name') + "' value='" + $action.attr('value') + "'/>");
|
||||||
|
form.submit();
|
||||||
|
});
|
||||||
|
return modal;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Namespace for core functionality related to client-side templating. */
|
||||||
|
horizon.templates = {
|
||||||
|
template_ids: ["#modal_template"],
|
||||||
|
compiled_templates: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Pre-loads and compiles the client-side templates. */
|
||||||
|
horizon.templates.compile_templates = function () {
|
||||||
|
$.each(horizon.templates.template_ids, function (ind, template_id) {
|
||||||
|
horizon.templates.compiled_templates[template_id] = Hogan.compile($(template_id).text());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Namespace for core functionality related to modal dialogs. */
|
||||||
|
horizon.modals = {};
|
||||||
|
|
||||||
|
/* Creates a modal dialog from the client-side template. */
|
||||||
|
horizon.modals.create = function (title, body, confirm, cancel) {
|
||||||
|
if (!cancel) {
|
||||||
|
cancel = "Cancel";
|
||||||
|
}
|
||||||
|
var template = horizon.templates.compiled_templates["#modal_template"],
|
||||||
|
params = {title: title, body: body, confirm: confirm, cancel: cancel},
|
||||||
|
modal = $(template.render(params)).appendTo("body");
|
||||||
|
return modal;
|
||||||
|
};
|
||||||
|
|
||||||
return horizon;
|
return horizon;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
22
horizon/horizon/templates/horizon/client_side/_modal.html
Normal file
22
horizon/horizon/templates/horizon/client_side/_modal.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{% extends "horizon/client_side/template.html" %}
|
||||||
|
{% load horizon %}
|
||||||
|
|
||||||
|
{% block id %}modal_template{% endblock %}
|
||||||
|
|
||||||
|
{% block template %}
|
||||||
|
{% jstemplate %}
|
||||||
|
<div class="modal hide fade">
|
||||||
|
<div class='modal-header'>
|
||||||
|
<a class='close' data-dismiss='modal'>×</a>
|
||||||
|
<h3>[[title]]</h3>
|
||||||
|
</div>
|
||||||
|
<div class='modal-body'>
|
||||||
|
[[body]]
|
||||||
|
</div>
|
||||||
|
<div class='modal-footer'>
|
||||||
|
<a href='#' class='btn primary'>[[confirm]]</a>
|
||||||
|
<a href='#' class='btn' data-dismiss='modal'>[[cancel]]</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endjstemplate %}
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<script type="text/html" id="{% block id %}{% endblock %}">{% block template %}{% endblock %}</script>
|
||||||
@@ -94,3 +94,25 @@ def horizon_dashboard_nav(context):
|
|||||||
return {'components': non_empty_panels,
|
return {'components': non_empty_panels,
|
||||||
'user': context['request'].user,
|
'user': context['request'].user,
|
||||||
'current': context['request'].horizon['panel'].slug}
|
'current': context['request'].horizon['panel'].slug}
|
||||||
|
|
||||||
|
|
||||||
|
class JSTemplateNode(template.Node):
|
||||||
|
""" Helper node for the ``jstemplate`` template tag. """
|
||||||
|
def __init__(self, nodelist):
|
||||||
|
self.nodelist = nodelist
|
||||||
|
|
||||||
|
def render(self, context, ):
|
||||||
|
output = self.nodelist.render(context)
|
||||||
|
return output.replace('[[', '{{').replace(']]', '}}')
|
||||||
|
|
||||||
|
|
||||||
|
@register.tag
|
||||||
|
def jstemplate(parser, token):
|
||||||
|
"""
|
||||||
|
Replaces ``[[`` and ``]]`` with ``{{`` and ``}}`` to avoid conflicts
|
||||||
|
with Django's template engine when using any of the Mustache-based
|
||||||
|
templating libraries.
|
||||||
|
"""
|
||||||
|
nodelist = parser.parse(('endjstemplate',))
|
||||||
|
parser.delete_first_token()
|
||||||
|
return JSTemplateNode(nodelist)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
<script src="{{ STATIC_URL }}dashboard/js/bootstrap/bootstrap-popover.js" type="text/javascript" charset="utf-8"></script>
|
<script src="{{ STATIC_URL }}dashboard/js/bootstrap/bootstrap-popover.js" type="text/javascript" charset="utf-8"></script>
|
||||||
<script src="{{ STATIC_URL }}dashboard/js/bootstrap/bootstrap-transition.js" type="text/javascript" charset="utf-8"></script>
|
<script src="{{ STATIC_URL }}dashboard/js/bootstrap/bootstrap-transition.js" type="text/javascript" charset="utf-8"></script>
|
||||||
<script src="{{ STATIC_URL }}dashboard/js/bootstrap/bootstrap-typeahead.js" type="text/javascript" charset="utf-8"></script>
|
<script src="{{ STATIC_URL }}dashboard/js/bootstrap/bootstrap-typeahead.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="{{ STATIC_URL }}horizon/js/hogan-1.0.5.min.js" type="text/javascript"></script>
|
||||||
<script src='{{ STATIC_URL }}horizon/js/horizon.js' type='text/javascript' charset='utf-8'></script>
|
<script src='{{ STATIC_URL }}horizon/js/horizon.js' type='text/javascript' charset='utf-8'></script>
|
||||||
<script src='{{ STATIC_URL }}dashboard/js/plugins.js' type='text/javascript' charset='utf-8'></script>
|
<script src='{{ STATIC_URL }}dashboard/js/plugins.js' type='text/javascript' charset='utf-8'></script>
|
||||||
<script src='{{ STATIC_URL }}dashboard/js/tables.js' type='text/javascript' charset='utf-8'></script>
|
<script src='{{ STATIC_URL }}dashboard/js/tables.js' type='text/javascript' charset='utf-8'></script>
|
||||||
@@ -49,7 +50,8 @@
|
|||||||
<div id="footer">
|
<div id="footer">
|
||||||
{% block footer %}{% endblock %}
|
{% block footer %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
{% block footer_js %}{% endblock %}
|
{% block footer_js %}
|
||||||
|
{% include "horizon/client_side/_modal.html" %}
|
||||||
|
{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user