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 | 102 |
<div id="sidebar"> |
103 | 103 |
<%= yield :sidebar %> |
104 | 104 |
<%= view_layouts_base_sidebar_hook_response %> |
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 |
$.fn.collapsibleSidebar = function() { |
|
829 |
main = this; |
|
830 | ||
831 |
// create the toggle button |
|
832 |
var panel = $('<div id="sidebar-switch-panel"></div>'); |
|
833 |
button = $('<a id="sidebar-switch-button" href="#"></a>'); |
|
834 |
button.click(function(e){ |
|
835 |
main.addClass("animate"); |
|
836 |
main.toggleClass('nosidebar'); |
|
837 |
applyState(); |
|
838 |
e.preventDefault(); |
|
839 |
return false; |
|
840 |
}); |
|
841 |
panel.append(button); |
|
842 |
main.find('#content').prepend(panel); |
|
843 | ||
844 |
// determine previously stored sidebar state for this page |
|
845 |
if(canUseLocalStorage) { |
|
846 |
// determine current controller/action pair and use them as storage key |
|
847 |
var bodyClass = $('body').attr('class'); |
|
848 |
if(bodyClass){ |
|
849 |
localStorageKey += '-' + bodyClass.split(/\s+/).filter(function(s){ |
|
850 |
return s.match(/(action|controller)-.*/); |
|
851 |
}).sort().join('-'); |
|
852 |
} |
|
853 |
var storedState = localStorage.getItem(localStorageKey); |
|
854 |
main.toggleClass('nosidebar', storedState === 'hidden'); |
|
855 |
} |
|
856 | ||
857 |
applyState(); |
|
858 |
}; |
|
859 |
}(jQuery)); |
|
860 | ||
784 | 861 |
$(document).ready(setupAjaxIndicator); |
785 | 862 |
$(document).ready(hideOnLoad); |
786 | 863 |
$(document).ready(addFormObserversForDoubleSubmit); |
787 | 864 |
$(document).ready(defaultFocus); |
788 | 865 |
$(document).ready(setupTabs); |
866 | ||
867 |
$(document).ready(function(){ |
|
868 |
$('#main.collapsiblesidebar').collapsibleSidebar(); |
|
869 |
}); |
|
870 |
public/stylesheets/application.css | ||
---|---|---|
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 |
} |
|
116 | 130 | |
117 | 131 |
#footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;} |
118 | 132 |