AIWindowUI.sys.mjs (3529B)
1 /** 2 * This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 */ 6 7 import { AIWINDOW_URL } from "moz-src:///browser/components/aiwindow/ui/modules/AIWindow.sys.mjs"; 8 9 export const AIWindowUI = { 10 BOX_ID: "ai-window-box", 11 SPLITTER_ID: "ai-window-splitter", 12 BROWSER_ID: "ai-window-browser", 13 STACK_CLASS: "ai-window-browser-stack", 14 15 /** 16 * @param {Window} win 17 * @returns {{ chromeDoc: Document, box: Element, splitter: Element } | null} 18 */ 19 _getSidebarElements(win) { 20 if (!win) { 21 return null; 22 } 23 const chromeDoc = win.document; 24 const box = chromeDoc.getElementById(this.BOX_ID); 25 const splitter = chromeDoc.getElementById(this.SPLITTER_ID); 26 27 if (!box || !splitter) { 28 return null; 29 } 30 return { chromeDoc, box, splitter }; 31 }, 32 33 /** 34 * Ensure the aiwindow <browser> exists under the sidebar box. 35 * 36 * @param {Document} chromeDoc 37 * @param {Element} box 38 * @returns {XULElement} browser 39 */ 40 ensureBrowserIsAppended(chromeDoc, box) { 41 const existingBrowser = chromeDoc.getElementById(this.BROWSER_ID); 42 if (existingBrowser) { 43 // Already exists 44 return existingBrowser; 45 } 46 47 const stack = box.querySelector(`.${this.STACK_CLASS}`); 48 49 if (!stack.isConnected) { 50 stack.className = this.STACK_CLASS; 51 stack.setAttribute("flex", "1"); 52 box.appendChild(stack); 53 } 54 55 const browser = chromeDoc.createXULElement("browser"); 56 browser.id = this.BROWSER_ID; 57 browser.setAttribute("transparent", "true"); 58 browser.setAttribute("flex", "1"); 59 browser.setAttribute("disablehistory", "true"); 60 browser.setAttribute("disablefullscreen", "true"); 61 browser.setAttribute("tooltip", "aHTMLTooltip"); 62 browser.setAttribute("src", AIWINDOW_URL); 63 stack.appendChild(browser); 64 return browser; 65 }, 66 67 /** 68 * @param {Window} win 69 * @returns {boolean} whether the sidebar is open (visible) 70 */ 71 isSidebarOpen(win) { 72 const nodes = this._getSidebarElements(win); 73 if (!nodes) { 74 return false; 75 } 76 // The sidebar is considered open if the box is visible 77 return !nodes.box.hidden; 78 }, 79 80 /** 81 * Open the AI Window sidebar 82 * 83 * @param {Window} win 84 */ 85 openSidebar(win) { 86 const nodes = this._getSidebarElements(win); 87 88 if (!nodes) { 89 return; 90 } 91 92 const { chromeDoc, box, splitter } = nodes; 93 94 this.ensureBrowserIsAppended(chromeDoc, box); 95 96 box.hidden = false; 97 splitter.hidden = false; 98 box.parentElement.hidden = false; 99 }, 100 101 /** 102 * Close the AI Window sidebar. 103 * 104 * @param {Window} win 105 */ 106 closeSidebar(win) { 107 const nodes = this._getSidebarElements(win); 108 if (!nodes) { 109 return; 110 } 111 const { box, splitter } = nodes; 112 113 box.hidden = true; 114 splitter.hidden = true; 115 }, 116 117 /** 118 * Toggle the AI Window sidebar 119 * 120 * @param {Window} win 121 * @returns {boolean} true if now open, false if now closed 122 */ 123 toggleSidebar(win) { 124 const nodes = this._getSidebarElements(win); 125 if (!nodes) { 126 return false; 127 } 128 const { chromeDoc, box, splitter } = nodes; 129 130 const opening = box.hidden; 131 if (opening) { 132 this.ensureBrowserIsAppended(chromeDoc, box); 133 } 134 135 box.hidden = !opening; 136 splitter.hidden = !opening; 137 138 if (opening && box.parentElement?.hidden) { 139 box.parentElement.hidden = false; 140 } 141 142 return opening; 143 }, 144 };