From 92146772b677e9fce57cc11b4a4a1542a05c23b2 Mon Sep 17 00:00:00 2001 From: Jiri Tomasek Date: Wed, 2 Jul 2014 14:05:54 +0200 Subject: [PATCH] Update Twitter Bootstrap to version 3 Updated to bootstrap 3.2.0 back to v3.1.1 fix base-line-height variable Revamped grid system Replaced help-inline with help-block Change .control-group to .form-group Add column widths to horizontal form labels and .controls, remove .controls class Datepicker form fix Add btn-default to btn elements with no other color Topbar switcher fix Rename button sizes Replace alert-error with alert-danger Removed alert-block Alerts fixing Updated LinkAction and Action table actions to define icon, replaced btn-default icon with glyphicon Replaced icons with glyphicons, removed btn-icon styling from horizon.scss change Button Icons text in customizing docs Fixed table header Fix page_header h2 margin Nav accordion fix Tables fix Modal fixes added form-control class to input and selects Forms fixes Workflow modal fix Fix quota bar updated customizing docs removed unused styling from horizon.scss make datepicker form inline fix table filter styling added btn-danger to terminate instances button fixed loading spinner form fields and validations Created bootstrap_form_field filter and template to render bootstrap forms properly Style up the datepicker Fixed failing test cases Implements: blueprint bootstrap-update Change-Id: Ic826849be1af7fc6bf06f97dd7a60fc54b862148 --- doc/source/topics/customizing.rst | 45 +- doc/source/topics/tutorial.rst | 4 +- horizon/static/bootstrap/js/bootstrap.js | 2949 +++++++++-------- .../static/horizon/js/horizon.d3linechart.js | 16 +- .../static/horizon/js/horizon.firewalls.js | 4 +- horizon/static/horizon/js/horizon.forms.js | 16 +- .../horizon/js/horizon.formset_table.js | 2 +- .../static/horizon/js/horizon.instances.js | 16 +- horizon/static/horizon/js/horizon.messages.js | 2 +- horizon/static/horizon/js/horizon.modals.js | 24 +- horizon/static/horizon/js/horizon.tables.js | 2 +- horizon/static/horizon/js/horizon.users.js | 2 +- horizon/static/horizon/lib/angular/angular.js | 102 +- horizon/static/horizon/tests/messages.js | 4 +- horizon/tables/actions.py | 15 +- horizon/tables/formset.py | 2 +- horizon/templates/auth/_login.html | 8 +- horizon/templates/horizon/_messages.html | 8 +- .../horizon/client_side/_alert_message.html | 2 +- .../horizon/client_side/_loading.html | 10 +- .../templates/horizon/client_side/_modal.html | 26 +- .../horizon/common/_bootstrap_form_field.html | 59 + .../horizon/common/_data_table_cell.html | 4 +- .../common/_data_table_row_actions.html | 2 +- .../common/_data_table_table_action.html | 10 +- .../common/_data_table_table_actions.html | 11 +- .../horizon/common/_form_fields.html | 14 +- .../horizon/common/_formset_table.html | 2 +- .../horizon/common/_formset_table_row.html | 4 +- horizon/templates/horizon/common/_modal.html | 20 +- .../templates/horizon/common/_modal_form.html | 60 +- .../horizon/common/_usage_summary.html | 15 +- .../templates/horizon/common/_workflow.html | 86 +- .../common/_workflow_step_update_members.html | 4 +- horizon/templatetags/bootstrap_form_field.py | 47 + horizon/workflows/views.py | 2 +- .../dashboards/admin/aggregates/tables.py | 9 +- .../templates/aggregates/_update.html | 4 +- .../dashboards/admin/domains/tables.py | 9 +- .../dashboards/admin/flavors/extras/tables.py | 6 +- .../dashboards/admin/flavors/tables.py | 13 +- .../templates/flavors/extras/_create.html | 2 +- .../templates/flavors/extras/_edit.html | 2 +- .../templates/flavors/extras/_index.html | 2 +- .../dashboards/admin/groups/tables.py | 13 +- .../templates/groups/_add_non_member.html | 2 +- .../groups/templates/groups/_create.html | 2 +- .../groups/templates/groups/_update.html | 2 +- .../images/templates/images/_create.html | 2 +- .../images/templates/images/_update.html | 2 +- .../admin/info/templates/info/index.html | 4 +- .../templates/instances/_live_migrate.html | 2 +- .../metering/templates/metering/daily.html | 40 +- .../metering/templates/metering/index.html | 4 +- .../metering/templates/metering/report.html | 4 +- .../metering/templates/metering/stats.html | 60 +- .../dashboards/admin/networks/ports/tables.py | 6 +- .../admin/networks/subnets/tables.py | 6 +- .../dashboards/admin/networks/tables.py | 6 +- .../networks/templates/networks/_create.html | 2 +- .../networks/templates/networks/_update.html | 2 +- .../templates/networks/ports/_create.html | 2 +- .../templates/networks/ports/_update.html | 2 +- .../dashboards/admin/projects/tables.py | 14 +- .../dashboards/admin/projects/tests.py | 15 +- .../dashboards/admin/roles/tables.py | 6 +- .../admin/roles/templates/roles/_create.html | 2 +- .../admin/roles/templates/roles/_update.html | 2 +- .../routers/templates/routers/detail.html | 4 +- .../dashboards/admin/users/tables.py | 6 +- .../admin/users/templates/users/_create.html | 2 +- .../admin/users/templates/users/_update.html | 2 +- .../dashboards/admin/volumes/tables.py | 3 +- .../volumes/_create_volume_type.html | 2 +- .../volumes/templates/volumes/detail.html | 4 +- .../access_and_security/api_access/tables.py | 4 +- .../floating_ips/tables.py | 9 +- .../access_and_security/keypairs/tables.py | 6 +- .../security_groups/tables.py | 11 +- .../floating_ips/_allocate.html | 2 +- .../templates/access_and_security/index.html | 4 +- .../access_and_security/keypairs/_create.html | 2 +- .../access_and_security/keypairs/_import.html | 2 +- .../security_groups/_add_rule.html | 2 +- .../security_groups/_create.html | 2 +- .../security_groups/_update.html | 2 +- .../dashboards/project/containers/tables.py | 23 +- .../containers/_container_detail.html | 6 +- .../templates/containers/_copy.html | 2 +- .../templates/containers/_create.html | 2 +- .../containers/_create_pseudo_folder.html | 2 +- .../templates/containers/_object_detail.html | 6 +- .../templates/containers/_update.html | 2 +- .../templates/containers/_upload.html | 2 +- .../_details.html | 4 +- .../data_processing.data_plugins/details.html | 6 +- .../project/database_backups/tables.py | 9 +- .../templates/database_backups/details.html | 8 +- .../dashboards/project/databases/tables.py | 9 +- .../templates/databases/_detail_overview.html | 17 +- .../databases/templates/databases/detail.html | 4 +- .../dashboards/project/firewalls/tables.py | 6 +- .../firewalls/_firewall_details.html | 2 +- .../firewalls/_insert_rule_to_policy.html | 2 +- .../templates/firewalls/_policy_details.html | 2 +- .../firewalls/_remove_rule_from_policy.html | 2 +- .../templates/firewalls/_rule_details.html | 2 +- .../templates/firewalls/_updatefirewall.html | 2 +- .../templates/firewalls/_updatepolicy.html | 2 +- .../templates/firewalls/_updaterule.html | 2 +- .../templates/firewalls/details_tabs.html | 4 +- .../project/images/images/tables.py | 12 +- .../templates/images/images/_create.html | 2 +- .../images/images/_detail_overview.html | 6 +- .../templates/images/images/_update.html | 2 +- .../templates/images/images/detail.html | 4 +- .../templates/images/snapshots/_create.html | 2 +- .../dashboards/project/instances/tables.py | 21 +- .../templates/instances/_decryptpassword.html | 2 +- .../templates/instances/_detail_console.html | 4 +- .../templates/instances/_detail_log.html | 4 +- .../templates/instances/_detail_overview.html | 14 +- .../templates/instances/_rebuild.html | 2 +- .../instances/templates/instances/detail.html | 4 +- .../dashboards/project/instances/tests.py | 9 +- .../project/loadbalancers/tables.py | 18 +- .../loadbalancers/_member_details.html | 2 +- .../loadbalancers/_monitor_details.html | 2 +- .../loadbalancers/_pool_details.html | 2 +- .../loadbalancers/_updatemember.html | 4 +- .../loadbalancers/_updatemonitor.html | 2 +- .../templates/loadbalancers/_updatepool.html | 2 +- .../templates/loadbalancers/_updatevip.html | 2 +- .../templates/loadbalancers/_vip_details.html | 2 +- .../templates/loadbalancers/details_tabs.html | 4 +- .../network_topology/_create_router.html | 2 +- .../network_topology/_post_massage.html | 4 +- .../client_side/_balloon_container.html | 4 +- .../client_side/_balloon_port.html | 2 +- .../templates/network_topology/index.html | 8 +- .../project/networks/ports/tables.py | 3 +- .../project/networks/subnets/tables.py | 6 +- .../dashboards/project/networks/tables.py | 9 +- .../networks/templates/networks/_create.html | 2 +- .../networks/templates/networks/_update.html | 2 +- .../networks/ports/_detail_overview.html | 2 +- .../templates/networks/ports/_update.html | 2 +- .../templates/networks/ports/detail.html | 4 +- .../networks/subnets/_detail_overview.html | 2 +- .../templates/networks/subnets/detail.html | 4 +- .../dashboards/project/overview/tests.py | 8 +- .../routers/extensions/routerrules/tables.py | 3 +- .../project/routers/ports/tables.py | 3 +- .../dashboards/project/routers/tables.py | 6 +- .../routers/templates/routers/_create.html | 2 +- .../routers/templates/routers/detail.html | 4 +- .../extensions/routerrules/_create.html | 2 +- .../routers/extensions/routerrules/grid.html | 10 +- .../templates/routers/ports/_create.html | 2 +- .../templates/routers/ports/_setgateway.html | 2 +- .../dashboards/project/stacks/tables.py | 9 +- .../templates/stacks/_change_template.html | 2 +- .../stacks/templates/stacks/_create.html | 2 +- .../templates/stacks/_detail_overview.html | 10 +- .../templates/stacks/_resource_overview.html | 6 +- .../templates/stacks/_select_template.html | 2 +- .../stacks/templates/stacks/_update.html | 2 +- .../stacks/templates/stacks/detail.html | 4 +- .../stacks/templates/stacks/resource.html | 4 +- .../project/volumes/snapshots/tables.py | 6 +- .../volumes/templates/volumes/index.html | 4 +- .../volumes/snapshots/_detail_overview.html | 4 +- .../templates/volumes/snapshots/_update.html | 2 +- .../templates/volumes/snapshots/detail.html | 4 +- .../templates/volumes/volumes/_attach.html | 2 +- .../templates/volumes/volumes/_create.html | 2 +- .../volumes/volumes/_create_snapshot.html | 2 +- .../volumes/volumes/_detail_overview.html | 10 +- .../templates/volumes/volumes/_extend.html | 2 +- .../templates/volumes/volumes/_update.html | 2 +- .../templates/volumes/volumes/detail.html | 4 +- .../project/volumes/volumes/tables.py | 15 +- .../project/volumes/volumes/tests.py | 3 +- .../vpn/templates/vpn/_ikepolicy_details.html | 2 +- .../templates/vpn/_ipsecpolicy_details.html | 2 +- .../vpn/_ipsecsiteconnection_details.html | 2 +- .../vpn/templates/vpn/_update_ikepolicy.html | 4 +- .../templates/vpn/_update_ipsecpolicy.html | 4 +- .../vpn/_update_ipsecsiteconnection.html | 4 +- .../vpn/templates/vpn/_update_vpnservice.html | 4 +- .../templates/vpn/_vpnservice_details.html | 2 +- .../vpn/templates/vpn/details_tabs.html | 4 +- .../project/vpn/templates/vpn/index.html | 4 +- .../dashboards/router/nexus1000v/tables.py | 6 +- .../nexus1000v/_create_network_profile.html | 2 +- .../nexus1000v/_update_network_profile.html | 2 +- .../templates/nexus1000v/index.html | 4 +- .../password/templates/password/_change.html | 2 +- .../user/templates/user/_settings.html | 2 +- .../glyphicons-halflings-regular.eot | Bin 0 -> 20335 bytes .../glyphicons-halflings-regular.svg | 229 ++ .../glyphicons-halflings-regular.ttf | Bin 0 -> 41280 bytes .../glyphicons-halflings-regular.woff | Bin 0 -> 23320 bytes .../img/glyphicons-halflings-white.png | Bin 4352 -> 0 bytes .../bootstrap/img/glyphicons-halflings.png | Bin 4352 -> 0 bytes .../bootstrap/scss/_bootstrap-mincer.scss | 17 + .../bootstrap/scss/_bootstrap-responsive.scss | 318 -- .../static/bootstrap/scss/_bootstrap.scss | 63 - .../static/bootstrap/scss/bootstrap.scss | 50 + .../bootstrap/scss/bootstrap/_accordion.scss | 28 - .../bootstrap/scss/bootstrap/_alerts.scss | 101 +- .../bootstrap/scss/bootstrap/_badges.scss | 57 + .../scss/bootstrap/_breadcrumbs.scss | 38 +- .../scss/bootstrap/_button-groups.scss | 282 +- .../bootstrap/scss/bootstrap/_buttons.scss | 246 +- .../bootstrap/scss/bootstrap/_carousel.scss | 243 +- .../bootstrap/scss/bootstrap/_close.scss | 39 +- .../bootstrap/scss/bootstrap/_code.scss | 68 +- .../scss/bootstrap/_component-animations.scss | 33 +- .../bootstrap/scss/bootstrap/_dropdowns.scss | 262 +- .../bootstrap/scss/bootstrap/_forms.scss | 775 ++--- .../bootstrap/scss/bootstrap/_glyphicons.scss | 237 ++ .../bootstrap/scss/bootstrap/_grid.scss | 88 +- .../bootstrap/scss/bootstrap/_hero-unit.scss | 20 - .../scss/bootstrap/_input-groups.scss | 162 + .../bootstrap/scss/bootstrap/_jumbotron.scss | 48 + .../bootstrap/scss/bootstrap/_labels.scss | 76 +- .../bootstrap/scss/bootstrap/_layouts.scss | 17 - .../bootstrap/scss/bootstrap/_list-group.scss | 129 + .../bootstrap/scss/bootstrap/_media.scss | 56 + .../bootstrap/scss/bootstrap/_mixins.scss | 559 +--- .../bootstrap/scss/bootstrap/_modals.scss | 180 +- .../bootstrap/scss/bootstrap/_navbar.scss | 856 +++-- .../bootstrap/scss/bootstrap/_navs.scss | 507 ++- .../bootstrap/scss/bootstrap/_normalize.scss | 425 +++ .../bootstrap/scss/bootstrap/_pager.scss | 73 +- .../bootstrap/scss/bootstrap/_pagination.scss | 131 +- .../bootstrap/scss/bootstrap/_panels.scss | 240 ++ .../bootstrap/scss/bootstrap/_popovers.scss | 154 +- .../bootstrap/scss/bootstrap/_print.scss | 101 + .../scss/bootstrap/_progress-bars.scss | 112 +- .../bootstrap/scss/bootstrap/_reset.scss | 105 - .../scss/bootstrap/_responsive-embed.scss | 34 + .../scss/bootstrap/_responsive-utilities.scss | 173 + .../scss/bootstrap/_scaffolding.scss | 155 +- .../bootstrap/scss/bootstrap/_sprites.scss | 157 - .../bootstrap/scss/bootstrap/_tables.scss | 285 +- .../bootstrap/scss/bootstrap/_theme.scss | 247 ++ .../bootstrap/scss/bootstrap/_thumbnails.scss | 61 +- .../bootstrap/scss/bootstrap/_tooltip.scss | 96 +- .../bootstrap/scss/bootstrap/_type.scss | 379 ++- .../bootstrap/scss/bootstrap/_utilities.scss | 53 +- .../bootstrap/scss/bootstrap/_variables.scss | 928 +++++- .../bootstrap/scss/bootstrap/_wells.scss | 26 +- .../bootstrap/scss/bootstrap/bootstrap.scss | 50 + .../scss/bootstrap/mixins/_alerts.scss | 14 + .../bootstrap/mixins/_background-variant.scss | 11 + .../scss/bootstrap/mixins/_border-radius.scss | 18 + .../scss/bootstrap/mixins/_buttons.scss | 50 + .../scss/bootstrap/mixins/_center-block.scss | 7 + .../scss/bootstrap/mixins/_clearfix.scss | 22 + .../scss/bootstrap/mixins/_forms.scss | 84 + .../scss/bootstrap/mixins/_gradients.scss | 58 + .../bootstrap/mixins/_grid-framework.scss | 87 + .../scss/bootstrap/mixins/_grid.scss | 122 + .../scss/bootstrap/mixins/_hide-text.scss | 21 + .../scss/bootstrap/mixins/_image.scss | 33 + .../scss/bootstrap/mixins/_labels.scss | 12 + .../scss/bootstrap/mixins/_list-group.scss | 31 + .../scss/bootstrap/mixins/_nav-divider.scss | 10 + .../bootstrap/mixins/_nav-vertical-align.scss | 9 + .../scss/bootstrap/mixins/_opacity.scss | 8 + .../scss/bootstrap/mixins/_pagination.scss | 23 + .../scss/bootstrap/mixins/_panels.scss | 20 + .../scss/bootstrap/mixins/_progress-bar.scss | 8 + .../scss/bootstrap/mixins/_reset-filter.scss | 8 + .../scss/bootstrap/mixins/_resize.scss | 6 + .../mixins/_responsive-visibility.scss | 21 + .../scss/bootstrap/mixins/_size.scss | 10 + .../scss/bootstrap/mixins/_tab-focus.scss | 9 + .../scss/bootstrap/mixins/_table-row.scss | 28 + .../scss/bootstrap/mixins/_text-emphasis.scss | 11 + .../scss/bootstrap/mixins/_text-overflow.scss | 8 + .../bootstrap/mixins/_vendor-prefixes.scss | 224 ++ .../static/dashboard/scss/_accordion_nav.scss | 9 +- .../static/dashboard/scss/horizon.scss | 242 +- .../dashboard/scss/horizon_workflow.scss | 2 +- openstack_dashboard/templates/_header.html | 4 +- .../templates/plugin_panel/index.html | 4 +- openstack_dashboard/usage/tables.py | 2 +- 290 files changed, 9965 insertions(+), 5464 deletions(-) create mode 100644 horizon/templates/horizon/common/_bootstrap_form_field.html create mode 100644 horizon/templatetags/bootstrap_form_field.py create mode 100644 openstack_dashboard/static/bootstrap/fonts/bootstrap/glyphicons-halflings-regular.eot create mode 100644 openstack_dashboard/static/bootstrap/fonts/bootstrap/glyphicons-halflings-regular.svg create mode 100644 openstack_dashboard/static/bootstrap/fonts/bootstrap/glyphicons-halflings-regular.ttf create mode 100644 openstack_dashboard/static/bootstrap/fonts/bootstrap/glyphicons-halflings-regular.woff delete mode 100644 openstack_dashboard/static/bootstrap/img/glyphicons-halflings-white.png delete mode 100644 openstack_dashboard/static/bootstrap/img/glyphicons-halflings.png create mode 100644 openstack_dashboard/static/bootstrap/scss/_bootstrap-mincer.scss delete mode 100644 openstack_dashboard/static/bootstrap/scss/_bootstrap-responsive.scss delete mode 100644 openstack_dashboard/static/bootstrap/scss/_bootstrap.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap.scss delete mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_accordion.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_badges.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_glyphicons.scss delete mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_hero-unit.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_input-groups.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_jumbotron.scss delete mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_layouts.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_list-group.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_media.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_normalize.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_panels.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_print.scss delete mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_reset.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_responsive-embed.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_responsive-utilities.scss delete mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_sprites.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/_theme.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/bootstrap.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_alerts.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_background-variant.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_border-radius.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_buttons.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_center-block.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_clearfix.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_forms.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_gradients.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_grid-framework.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_grid.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_hide-text.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_image.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_labels.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_list-group.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_nav-divider.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_nav-vertical-align.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_opacity.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_pagination.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_panels.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_progress-bar.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_reset-filter.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_resize.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_responsive-visibility.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_size.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_tab-focus.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_table-row.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_text-emphasis.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_text-overflow.scss create mode 100644 openstack_dashboard/static/bootstrap/scss/bootstrap/mixins/_vendor-prefixes.scss diff --git a/doc/source/topics/customizing.rst b/doc/source/topics/customizing.rst index 0a2ab7cb02..dbf39e9a07 100644 --- a/doc/source/topics/customizing.rst +++ b/doc/source/topics/customizing.rst @@ -15,7 +15,7 @@ The file ``local_settings.py`` can be found at the Horizon directory path of Changing the Logo ================= -There are currently two places where the OpenStack logo is pulled in +There are currently two places where the OpenStack logo is pulled in through ``horizon.less``. The first is shown at the login screen and the other on top of the menu bar:: @@ -52,7 +52,7 @@ This allows for common site-customization requirements such as: To specify the python module containing your modifications, add the key ``customization_module`` to your ``HORIZON_CONFIG`` dictionary in -``local_settings.py``. The value should be a string containing the path to your +``local_settings.py``. The value should be a string containing the path to your module in dotted python path notation. Example:: HORIZON_CONFIG = { @@ -148,41 +148,16 @@ similar way, add the new column definition and then use the ``Meta`` Button Icons ============ -Horizon provides hooks for customizing the look and feel of each class of -button on the site. The following classes are used to identify each type of -button: +Horizon uses font icons (glyphicons) from Twitter Bootstrap to add icons to buttons. +Please see http://bootstrapdocs.com/v3.1.1/docs/components/#glyphicons for instructions +how to use icons in the code. -* Generic Classes - * btn-search - * btn-delete - * btn-upload - * btn-download - * btn-create - * btn-edit - * btn-list - * btn-copy - * btn-camera - * btn-stats - * btn-enable - * btn-disable +To add icon to Table Action, use icon property. Example: -* Floating IP-specific Classes - * btn-allocate - * btn-release - * btn-associate - * btn-disassociate - -* Instance-specific Classes - * btn-launch - * btn-terminate - * btn-reboot - * btn-pause - * btn-suspend - * btn-console - * btn-log - -* Volume-specific classes - * btn-detach + class CreateSnapshot(tables.LinkAction): + name = "snapshot" + verbose_name = _("Create Snapshot") + icon = "camera" Additionally, the site-wide default button classes can be configured by setting ``ACTION_CSS_CLASSES`` to a tuple of the classes you wish to appear diff --git a/doc/source/topics/tutorial.rst b/doc/source/topics/tutorial.rst index a466795471..5abe02aad2 100644 --- a/doc/source/topics/tutorial.rst +++ b/doc/source/topics/tutorial.rst @@ -411,8 +411,8 @@ dashboards:: {% endblock page_header %} {% block main %} -
-
+
+
{{ tab_group.render }}
diff --git a/horizon/static/bootstrap/js/bootstrap.js b/horizon/static/bootstrap/js/bootstrap.js index 4412304ebf..8ae571b6da 100644 --- a/horizon/static/bootstrap/js/bootstrap.js +++ b/horizon/static/bootstrap/js/bootstrap.js @@ -1,132 +1,126 @@ -/* =================================================== - * bootstrap-transition.js v2.0.1 - * http://twitter.github.com/bootstrap/javascript.html#transitions - * =================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ +/*! + * Bootstrap v3.1.1 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ -!function( $ ) { +if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery') } - $(function () { - - "use strict" - - /* CSS TRANSITION SUPPORT (https://gist.github.com/373874) - * ======================================================= */ - - $.support.transition = (function () { - var thisBody = document.body || document.documentElement - , thisStyle = thisBody.style - , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined - - return support && { - end: (function () { - var transitionEnd = "TransitionEnd" - if ( $.browser.webkit ) { - transitionEnd = "webkitTransitionEnd" - } else if ( $.browser.mozilla ) { - transitionEnd = "transitionend" - } else if ( $.browser.opera ) { - transitionEnd = "oTransitionEnd" - } - return transitionEnd - }()) - } - })() - - }) - -}( window.jQuery );/* ========================================================== - * bootstrap-alert.js v2.0.1 - * http://twitter.github.com/bootstrap/javascript.html#alerts - * ========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ +/* ======================================================================== + * Bootstrap: transition.js v3.1.1 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ -!function( $ ){ ++function ($) { + 'use strict'; - "use strict" + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ - /* ALERT CLASS DEFINITION - * ====================== */ + function transitionEnd() { + var el = document.createElement('bootstrap') - var dismiss = '[data-dismiss="alert"]' - , Alert = function ( el ) { - $(el).on('click', dismiss, this.close) - } - - Alert.prototype = { - - constructor: Alert - - , close: function ( e ) { - var $this = $(this) - , selector = $this.attr('data-target') - , $parent - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 - } - - $parent = $(selector) - $parent.trigger('close') - - e && e.preventDefault() - - $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) - - $parent - .trigger('close') - .removeClass('in') - - function removeElement() { - $parent - .trigger('closed') - .remove() - } - - $.support.transition && $parent.hasClass('fade') ? - $parent.on($.support.transition.end, removeElement) : - removeElement() + var transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd', + 'MozTransition' : 'transitionend', + 'OTransition' : 'oTransitionEnd otransitionend', + 'transition' : 'transitionend' } + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + + return false // explicit for ie8 ( ._.) + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false, $el = this + $(this).one($.support.transition.end, function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.1.1 + * http://getbootstrap.com/javascript/#alerts + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('alert') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent.trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(150) : + removeElement() } - /* ALERT PLUGIN DEFINITION - * ======================= */ + // ALERT PLUGIN DEFINITION + // ======================= - $.fn.alert = function ( option ) { + var old = $.fn.alert + + $.fn.alert = function (option) { return this.each(function () { var $this = $(this) - , data = $this.data('alert') - if (!data) $this.data('alert', (data = new Alert(this))) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) if (typeof option == 'string') data[option].call($this) }) } @@ -134,479 +128,628 @@ $.fn.alert.Constructor = Alert - /* ALERT DATA-API - * ============== */ - - $(function () { - $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) - }) - -}( window.jQuery );/* ============================================================ - * bootstrap-button.js v2.0.1 - * http://twitter.github.com/bootstrap/javascript.html#buttons - * ============================================================ - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============================================================ */ - -!function( $ ){ - - "use strict" - - /* BUTTON PUBLIC CLASS DEFINITION - * ============================== */ - - var Button = function ( element, options ) { - this.$element = $(element) - this.options = $.extend({}, $.fn.button.defaults, options) - } - - Button.prototype = { - - constructor: Button - - , setState: function ( state ) { - var d = 'disabled' - , $el = this.$element - , data = $el.data() - , val = $el.is('input') ? 'val' : 'html' - - state = state + 'Text' - data.resetText || $el.data('resetText', $el[val]()) - - $el[val](data[state] || this.options[state]) - - // push to event loop to allow forms to submit - setTimeout(function () { - state == 'loadingText' ? - $el.addClass(d).attr(d, d) : - $el.removeClass(d).removeAttr(d) - }, 0) - } - - , toggle: function () { - var $parent = this.$element.parent('[data-toggle="buttons-radio"]') - - $parent && $parent - .find('.active') - .removeClass('active') - - this.$element.toggleClass('active') - } + // ALERT NO CONFLICT + // ================= + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this } - /* BUTTON PLUGIN DEFINITION - * ======================== */ + // ALERT DATA-API + // ============== - $.fn.button = function ( option ) { + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.1.1 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (!data.resetText) $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && this.$element.hasClass('active')) changed = false + else $parent.find('.active').removeClass('active') + } + if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } + + if (changed) this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + var old = $.fn.button + + $.fn.button = function (option) { return this.each(function () { - var $this = $(this) - , data = $this.data('button') - , options = typeof option == 'object' && option - if (!data) $this.data('button', (data = new Button(this, options))) + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() else if (option) data.setState(option) }) } - $.fn.button.defaults = { - loadingText: 'loading...' - } - $.fn.button.Constructor = Button - /* BUTTON DATA-API - * =============== */ + // BUTTON NO CONFLICT + // ================== - $(function () { - $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') - $btn.button('toggle') - }) - }) - -}( window.jQuery );/* ========================================================== - * bootstrap-carousel.js v2.0.1 - * http://twitter.github.com/bootstrap/javascript.html#carousel - * ========================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function( $ ){ - - "use strict" - - /* CAROUSEL CLASS DEFINITION - * ========================= */ - - var Carousel = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, $.fn.carousel.defaults, options) - this.options.slide && this.slide(this.options.slide) + $.fn.button.noConflict = function () { + $.fn.button = old + return this } - Carousel.prototype = { - cycle: function () { - this.interval = setInterval($.proxy(this.next, this), this.options.interval) - return this + // BUTTON DATA-API + // =============== + + $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + e.preventDefault() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.1.1 + * http://getbootstrap.com/javascript/#carousel + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.DEFAULTS = { + interval: 5000, + pause: 'hover', + wrap: true + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getActiveIndex = function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + + return this.$items.index(this.$active) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getActiveIndex() + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition) { + this.$element.trigger($.support.transition.end) + this.cycle(true) } - , to: function (pos) { - var $active = this.$element.find('.active') - , children = $active.parent().children() - , activePos = children.index($active) - , that = this + this.interval = clearInterval(this.interval) - if (pos > (children.length - 1) || pos < 0) return + return this + } - if (this.sliding) { - return this.$element.one('slid', function () { - that.to(pos) - }) - } + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } - if (activePos == pos) { - return this.pause().cycle() - } + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } - return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || $active[type]() + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) return + $next = this.$element.find('.item')[fallback]() } - , pause: function () { - clearInterval(this.interval) - this.interval = null - return this + if ($next.hasClass('active')) return this.sliding = false + + var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + + this.sliding = true + + isCycling && this.pause() + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid.bs.carousel', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) } - , next: function () { - if (this.sliding) return - return this.slide('next') - } - - , prev: function () { - if (this.sliding) return - return this.slide('prev') - } - - , slide: function (type, next) { - var $active = this.$element.find('.active') - , $next = next || $active[type]() - , isCycling = this.interval - , direction = type == 'next' ? 'left' : 'right' - , fallback = type == 'next' ? 'first' : 'last' - , that = this - - if (!$next.length) return - - this.sliding = true - - isCycling && this.pause() - - $next = $next.length ? $next : this.$element.find('.item')[fallback]() - - if (!$.support.transition && this.$element.hasClass('slide')) { - this.$element.trigger('slide') - $active.removeClass('active') - $next.addClass('active') - this.sliding = false - this.$element.trigger('slid') - } else { - $next.addClass(type) - $next[0].offsetWidth // force reflow - $active.addClass(direction) - $next.addClass(direction) - this.$element.trigger('slide') - this.$element.one($.support.transition.end, function () { + if ($.support.transition && this.$element.hasClass('slide')) { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one($.support.transition.end, function () { $next.removeClass([type, direction].join(' ')).addClass('active') $active.removeClass(['active', direction].join(' ')) that.sliding = false - setTimeout(function () { that.$element.trigger('slid') }, 0) + setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) }) - } - - isCycling && this.cycle() - - return this + .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) + } else { + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid.bs.carousel') } + isCycling && this.cycle() + + return this } - /* CAROUSEL PLUGIN DEFINITION - * ========================== */ + // CAROUSEL PLUGIN DEFINITION + // ========================== - $.fn.carousel = function ( option ) { + var old = $.fn.carousel + + $.fn.carousel = function (option) { return this.each(function () { - var $this = $(this) - , data = $this.data('carousel') - , options = typeof option == 'object' && option - if (!data) $this.data('carousel', (data = new Carousel(this, options))) - if (typeof option == 'number') data.to(option) - else if (typeof option == 'string' || (option = options.slide)) data[option]() - else data.cycle() - }) - } + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide - $.fn.carousel.defaults = { - interval: 5000 + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) } $.fn.carousel.Constructor = Carousel - /* CAROUSEL DATA-API - * ================= */ + // CAROUSEL NO CONFLICT + // ==================== - $(function () { - $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { - var $this = $(this), href - , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 - , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) - $target.carousel(options) - e.preventDefault() + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + }) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + $carousel.carousel($carousel.data()) }) }) -}( window.jQuery );/* ============================================================= - * bootstrap-collapse.js v2.0.1 - * http://twitter.github.com/bootstrap/javascript.html#collapse - * ============================================================= - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============================================================ */ +}(jQuery); -!function( $ ){ +/* ======================================================================== + * Bootstrap: collapse.js v3.1.1 + * http://getbootstrap.com/javascript/#collapse + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ - "use strict" - var Collapse = function ( element, options ) { - this.$element = $(element) - this.options = $.extend({}, $.fn.collapse.defaults, options) ++function ($) { + 'use strict'; - if (this.options["parent"]) { - this.$parent = $(this.options["parent"]) - } + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ - this.options.toggle && this.toggle() + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.transitioning = null + + if (this.options.parent) this.$parent = $(this.options.parent) + if (this.options.toggle) this.toggle() } - Collapse.prototype = { - - constructor: Collapse - - , dimension: function () { - var hasWidth = this.$element.hasClass('width') - return hasWidth ? 'width' : 'height' - } - - , show: function () { - var dimension = this.dimension() - , scroll = $.camelCase(['scroll', dimension].join('-')) - , actives = this.$parent && this.$parent.find('.in') - , hasData - - if (actives && actives.length) { - hasData = actives.data('collapse') - actives.collapse('hide') - hasData || actives.data('collapse', null) - } - - this.$element[dimension](0) - this.transition('addClass', 'show', 'shown') - this.$element[dimension](this.$element[0][scroll]) - - } - - , hide: function () { - var dimension = this.dimension() - this.reset(this.$element[dimension]()) - this.transition('removeClass', 'hide', 'hidden') - this.$element[dimension](0) - } - - , reset: function ( size ) { - var dimension = this.dimension() - - this.$element - .removeClass('collapse') - [dimension](size || 'auto') - [0].offsetWidth - - this.$element.addClass('collapse') - } - - , transition: function ( method, startEvent, completeEvent ) { - var that = this - , complete = function () { - if (startEvent == 'show') that.reset() - that.$element.trigger(completeEvent) - } - - this.$element - .trigger(startEvent) - [method]('in') - - $.support.transition && this.$element.hasClass('collapse') ? - this.$element.one($.support.transition.end, complete) : - complete() - } - - , toggle: function () { - this[this.$element.hasClass('in') ? 'hide' : 'show']() - } - + Collapse.DEFAULTS = { + toggle: true } - /* COLLAPSIBLE PLUGIN DEFINITION - * ============================== */ + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } - $.fn.collapse = function ( option ) { + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var actives = this.$parent && this.$parent.find('> .panel > .in') + + if (actives && actives.length) { + var hasData = actives.data('bs.collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing') + [dimension](0) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('collapse in') + [dimension]('auto') + this.transitioning = 0 + this.$element.trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + [dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element + [dimension](this.$element[dimension]()) + [0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse') + .removeClass('in') + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .trigger('hidden.bs.collapse') + .removeClass('collapsing') + .addClass('collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + var old = $.fn.collapse + + $.fn.collapse = function (option) { return this.each(function () { - var $this = $(this) - , data = $this.data('collapse') - , options = typeof option == 'object' && option - if (!data) $this.data('collapse', (data = new Collapse(this, options))) + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data && options.toggle && option == 'show') option = !option + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) if (typeof option == 'string') data[option]() }) } - $.fn.collapse.defaults = { - toggle: true - } - $.fn.collapse.Constructor = Collapse - /* COLLAPSIBLE DATA-API - * ==================== */ + // COLLAPSE NO CONFLICT + // ==================== - $(function () { - $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { - var $this = $(this), href - , target = $this.attr('data-target') - || e.preventDefault() - || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 - , option = $(target).data('collapse') ? 'toggle' : $this.data() - $(target).collapse(option) - }) - }) - -}( window.jQuery );/* ============================================================ - * bootstrap-dropdown.js v2.0.1 - * http://twitter.github.com/bootstrap/javascript.html#dropdowns - * ============================================================ - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============================================================ */ + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } -!function( $ ){ + // COLLAPSE DATA-API + // ================= - "use strict" + $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + var $target = $(target) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + var parent = $this.attr('data-parent') + var $parent = parent && $(parent) - /* DROPDOWN CLASS DEFINITION - * ========================= */ - - var toggle = '[data-toggle="dropdown"]' - , Dropdown = function ( element ) { - var $el = $(element).on('click.dropdown.data-api', this.toggle) - $('html').on('click.dropdown.data-api', function () { - $el.parent().removeClass('open') - }) - } - - Dropdown.prototype = { - - constructor: Dropdown - - , toggle: function ( e ) { - var $this = $(this) - , selector = $this.attr('data-target') - , $parent - , isActive - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 - } - - $parent = $(selector) - $parent.length || ($parent = $this.parent()) - - isActive = $parent.hasClass('open') - - clearMenus() - !isActive && $parent.toggleClass('open') - - return false + if (!data || !data.transitioning) { + if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') + $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') } + $target.collapse(option) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.1.1 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle=dropdown]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) } - function clearMenus() { - $(toggle).parent().removeClass('open') + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $('