diff --git a/doc/source/contributor/tutorials/plugin.rst b/doc/source/contributor/tutorials/plugin.rst old mode 100644 new mode 100755 index dd77b4e303..1e740e1917 --- a/doc/source/contributor/tutorials/plugin.rst +++ b/doc/source/contributor/tutorials/plugin.rst @@ -149,6 +149,9 @@ _31000_myplugin.py:: # A list of scss files to be included in the compressed set of files ADD_SCSS_FILES = ['dashboard/identity/myplugin/mypanel/mypanel.scss'] + # A list of template-based views to be added to the header + ADD_HEADER_SECTIONS = ['myplugin.content.mypanel.views.HeaderView',] + .. Note :: Currently, AUTO_DISCOVER_STATIC_FILES = True will only discover JavaScript files, diff --git a/horizon/static/horizon/js/horizon.extensible_header.js b/horizon/static/horizon/js/horizon.extensible_header.js new file mode 100755 index 0000000000..bdbec77210 --- /dev/null +++ b/horizon/static/horizon/js/horizon.extensible_header.js @@ -0,0 +1,65 @@ +/** + * 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. + */ + +/* Core functionality related to extensible header sections. */ +horizon.extensible_header = { + populate: function() { + var $path = $(location).attr('pathname'); + var $url = $(location).attr('href'); + $url = $url.replace($path, $(window).attr('WEBROOT') + 'header/'); + + horizon.ajax.queue({ + url: $url, + success: function(data) { + $('#extensible-header').replaceWith($(data)); + + selected = horizon.cookies.get('selected_header'); + if(selected && $('#header-list #' + selected).length){ + $old_primary = $('#primary-extensible-header > a'); + $new_primary = $('#header-list #' + selected); + + $old_primary.insertAfter($new_primary); + $new_primary.first().appendTo($('#primary-extensible-header')); + } + + function swap() { + $old_primary = $('#primary-extensible-header > a'); + $new_primary = $(this); + + horizon.cookies.put("selected_header", $new_primary.attr('id'), {path:'/'}); + $old_primary.insertAfter($new_primary); + $new_primary.appendTo($('#primary-extensible-header')); + $new_primary.off('click', swap); + $old_primary.on('click', swap); + } + $('#header-list .extensible-header-section').on('click', swap); + }, + error: function(jqXHR) { + if (jqXHR.status !== 401 && jqXHR.status !== 403) { + // error is raised with status of 0 when ajax query is cancelled + // due to new page request + if (jqXHR.status !== 0) { + horizon.alert("info", gettext("Failed to populate extensible header.")); + } + } + } + }); + return true; + } +}; + +horizon.addInitFunction(function() { + // trigger extensible header section query on page load + horizon.extensible_header.populate(); +}); diff --git a/openstack_dashboard/static/dashboard/scss/components/_navbar.scss b/openstack_dashboard/static/dashboard/scss/components/_navbar.scss old mode 100644 new mode 100755 index 6a6ecf7c12..a8825e4d5a --- a/openstack_dashboard/static/dashboard/scss/components/_navbar.scss +++ b/openstack_dashboard/static/dashboard/scss/components/_navbar.scss @@ -23,6 +23,11 @@ margin-bottom: 1px; } + .navbar-nav .header-overflow ul li{ + white-space: nowrap; + padding: $bs-dropdown-item-padding-vertical $bs-dropdown-item-padding-horizontal; + } + .dropdown-toggle > .fa { padding-left: $padding-small-vertical; padding-right: $padding-small-vertical; diff --git a/openstack_dashboard/templates/header/_header.html b/openstack_dashboard/templates/header/_header.html old mode 100644 new mode 100755 index c1aa83357b..81bb54dd46 --- a/openstack_dashboard/templates/header/_header.html +++ b/openstack_dashboard/templates/header/_header.html @@ -29,6 +29,7 @@