Feature #21808 » 0001-make-the-sidebar-collapsible-with-per-page-state.patch
| app/views/layouts/base.html.erb | ||
|---|---|---|
| 98 | 98 |
<% end %> |
| 99 | 99 |
</div> |
| 100 | 100 | |
| 101 |
<div id="main" class="<%= sidebar_content? ? '' : 'nosidebar' %>"> |
|
| 101 |
<div id="main" class="<%= sidebar_content? ? 'collapsiblesidebar' : 'nosidebar' %>"> |
|
| 102 |
<%= javascript_tag "$('#main.collapsiblesidebar').collapsibleSidebar();" if sidebar_content? %>
|
|
| 102 | 103 |
<div id="sidebar"> |
| 103 | 104 |
<%= yield :sidebar %> |
| 104 | 105 |
<%= view_layouts_base_sidebar_hook_response %> |
| 105 | 106 |
</div> |
| 106 | 107 | |
| 107 | 108 |
<div id="content"> |
| 109 |
<% if sidebar_content? %> |
|
| 110 |
<div id="sidebar-switch-panel" style="visibility: hidden;"> |
|
| 111 |
<a id="sidebar-switch-button" href="#">»</a> |
|
| 112 |
</div> |
|
| 113 |
<%= javascript_tag "$('#sidebar-switch-panel').css('visibility', 'visible');" %>
|
|
| 114 |
<% end %> |
|
| 108 | 115 |
<%= render_flash_messages %> |
| 109 | 116 |
<%= yield %> |
| 110 | 117 |
<%= call_hook :view_layouts_base_content %> |
| public/javascripts/application.js | ||
|---|---|---|
| 781 | 781 |
return true; |
| 782 | 782 |
} |
| 783 | 783 | |
| 784 |
// collapsible sidebar jQuery plugin |
|
| 785 |
(function($) {
|
|
| 786 | ||
| 787 |
// main container this is applied to |
|
| 788 |
var main; |
|
| 789 | ||
| 790 |
// triggers show/hide |
|
| 791 |
var button; |
|
| 792 | ||
| 793 |
// the key to use in local storage |
|
| 794 |
// this will later be expanded using the current controller and action to |
|
| 795 |
// allow for different sidebar states for different pages |
|
| 796 |
var localStorageKey = 'redmine-sidebar-state'; |
|
| 797 | ||
| 798 |
// true if local storage is available |
|
| 799 |
var canUseLocalStorage = function(){
|
|
| 800 |
try {
|
|
| 801 |
if('localStorage' in window){
|
|
| 802 |
localStorage.setItem('redmine.test.storage', 'ok');
|
|
| 803 |
var item = localStorage.getItem('redmine.test.storage');
|
|
| 804 |
localStorage.removeItem('redmine.test.storage');
|
|
| 805 |
if(item === 'ok') return true; |
|
| 806 |
} |
|
| 807 |
} catch (err) {}
|
|
| 808 |
return false; |
|
| 809 |
}(); |
|
| 810 | ||
| 811 |
// function to set current sidebar state |
|
| 812 |
var setState = function(state){
|
|
| 813 |
if(canUseLocalStorage){
|
|
| 814 |
localStorage.setItem(localStorageKey, state); |
|
| 815 |
} |
|
| 816 |
}; |
|
| 817 | ||
| 818 |
var applyState = function(){
|
|
| 819 |
if(main.hasClass('nosidebar')){
|
|
| 820 |
button.html("«");
|
|
| 821 |
setState('hidden');
|
|
| 822 |
} else {
|
|
| 823 |
button.html("»");
|
|
| 824 |
setState('visible');
|
|
| 825 |
} |
|
| 826 |
}; |
|
| 827 | ||
| 828 |
var setupToggleButton = function(){
|
|
| 829 |
button = $('#sidebar-switch-button');
|
|
| 830 |
button.click(function(e){
|
|
| 831 |
main.addClass("animate");
|
|
| 832 |
main.toggleClass('nosidebar');
|
|
| 833 |
applyState(); |
|
| 834 |
e.preventDefault(); |
|
| 835 |
return false; |
|
| 836 |
}); |
|
| 837 | ||
| 838 |
applyState(); |
|
| 839 |
}; |
|
| 840 | ||
| 841 |
$.fn.collapsibleSidebar = function() {
|
|
| 842 |
main = this; |
|
| 843 |
// determine previously stored sidebar state for this page |
|
| 844 |
if(canUseLocalStorage) {
|
|
| 845 |
// determine current controller/action pair and use them as storage key |
|
| 846 |
var bodyClass = $('body').attr('class');
|
|
| 847 |
if(bodyClass){
|
|
| 848 |
try {
|
|
| 849 |
localStorageKey += '-' + bodyClass.split(/\s+/).filter(function(s){
|
|
| 850 |
return s.match(/(action|controller)-.*/); |
|
| 851 |
}).sort().join('-');
|
|
| 852 |
} catch(e) {
|
|
| 853 |
// in case of error (probably IE8), continue with the unmodified key |
|
| 854 |
} |
|
| 855 |
} |
|
| 856 |
var storedState = localStorage.getItem(localStorageKey); |
|
| 857 |
main.toggleClass('nosidebar', storedState === 'hidden');
|
|
| 858 |
} |
|
| 859 | ||
| 860 |
// draw the toggle button once the DOM is complete |
|
| 861 |
$(document).ready(setupToggleButton); |
|
| 862 |
}; |
|
| 863 |
}(jQuery)); |
|
| 864 | ||
| 784 | 865 |
$(document).ready(setupAjaxIndicator); |
| 785 | 866 |
$(document).ready(hideOnLoad); |
| 786 | 867 |
$(document).ready(addFormObserversForDoubleSubmit); |
| public/stylesheets/application.css | ||
|---|---|---|
| 95 | 95 | |
| 96 | 96 |
#main {background-color:#EEEEEE;}
|
| 97 | 97 | |
| 98 |
#sidebar{ float: right; width: 22%; position: relative; z-index: 9; padding: 0; margin: 0;}
|
|
| 99 |
* html #sidebar{ width: 22%; }
|
|
| 98 |
#sidebar{ float: right; width: 23.5%; position: relative; z-index: 9; padding: 0; margin: 0;}
|
|
| 99 |
* html #sidebar{ width: 23.5%; }
|
|
| 100 | 100 |
#sidebar h3{ font-size: 14px; margin-top:14px; color: #666; }
|
| 101 | 101 |
#sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }
|
| 102 | 102 |
* html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }
|
| ... | ... | |
| 106 | 106 |
#sidebar div.wiki ul {margin:inherit; padding-left:40px;}
|
| 107 | 107 |
#sidebar div.wiki ul li {list-style-type:inherit;}
|
| 108 | 108 | |
| 109 |
#content { width: 75%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
|
|
| 110 |
* html #content{ width: 75%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
|
|
| 109 |
#content { background-color: #fff; margin: 0 25% 0 0; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }
|
|
| 110 |
* html #content{ margin-right: 25%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}
|
|
| 111 | 111 |
html>body #content { min-height: 600px; }
|
| 112 | 112 |
* html body #content { height: 600px; } /* IE */
|
| 113 | 113 | |
| 114 |
#main.nosidebar #sidebar{ display: none; }
|
|
| 115 |
#main.nosidebar #content{ width: auto; border-right: 0; }
|
|
| 114 |
#main.nosidebar #sidebar { display: block; margin-right: -25%; }
|
|
| 115 |
#main.nosidebar #content{ border-right: 0; margin-right: 0; }
|
|
| 116 |
#main.animate { transition: background-position 0.2s ease-in-out; }
|
|
| 117 |
#main.animate #sidebar, #main.animate #content { transition: margin 0.2s ease-in-out; }
|
|
| 118 | ||
| 119 |
#sidebar-switch-panel {
|
|
| 120 |
background-color: #EEEEEE; |
|
| 121 |
border-bottom: 1px solid #DDDDDD; |
|
| 122 |
border-left: 1px solid #DDDDDD; |
|
| 123 |
border-top: 1px solid #DDDDDD; |
|
| 124 |
float: right; |
|
| 125 |
left: 10px; |
|
| 126 |
top: 2px; |
|
| 127 |
position: relative; |
|
| 128 |
padding: 2px; |
|
| 129 |
margin-left: 5px; |
|
| 130 |
} |
|
| 116 | 131 | |
| 117 | 132 |
#footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}
|
| 118 | 133 | |