Project

General

Profile

Patch #21808 » 0001-make-the-sidebar-collapsible-with-per-page-state.patch

local storage based solution with per page sidebar state - Jens Krämer, 2016-09-01 02:39

View differences:

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("&laquo;");
821
      setState('hidden');
822
    } else {
823
      button.html("&raquo;");
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

  
(6-6/18)