diff options
author | Jenkins <jenkins@review.openstack.org> | 2013-10-09 06:03:26 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2013-10-09 06:03:26 +0000 |
commit | 177d972960beaa306f31b35060e4f73ea6b00c77 (patch) | |
tree | 77e84b165536d71bb3ba66b6c1225a4db566958b | |
parent | 99fb8f630c751b8a938808a9974fe6a4003afdcc (diff) | |
parent | 87ce84eede864660b5d1be45592e12c37a312d52 (diff) | |
download | tuskar-ui-177d972960beaa306f31b35060e4f73ea6b00c77.tar.gz |
Merge "JavaScript enhancements for the FormsetDataTable"
5 files changed, 326 insertions, 0 deletions
diff --git a/tuskar_ui/infrastructure/static/infrastructure/js/tuskar.formset_table.js b/tuskar_ui/infrastructure/static/infrastructure/js/tuskar.formset_table.js new file mode 100644 index 00000000..61b0a87d --- /dev/null +++ b/tuskar_ui/infrastructure/static/infrastructure/js/tuskar.formset_table.js @@ -0,0 +1,79 @@ +tuskar.formset_table = (function () { + 'use strict'; + + var module = {}; + + + // go through the whole table and fix the numbering of rows + module.reenumerate_rows = function (table, prefix) { + var count = 0; + var input_name_re = new RegExp('^' + prefix + '-(\\d+|__prefix__)-'); + var input_id_re = new RegExp('^id_' + prefix + '-(\\d+|__prefix__)-'); + + table.find('tbody tr').each(function () { + $(this).find('input').each(function () { + var input = $(this); + input.attr('name', input.attr('name').replace( + input_name_re, prefix + '-' + count + '-')); + input.attr('id', input.attr('id').replace( + input_id_re, 'id_' + prefix + '-' + count + '-')); + }); + count += 1; + }); + $('#id_' + prefix + '-TOTAL_FORMS').val(count); + }; + + // mark a row as deleted and hide it + module.delete_row = function (e) { + $(this).closest('tr').hide(); + $(this).prev('input[name$="-DELETE"]').attr('checked', true); + }; + + // replace the "Delete" checkboxes with × for deleting rows + module.replace_delete = function (where) { + where.find('input[name$="-DELETE"]').hide().after( + $('<a href="#" class="close">×</a>').click(module.delete_row) + ); + }; + + // add more empty rows in the flavors table + module.add_row = function (table, prefix, empty_row_html) { + var new_row = $(empty_row_html); + module.replace_delete(new_row); + table.find('tbody').append(new_row); + module.reenumerate_rows(table, prefix); + }; + + // prepare all the javascript for formset table + module.init = function (prefix, empty_row_html, add_label) { + + var table = $('table#' + prefix); + + module.replace_delete(table); + + // if there are extra empty rows, add the button for new rows + if ($('#id_' + prefix + '-TOTAL_FORMS').val() > + $('#id_' + prefix + '-INITIAL_FORMS').val()) { + table.find('tfoot td').append( + '<a href="#" class="btn btn-small pull-right">' + + add_label + + '</a>' + ).click(function () { + module.add_row(table, prefix, empty_row_html); + }); + }; + + // if the formset is not empty, and is not being redisplayed, + // delete the empty extra row from the end + if (table.find('tbody tr').length > 1 && + $('#id_' + prefix + '-TOTAL_FORMS').val() > + $('#id_' + prefix + '-INITIAL_FORMS').val()) { + table.find('tbody tr:last').remove(); + module.reenumerate_rows(table, prefix); + $('#id_' + prefix + '-INITIAL_FORMS').val( + $('#id_' + prefix + '-TOTAL_FORMS').val()); + }; + }; + + return module; +} ()); diff --git a/tuskar_ui/infrastructure/static/infrastructure/tests/formset_table.js b/tuskar_ui/infrastructure/static/infrastructure/tests/formset_table.js new file mode 100644 index 00000000..720b9d56 --- /dev/null +++ b/tuskar_ui/infrastructure/static/infrastructure/tests/formset_table.js @@ -0,0 +1,73 @@ +horizon.addInitFunction(function () { + module("Formset table (tuskar.formset_table.js)"); + + test("Reenumerate rows", function () { + var html = $('#qunit-fixture'); + var table = html.find('table'); + var input = table.find('tbody tr#flavors__row__14 input').first(); + + input.attr('id', 'id_flavors-3-name'); + tuskar.formset_table.reenumerate_rows(table, 'flavors'); + equal(input.attr('id'), 'id_flavors-0-name', "Enumerate old rows ids"); + input.attr('id', 'id_flavors-__prefix__-name'); + tuskar.formset_table.reenumerate_rows(table, 'flavors'); + equal(input.attr('id'), 'id_flavors-0-name', "Enumerate new rows ids"); + }); + + test("Delete row", function () { + var html = $('#qunit-fixture'); + var table = html.find('table'); + var row = table.find('tbody tr').first(); + var input = row.find('input#id_flavors-0-DELETE'); + + equal(row.css("display"), 'table-row'); + equal(input.attr('checked'), undefined); + tuskar.formset_table.replace_delete(row); + var x = input.next('a'); + tuskar.formset_table.delete_row.call(x) + equal(row.css("display"), 'none'); + equal(input.attr('checked'), 'checked'); + }); + + test("Add row", function() { + var html = $('#qunit-fixture'); + var table = html.find('table'); + var empty_row_html = '<tr><td><input id="id_flavors-__prefix__-name" name="flavors-__prefix__-name"></td></tr>'; + + equal(table.find('tbody tr').length, 3); + equal(html.find('#id_flavors-TOTAL_FORMS').val(), 3); + tuskar.formset_table.add_row(table, 'flavors', empty_row_html); + equal(table.find('tbody tr').length, 4); + equal(table.find('tbody tr:last input').attr('id'), 'id_flavors-3-name'); + equal(html.find('#id_flavors-TOTAL_FORMS').val(), 4); + }); + + test("Init formset table", function() { + var html = $('#qunit-fixture'); + var table = html.find('table'); + + equal(table.find('tbody tr').length, 3); + equal(html.find('#id_flavors-TOTAL_FORMS').val(), 3); + equal(html.find('#id_flavors-INITIAL_FORMS').val(), 2); + tuskar.formset_table.init('flavors', '', 'Add row'); + equal(table.find('tfoot tr a').html(), 'Add row'); + equal(table.find('tbody tr').length, 2); + equal(html.find('#id_flavors-TOTAL_FORMS').val(), 2); + equal(html.find('#id_flavors-INITIAL_FORMS').val(), 2); + }); + + test("Init formset table -- no add", function() { + var html = $('#qunit-fixture'); + var table = html.find('table'); + + table.find('tbody tr:last').remove(); + html.find('#id_flavors-TOTAL_FORMS').val(2); + html.find('#id_flavors-INITIAL_FORMS').val(2); + equal(table.find('tbody tr').length, 2); + tuskar.formset_table.init('flavors', '', 'Add row'); + equal(table.find('tfoot tr a').length, 0); + equal(table.find('tbody tr').length, 2); + equal(html.find('#id_flavors-TOTAL_FORMS').val(), 2); + equal(html.find('#id_flavors-INITIAL_FORMS').val(), 2); + }); +}); diff --git a/tuskar_ui/infrastructure/templates/formset_table/_table.html b/tuskar_ui/infrastructure/templates/formset_table/_table.html index 5ef160af..22532bd1 100644 --- a/tuskar_ui/infrastructure/templates/formset_table/_table.html +++ b/tuskar_ui/infrastructure/templates/formset_table/_table.html @@ -25,4 +25,15 @@ {% endif %} {% endwith %} {{ block.super }} + +<script type="text/javascript"> + ($ || addHorizonLoadEvent)(function () { + // prepare the js-enabled parts of the formset data table + var prefix = '{{ table.name|escapejs }}'; + var empty_row_html = '{% filter escapejs %}{% include "formset_table/_row.html" with row=table.get_empty_row %}{% endfilter %}'; + var add_label = '{% filter escapejs %}{% trans "Add a row" %}{% endfilter %}'; + + tuskar.formset_table.init(prefix, empty_row_html, add_label); + }); +</script> {% endblock table %} diff --git a/tuskar_ui/infrastructure/templates/infrastructure/_scripts.html b/tuskar_ui/infrastructure/templates/infrastructure/_scripts.html index 73733889..a764f386 100644 --- a/tuskar_ui/infrastructure/templates/infrastructure/_scripts.html +++ b/tuskar_ui/infrastructure/templates/infrastructure/_scripts.html @@ -5,6 +5,7 @@ <script src='{{ STATIC_URL }}infrastructure/js/horizon.d3singlebarchart.js' type='text/javascript' charset='utf-8'></script> <script src='{{ STATIC_URL }}infrastructure/js/tuskar.js' type='text/javascript' charset='utf-8'></script> <script src='{{ STATIC_URL }}infrastructure/js/tuskar.templates.js' type='text/javascript' charset='utf-8'></script> + <script src='{{ STATIC_URL }}infrastructure/js/tuskar.formset_table.js' type='text/javascript' charset='utf-8'></script> {% endblock %} {% comment %} Tuskar-UI Client-side Templates (These should *not* be inside the "compress" tag.) {% endcomment %} diff --git a/tuskar_ui/infrastructure/templates/infrastructure/qunit.html b/tuskar_ui/infrastructure/templates/infrastructure/qunit.html index ad03ae99..e0e0ba8a 100644 --- a/tuskar_ui/infrastructure/templates/infrastructure/qunit.html +++ b/tuskar_ui/infrastructure/templates/infrastructure/qunit.html @@ -9,6 +9,7 @@ {% include "horizon/_conf.html" %} {% comment %}Load test modules here.{% endcomment %} + <script type="text/javascript" src="{{ STATIC_URL }}infrastructure/tests/formset_table.js"></script> {% comment %}End test modules.{% endcomment %} {% include "horizon/_scripts.html" %} @@ -22,6 +23,167 @@ <ol id="qunit-tests"></ol> <div id="qunit-fixture"> <!-- Test markup; will be hidden. --> + +<div class="table_wrapper"> + <input id="id_flavors-TOTAL_FORMS" name="flavors-TOTAL_FORMS" + type="hidden" value="3"><input id="id_flavors-INITIAL_FORMS" + name="flavors-INITIAL_FORMS" type="hidden" value="2"><input id= + "id_flavors-MAX_NUM_FORMS" name="flavors-MAX_NUM_FORMS" type= + "hidden" value="1000"> + + <table id="flavors" class= + "table table-bordered table-striped datatable"> + <thead> + <tr class='table_caption'> + <th class='table_header' colspan='8'> + <h3 class='table_title'>Flavors</h3> + + <div class="table_actions clearfix"></div> + </th> + </tr> + + <tr> + <th class="sortable normal_column"><span class= + "required">Flavor Name</span></th> + + <th class="sortable normal_column"><span class= + "required">VCPU</span></th> + + <th class="sortable normal_column"><span class= + "required">RAM (MB)</span></th> + + <th class="sortable normal_column"><span class= + "required">Root Disk (GB)</span></th> + + <th class="sortable normal_column"><span>Ephemeral Disk + (GB)</span></th> + + <th class="sortable normal_column"><span>Swap Disk + (MB)</span></th> + + <th class="sortable normal_column"><span>Max. + VMs</span></th> + + <th class="sortable normal_column"> + <span>Delete</span></th> + </tr> + </thead> + + <tbody> + <tr class="" data-display="yyy.1" id="flavors__row__14"> + <td class="sortable normal_column"><input class= + "input input-small" id="id_flavors-0-name" maxlength="25" + name="flavors-0-name" type="text" value="1"> <input id= + "id_flavors-0-id" name="flavors-0-id" type="hidden" + value="14"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-0-cpu" name= + "flavors-0-cpu" type="number" value="1"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-0-memory" name= + "flavors-0-memory" type="number" value="1"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-0-storage" name= + "flavors-0-storage" type="number" value="1"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id= + "id_flavors-0-ephemeral_disk" name= + "flavors-0-ephemeral_disk" type="number"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-0-swap_disk" + name="flavors-0-swap_disk" type="number"></td> + + <td class="sortable normal_column">-</td> + + <td class="sortable normal_column"><input id= + "id_flavors-0-DELETE" name="flavors-0-DELETE" type= + "checkbox"></td> + </tr> + + <tr class="" data-display="yyy.2" id="flavors__row__15"> + <td class="sortable normal_column"><input class= + "input input-small" id="id_flavors-1-name" maxlength="25" + name="flavors-1-name" type="text" value="2"> <input id= + "id_flavors-1-id" name="flavors-1-id" type="hidden" + value="15"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-1-cpu" name= + "flavors-1-cpu" type="number" value="2"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-1-memory" name= + "flavors-1-memory" type="number" value="2"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-1-storage" name= + "flavors-1-storage" type="number" value="2"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id= + "id_flavors-1-ephemeral_disk" name= + "flavors-1-ephemeral_disk" type="number"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-1-swap_disk" + name="flavors-1-swap_disk" type="number"></td> + + <td class="sortable normal_column">-</td> + + <td class="sortable normal_column"><input id= + "id_flavors-1-DELETE" name="flavors-1-DELETE" type= + "checkbox"></td> + </tr> + + <tr class="current_selected"> + <td class="sortable normal_column"><input class= + "input input-small" id="id_flavors-2-name" maxlength="25" + name="flavors-2-name" type="text"> <input id= + "id_flavors-2-id" name="flavors-2-id" type="hidden"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-2-cpu" name= + "flavors-2-cpu" type="number"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-2-memory" name= + "flavors-2-memory" type="number"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-2-storage" name= + "flavors-2-storage" type="number"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id= + "id_flavors-2-ephemeral_disk" name= + "flavors-2-ephemeral_disk" type="number"></td> + + <td class="sortable normal_column"><input class= + "input number_input_slim" id="id_flavors-2-swap_disk" + name="flavors-2-swap_disk" type="number"></td> + + <td class="sortable normal_column">-</td> + + <td class="sortable normal_column"><input id= + "id_flavors-2-DELETE" name="flavors-2-DELETE" type= + "checkbox"></td> + </tr> + </tbody> + + <tfoot> + <tr> + <td colspan="8"><span class="table_count">Displaying 3 + items</span></td> + </tr> + </tfoot> + </table> +</div> + </div> </body> </html> |