├── .gitignore
├── .editorconfig
├── README.md
└── salf.uc.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .git
2 | .cache
3 | .eslintrc.json
4 | *.zip
5 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | charset = utf-8
6 | trim_trailing_whitespace = true
7 | insert_final_newline = true
8 | indent_style = space
9 | indent_size = 2
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ## Sidebar Always Loaded
8 | This script makes the sidebar to be always been ready to show its content, without the need to load it again each time we open the sidebar panel. The panel is just hiding, but without discard its content.
9 |
10 | > Firefox default behavior is that each time you open the sidebar the content has to load again.
11 |
12 | **It has two visual modes:**
13 | - Float (default): the sidebar is floating over the tab content. Has options to customize it.
14 | - [Classic](https://i.imgur.com/F1StTk6.gif): Firefox's default look. Tab content and sidebar content shares the window's space.
15 |
16 | [**Check out a short demo video**](https://imgur.com/a/KnstI16)
17 |
18 | * Any addon (eg: Tree Style Tab) doesn't need to load every time you open the sidebar.
19 | * Bookmarks or history panels doesn't "lost position". You can search for something there, open a folder or whatever, then close the sidebar and open it again, you'll see that the panel is displaying the same content as when you closed it.
20 |
21 | ## Sidebar shortcut
22 | It has the option to set a keybind to open and close the sidebar.
23 |
24 | Within this functionality there's a plus: Auto close. If the shortcut functionality and auto close are enabled, you can press the modifier (ctrl by default) and click somewhere inside the sidebar content and it will close.
25 |
26 | For example, that is useful for switching tabs: (I have tabs on the sidebar) I open it with the shortcut and keep pressing ctrl to click a tab to swith to. The sidebar closes and I'm in the clicked tab without having to press the shortcut key combo again.
27 |
28 | ## How to install it
29 | **Note that it requires to have an user script loader:** [You can check the steps here](https://github.com/thepante/setup/wiki/How-to-use-Firefox-'userChrome'-scripts).
30 | 1. [**Download salf-userchrome.zip**](https://github.com/thepante/SAL-Firefox/releases/latest/download/salf-userchrome.zip)
31 | 2. Copy the file `salf.uc.js` to your profile's `chrome` folder
32 | 3. Restart Firefox
33 |
34 | > **Note:** `chrome` its a folder that the user can use to customize the Firefox interface. [Read more here](http://kb.mozillazine.org/index.php?title=UserChrome.css).
35 | If you don't have it, just create that. It is located inside your Firefox profile folder:
36 |
37 | > In your Firefox address bar type and enter to `about:support`. There is 'Profile Directory' information, click 'Open Directory'. That's where the `chrome` folder should be located at.
38 |
39 | Restart Firefox: `about:profiles` → `Restart normally`
40 |
41 | ## Preferences
42 | If float mode is not enabled, then it is activated the "classic" mode, which is the (visually) Firefox default behavior. It does not discard its contents but the UI preferences are handled by the browser itself. That's mean that the "float mode settings" of this script are just for that floating mode.
43 |
44 | ### Sidebar header
45 | You can hide it by toggling the `hide_sidebar_header` constant to `true`. This just like the shortcut preferences, are not mode specific so it works on both classic and float modes.
46 |
47 | ### Shortcut preferences
48 |
49 | | option | type | default value | values
50 | | :--- | ---: | ---: | :--- |
51 | | enabled | `Boolean` | `false` | `true`, `false`
52 | | modifier | `String` | `ctrl` | `ctrl`, `alt`, `shift`, `meta`
53 | | key | `String` | `e` | [any valid key](https://gist.github.com/thepante/2a72d4937f076dc6704ed0fbb3a4ca0c)
54 | | auto_close | `Boolean` | `true` | `true`, `false`
55 |
56 | With those default values (if enabled) the sidebar toggles visibility by pressing ctrl + e.
57 |
58 | ### Float mode specific settings
59 |
60 | | option | type | default value | values
61 | | :--- | ---: | ---: | :--- |
62 | | enabled | `Boolean` | `true` | `true`, `false`
63 | | width | `String` | `280px` | CSS units (`px`, `em`, `%`, etc)
64 | | height | `String` | `100%` | CSS units (`px`, `em`, `%`, etc)
65 | | position | `String` | `right` | `left`, `right`
66 | | shadow_intst | `Number` | `0.12` | `0` to `1`
67 | | transparent* | `Boolean` | `false` | `true`, `false`
68 | | slide | `Boolean` | `true` | `true`, `false`
69 | | fade | `Boolean` | `true` | `true`, `false`
70 | | speed | `Number` | `0.1` | seconds
71 |
72 | Note that `fade` and `speed` preferences are specific for the sliding (`slide`) effect.
73 |
74 | \* `Transparent` option has blurred background, which uses the [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter) property:
75 | > From version 70 this feature is behind `thelayout.css.backdrop-filter.enabled` and the `gfx.webrender.all` preferences (both needs to be set to `true`). To change those preferences, visit `about:config`.
76 |
77 | ---
78 |
79 | ## Note
80 | **This script was made under Firefox version 89.0a1 (Nightly, 2021-04-08).**
81 | If in a previous versions doesn't work, [try this previous script](https://github.com/thepante/SAL-Firefox/releases/tag/2.5) instead (only classic mode; [readme](https://github.com/thepante/SAL-Firefox/tree/2.5)).
82 |
83 |
84 | This is a rework of my other script [alfs](https://github.com/thepante/alfs-firefox). That one didn't work anymore in newer versions of Firefox, so I had to redo it. At first, this one didn't had the floating mode so hadn't sense to be in that repo with "floating" in its name.
85 |
--------------------------------------------------------------------------------
/salf.uc.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name salf.uc.js
3 | // @include main
4 | // @version 3.4
5 | // @note github.com/thepante
6 | // ==/UserScript==
7 |
8 | /* - - - - - - - - - - - SETTINGS - - - - - - - - - - - - - - - */
9 |
10 | const float_mode = {
11 | enabled: true,
12 | config: {
13 | width: '280px',
14 | height: '100%',
15 | position: 'right',
16 | shadow_intst: 0.12,
17 | transparent: false,
18 | // -- sliding settings
19 | slide: true,
20 | fade: true,
21 | speed: 0.1,
22 | // -- partially hide
23 | part_hide: {
24 | enabled: false,
25 | shrinked_width: '32px',
26 | expands_onhover: true,
27 | shrinks_onleave: true,
28 | }
29 | }
30 | };
31 |
32 | const shortcut = {
33 | enabled: false,
34 | modifier: 'ctrl',
35 | key: 'e',
36 | auto_close: true,
37 | }
38 |
39 | const hide_sidebar_header = false;
40 |
41 |
42 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
43 |
44 | const sidebar = document.getElementById('sidebar');
45 | const sidebarBox = document.getElementById('sidebar-box');
46 | const sidebarBtnClose = document.getElementById('sidebar-close');
47 | const sidebarHeader = document.getElementById('sidebar-header');
48 |
49 | let sidebarButton;
50 | let isSidebarOpen = false;
51 |
52 | const sidebar_height = float_mode.config.part_hide.enabled ? '100%' : float_mode.config.height;
53 |
54 | const style_classic = `
55 | #sidebar-box { display: inherit; }
56 | #sidebar-box + #sidebar-splitter { display: inherit; }
57 | #sidebar-box.hide { display: none; }
58 | #sidebar-box.hide + #sidebar-splitter { display: none; }
59 | `;
60 |
61 | const style_float = () => `
62 | ${ float_mode.config.part_hide.enabled
63 | ? `#appcontent { margin-right: ${float_mode.config.part_hide.shrinked_width }}`
64 | : ''
65 | }
66 | #sidebar-splitter { display: none; }
67 | #sidebar-header { width: 100% !important; }
68 | ${ sidebar_height != '100%' ? `
69 | #sidebar-box, #sidebar-box #sidebar {
70 | border-bottom-${float_mode.config.position == 'right' ? 'left' : 'right'}-radius: 4px;
71 | }
72 | ` : ''}
73 | #sidebar-box {
74 | --sidebar-width: ${float_mode.config.width};
75 | --sidebar-height: calc(${float_mode.config.height} - ${window.innerHeight - browser.clientHeight}px);
76 | --sidebar-offset-right: ${float_mode.config.part_hide.shrinked_width};
77 | transition: all ${float_mode.config.speed}s ease-in-out;
78 | position: absolute;
79 | display: block;
80 | float: right;
81 | ${float_mode.config.position}: 0;
82 | width: var(--sidebar-width) !important;
83 | height: var(--sidebar-height) !important;
84 | box-shadow: rgba(0, 0, 0, ${float_mode.config.shadow_intst}) 5px 15px 60px 42px;
85 | z-index: 100;
86 | ${ float_mode.config.transparent
87 | ? `opacity: .8;
88 | backdrop-filter: blur(12px);`
89 | : 'opacity: 1;'
90 | }
91 | }
92 | #sidebar-box #sidebar {
93 | display: block;
94 | width: 100% !important;
95 | max-width: 100% !important;
96 | height: calc(100% ${!hide_sidebar_header ? `- 42px` : ''}) !important;
97 | }
98 | #sidebar-box.hide {
99 | box-shadow: none;
100 | ${ float_mode.config.slide
101 | ? `--placement-offset: calc(var(--sidebar-width) * -1);
102 | ${float_mode.config.position}:
103 | ${float_mode.config.part_hide.enabled
104 | ? `calc(var(--placement-offset) + ${float_mode.config.part_hide.shrinked_width});`
105 | : 'var(--placement-offset);'
106 | }`
107 | : 'display: none;'
108 | }
109 | ${ float_mode.config.fade && !float_mode.config.part_hide.enabled &&
110 | 'opacity: 0;'
111 | }
112 | }
113 | `;
114 |
115 | // Append stylesheet to the browser document
116 | // In a function to call later on. Thats because the float stylesheet is
117 | // also in a func to call and define when info about top offset is correct
118 | function setStylesheet() {
119 | try {
120 | const s = document.createElement('style');
121 | s.setAttribute('type', 'text/css');
122 | s.setAttribute('id', 'salf');
123 | s.appendChild(document.createTextNode(
124 | float_mode.enabled ? style_float() : style_classic
125 | ));
126 | document.head.appendChild(s);
127 | } catch (error) {
128 | console.debug(error);
129 | }
130 | }
131 |
132 | function showSidebar() {
133 | isSidebarOpen = true;
134 | sidebarBox.hidden = false;
135 | sidebarButton && (sidebarButton.checked = true);
136 | sidebarBox.classList.remove('hide');
137 | }
138 |
139 | function hideSidebar() {
140 | isSidebarOpen = false;
141 | sidebarBox.hidden = true;
142 | sidebarButton && (sidebarButton.checked = false);
143 | sidebarBox.classList.add('hide');
144 | }
145 |
146 | // Button functionality
147 | const buttonBehavior = () => isSidebarOpen ? hideSidebar() : showSidebar();
148 |
149 | // Add salf behavior
150 | const apply = function() {
151 | sidebarButton = document.getElementById('sidebar-button');
152 |
153 | if (hide_sidebar_header) sidebarHeader.style.display = 'none';
154 | if (!isSidebarOpen && sidebarButton) sidebarButton.checked = false;
155 |
156 | setStylesheet();
157 | hideSidebar();
158 |
159 | // replace buttons vanilla behavior
160 | [sidebarButton, sidebarBtnClose].forEach(
161 | e => e && e.addEventListener('click', function(e) {
162 | e.preventDefault();
163 | e.stopPropagation();
164 | buttonBehavior();
165 | })
166 | );
167 |
168 | // remove listener to avoid being fired again after panel content is changed
169 | window.removeEventListener('DOMContentLoaded', apply);
170 | }
171 |
172 | window.addEventListener('DOMContentLoaded', apply);
173 |
174 | // Shortcut functionality
175 | if (shortcut.enabled) {
176 | document.onkeydown = function(e) {
177 | if (e[shortcut.modifier + 'Key'] && e.key.toLowerCase() === shortcut.key.toLowerCase()) {
178 | e.preventDefault();
179 | e.stopPropagation();
180 | buttonBehavior();
181 | }
182 | };
183 |
184 | // auto hide sidebar when modifier + click inside its content
185 | if (shortcut.auto_close) {
186 | sidebar.onclick = function(e) {
187 | if (e[shortcut.modifier + 'Key']) hideSidebar();
188 | }
189 | }
190 | }
191 |
192 | if (float_mode.config.part_hide.enabled) {
193 | sidebarBox.onmouseenter = function(e) {
194 | e.preventDefault();
195 | e.stopPropagation();
196 | showSidebar();
197 | };
198 |
199 | if (float_mode.config.part_hide.shrinks_onleave) {
200 | sidebarBox.onmouseleave = function(e) {
201 | e.preventDefault();
202 | e.stopPropagation();
203 | hideSidebar();
204 | }
205 | }
206 | }
207 |
208 | console.log('salf → loaded ok');
209 |
210 |
--------------------------------------------------------------------------------