11diff --git a/browser/base/content/browser-sidebar.js b/browser/base/content/browser-sidebar.js
2- index c5ac301416d2d820ba95e21c0ce1fe305e63b554..ef82cb7bf931d7601c2116ee0d1828d6aa593cae 100644
2+ index c5ac301416d2d820ba95e21c0ce1fe305e63b554..513dcacbe33770cfafb57bdcadfd64b6fb999eef 100644
33--- a/browser/base/content/browser-sidebar.js
44+++ b/browser/base/content/browser-sidebar.js
55@@ -11,6 +11,10 @@ var SidebarUI = {
@@ -51,7 +51,7 @@ index c5ac301416d2d820ba95e21c0ce1fe305e63b554..ef82cb7bf931d7601c2116ee0d1828d6
5151+ title: "Downloads",
5252+ url: "about:downloads",
5353+ menuId: "menu_downloadsSidebar",
54- + iconurl: "chrome://browser/skin/downloads/downloads.svg"
54+ + iconurl: "chrome://browser/skin/downloads/downloads.svg",
5555 }),
5656 ],
5757+ [
@@ -75,25 +75,32 @@ index c5ac301416d2d820ba95e21c0ce1fe305e63b554..ef82cb7bf931d7601c2116ee0d1828d6
7575 ]));
7676 },
7777
78- @@ -61,6 +97,8 @@ var SidebarUI = {
78+ @@ -61,7 +97,10 @@ var SidebarUI = {
7979 return (this._browser = document.getElementById("sidebar"));
8080 },
8181 POSITION_START_PREF: "sidebar.position_start",
8282+ SIDEBAR_TABS_PREF: "pulse.sidebar.enabled",
8383+ SIDEBAR_EXTENSIONS_PREF: "pulse.sidebar.extensions.enabled",
8484 DEFAULT_SIDEBAR_ID: "viewBookmarksSidebar",
85+ + SIDEBAR_KEEP_TABS_ACTIVE_PREF: "pulse.sidebar.keeptabsactive.enabled",
8586
8687 // lastOpenedId is set in show() but unlike currentID it's not cleared out on hide
87- @@ -78,6 +116,8 @@ var SidebarUI = {
88+ // and isn't persisted across windows
89+ @@ -76,8 +115,13 @@ var SidebarUI = {
90+ }
91+ return (this.__title = document.getElementById("sidebar-title"));
8892 },
93+ +
8994 _splitter: null,
9095 _icon: null,
9196+ _sidebarIcons: null,
9297+ _sidebarIconsBottom: null,
98+ + /** @type {string[]} */
99+ + loadedSidebars: null,
93100 _reversePositionButton: null,
94101 _switcherPanel: null,
95102 _switcherTarget: null,
96- @@ -110,10 +150,40 @@ var SidebarUI = {
103+ @@ -110,15 +154,58 @@ var SidebarUI = {
97104 this._switcherTarget = document.getElementById("sidebar-switcher-target");
98105 this._switcherArrow = document.getElementById("sidebar-switcher-arrow");
99106
@@ -110,18 +117,18 @@ index c5ac301416d2d820ba95e21c0ce1fe305e63b554..ef82cb7bf931d7601c2116ee0d1828d6
110117+ false
111118+ );
112119+
120+ + this._keepTabsActivePref = Services.prefs.getBoolPref(
121+ + this.SIDEBAR_KEEP_TABS_ACTIVE_PREF,
122+ + false
123+ + );
124+ +
113125+ for (const sidebaritem of sidebaritems) {
114126+ if (this.sidebars.get(sidebaritem).extensionId && !sidebarExtensionVis) {
115127+ return;
116128+ }
117129+ this.createSidebarItem(sidebaritem, this.sidebars.get(sidebaritem), true);
118130+ }
119131+
120- + //Add divider
121- + const divider = document.createElement("hr");
122- + divider.classList.add("sidebar-divider");
123- + this._sidebarIcons.appendChild(divider);
124- +
125132+ const sidebarVisible = Services.prefs.getBoolPref(
126133+ this.SIDEBAR_TABS_PREF,
127134+ true
@@ -130,11 +137,54 @@ index c5ac301416d2d820ba95e21c0ce1fe305e63b554..ef82cb7bf931d7601c2116ee0d1828d6
130137+
131138+ // Keep track on the changes of the sidebar visibility
132139+ Services.prefs.addObserver(this.SIDEBAR_TABS_PREF, this);
140+ +
141+ + Services.prefs.addObserver(this.SIDEBAR_KEEP_TABS_ACTIVE_PREF, this);
133142+
134143 this._inited = true;
135144
136145 Services.obs.addObserver(this, "intl:app-locales-changed");
137- @@ -159,17 +229,26 @@ var SidebarUI = {
146+
147+ this._initDeferred.resolve();
148+ +
149+ + //Check the pre-existance of sidebar and if it is not there, create it
150+ + var sidebar = this.browser;
151+ + let sidebarExists = !!sidebar;
152+ + if (this._keepTabsActivePref && sidebarExists) {
153+ + sidebar.remove();
154+ + } else if (this._keepTabsActivePref && !sidebarExists) {
155+ + this.createBrowser("sidebar");
156+ + }
157+ +
158+ + this.loadedSidebars = [];
159+ },
160+
161+ uninit() {
162+ @@ -127,7 +214,10 @@ var SidebarUI = {
163+ let enumerator = Services.wm.getEnumerator("navigator:browser");
164+ if (!enumerator.hasMoreElements()) {
165+ let xulStore = Services.xulStore;
166+ - xulStore.persist(this._box, "sidebarcommand");
167+ +
168+ + if (!this._keepTabsActivePref) {
169+ + xulStore.persist(this._box, "sidebarcommand");
170+ + }
171+
172+ if (this._box.hasAttribute("positionend")) {
173+ xulStore.persist(this._box, "positionend");
174+ @@ -148,6 +238,12 @@ var SidebarUI = {
175+ xulStore.persist(this._title, "value");
176+ }
177+
178+ + // Remove the sidebar seperator with class sidebar-divider
179+ + const sidebarDivider = document.querySelector(".sidebar-divider");
180+ + if (sidebarDivider) {
181+ + sidebarDivider.remove();
182+ + }
183+ +
184+ Services.obs.removeObserver(this, "intl:app-locales-changed");
185+
186+ if (this._observer) {
187+ @@ -159,17 +255,47 @@ var SidebarUI = {
138188 /**
139189 * The handler for Services.obs.addObserver.
140190 **/
@@ -160,26 +210,134 @@ index c5ac301416d2d820ba95e21c0ce1fe305e63b554..ef82cb7bf931d7601c2116ee0d1828d6
160210+ Services.prefs.getBoolPref(this.SIDEBAR_TABS_PREF, true)
161211+ );
162212+ break;
213+ +
214+ + case this.SIDEBAR_KEEP_TABS_ACTIVE_PREF:
215+ + //Hide the sidebar if it is open
216+ + if (this.isOpen) {
217+ + this.hide();
218+ + }
219+ +
220+ + this.uninit();
221+ +
222+ + // We need to clean up all existing sidebar frames to prevent a memory leak.
223+ + for (const loadedSidebar of this.loadedSidebars) {
224+ + const elementId = `sidebar-browser-${loadedSidebar}`;
225+ + const element = document.getElementById(elementId);
226+ +
227+ + if (element) {
228+ + element.remove();
229+ + }
230+ + }
231+ +
232+ + this.init();
233+ + break;
163234+ }
164235+ break;
165236 }
166237 }
167238 },
168- @@ -570,6 +649,13 @@ var SidebarUI = {
239+ @@ -485,6 +611,9 @@ var SidebarUI = {
240+ },
241+
242+ _loadSidebarExtension(commandID) {
243+ + if (this._keepTabsActivePref && this.loadedSidebars.includes(commandID)) {
244+ + return;
245+ + }
246+ let sidebar = this.sidebars.get(commandID);
247+ let { extensionId } = sidebar;
248+ if (extensionId) {
249+ @@ -523,6 +652,7 @@ var SidebarUI = {
250+ }
251+
252+ this._fireFocusedEvent();
253+ + this.loadedSidebars.push(commandID);
254+ return true;
255+ });
256+ },
257+ @@ -546,10 +676,28 @@ var SidebarUI = {
258+ }
259+ return this._show(commandID).then(() => {
260+ this._loadSidebarExtension(commandID);
261+ + this.loadedSidebars.push(commandID);
262+ return true;
263+ });
264+ },
265+
266+ + //Create sidebar browser between active and inactive for persistence reasons
267+ + createBrowser(id, commandID) {
268+ + let browser = document.createXULElement("browser");
269+ + browser.setAttribute("id", id);
270+ + browser.setAttribute("autoscroll", "false");
271+ + browser.setAttribute("disablehistory", "true");
272+ + browser.setAttribute("disablefullscreen", "true");
273+ + browser.setAttribute("tooltip", "aHTMLTooltip");
274+ + browser.setAttribute("class", "sidebar-tab");
275+ + if (commandID) {
276+ + browser.setAttribute("sidebarcommand", commandID);
277+ + }
278+ + browser.setAttribute("style", "min-width: 14em; -moz-box-flex: 1;");
279+ + this._box.appendChild(browser);
280+ + this._browser = browser;
281+ + },
282+ +
283+ /**
284+ * Implementation for show. Also used internally for sidebars that are shown
285+ * when a window is opened and we don't want to ping telemetry.
286+ @@ -559,6 +707,29 @@ var SidebarUI = {
287+ */
288+ _show(commandID) {
289+ return new Promise(resolve => {
290+ + if (this._keepTabsActivePref) {
291+ + const elementId = `sidebar-browser-${commandID}`;
292+ +
293+ + //try and find browser with id sidebar-browser-<commandid>
294+ + if (!document.getElementById(elementId)) {
295+ + this.createBrowser(elementId, commandID);
296+ + } else {
297+ + //browser already exists, get it
298+ + let browser = document.getElementById(elementId);
299+ + this._browser = browser;
300+ + }
301+ +
302+ + let browsers = document.querySelectorAll("[id^='sidebar-browser-']");
303+ + //hide all of them except the one we want to show
304+ + for (let i = 0; i < browsers.length; i++) {
305+ + if (browsers[i].id != "sidebar-browser-" + commandID) {
306+ + browsers[i].setAttribute("hidden", "true");
307+ + } else {
308+ + browsers[i].removeAttribute("hidden");
309+ + }
310+ + }
311+ + }
312+ +
313+ this.selectMenuItem(commandID);
314+
315+ this._box.hidden = this._splitter.hidden = false;
316+ @@ -570,13 +741,21 @@ var SidebarUI = {
169317 this._box.setAttribute("sidebarcommand", commandID);
170318 this.lastOpenedId = commandID;
171319
172320+ // Pulse: Reset sidebar margin to zero to allow for correct animations to
173321+ // take place (adapted from dot browser, se below)
174322+ this._box.style.marginLeft = "0px";
175- +
176- + // Pulse: Add checked to the sidebar-icons class to enable more css latter
177- + this._sidebarIcons.setAttribute("checked", "true");
178323+
179324 let { url, title, sourceL10nEl } = this.sidebars.get(commandID);
180325 this.title = title;
181326 // Keep the title element in sync with any l10n changes.
182- @@ -615,6 +701,27 @@ var SidebarUI = {
327+ this.observeTitleChanges(sourceL10nEl);
328+ this.browser.setAttribute("src", url); // kick off async load
329+ -
330+ - if (this.browser.contentDocument.location.href != url) {
331+ + if (
332+ + (!this.loadedSidebars.includes(commandID) &&
333+ + this._keepTabsActivePref) ||
334+ + ((this.browser.contentDocument.location.href != url || null) &&
335+ + !this._keepTabsActivePref)
336+ + ) {
337+ this.browser.addEventListener(
338+ "load",
339+ event => {
340+ @@ -615,22 +794,46 @@ var SidebarUI = {
183341
184342 this.selectMenuItem("");
185343
@@ -201,21 +359,39 @@ index c5ac301416d2d820ba95e21c0ce1fe305e63b554..ef82cb7bf931d7601c2116ee0d1828d6
201359+ this._splitter.hidden = true;
202360+
203361+ this._box.removeAttribute("checked");
204- + this._sidebarIcons.removeAttribute("checked");
205362+ }, 170);
206363+
207364 // Replace the document currently displayed in the sidebar with about:blank
208365 // so that we can free memory by unloading the page. We need to explicitly
209366 // create a new content viewer because the old one doesn't get destroyed
210- @@ -625,6 +732,7 @@ var SidebarUI = {
367+ // until about:blank has loaded (which does not happen as long as the
368+ // element is hidden).
369+ - this.browser.setAttribute("src", "about:blank");
370+ - this.browser.docShell.createAboutBlankContentViewer(null, null);
371+ +
372+ + if (!this._keepTabsActivePref) {
373+ + this.browser.setAttribute("src", "about:blank");
374+ + this.browser.docShell.createAboutBlankContentViewer(null, null);
375+ + }
211376
212377 this._box.removeAttribute("checked");
213378 this._box.hidden = this._splitter.hidden = true;
214379+ this._sidebarIcons.removeAttribute("checked");
215380
216- let selBrowser = gBrowser.selectedBrowser;
217- selBrowser.focus();
218- @@ -638,25 +746,112 @@ var SidebarUI = {
381+ - let selBrowser = gBrowser.selectedBrowser;
382+ - selBrowser.focus();
383+ - if (triggerNode) {
384+ - updateToggleControlLabel(triggerNode);
385+ - }
386+ + // let selBrowser = gBrowser.selectedBrowser;
387+ + // selBrowser.focus();
388+ + // if (triggerNode) {
389+ + // updateToggleControlLabel(triggerNode);
390+ + // }
391+ },
392+
393+ /**
394+ @@ -638,25 +841,121 @@ var SidebarUI = {
219395 * none if the argument is an empty string.
220396 */
221397 selectMenuItem(commandID) {
@@ -289,6 +465,15 @@ index c5ac301416d2d820ba95e21c0ce1fe305e63b554..ef82cb7bf931d7601c2116ee0d1828d6
289465+ document.getElementById(`sidebar-background-${id}`).remove();
290466+ }
291467+
468+ + //if id contains ext
469+ + if (id.includes("ext")) {
470+ + if (!document.getElementsByClassName("sidebar-divider").length) {
471+ + const divider = document.createElement("hr");
472+ + divider.classList.add("sidebar-divider");
473+ + this._sidebarIcons.appendChild(divider);
474+ + }
475+ + }
476+ +
292477+ const background = document.createXULElement("vbox");
293478+ background.classList.add("sidebar-item-background");
294479+ background.setAttribute("id", `sidebar-background-${id}`);
0 commit comments