Namespace globals under window.uncloseai to stop clobbering host pages

window.sendMessage, window.handleUserInput, window.speakText etc
were overwriting host page functions with the same names. This broke
OpenCompletion chat (sendMessage clobbered). Now all exports live
under window.uncloseai namespace. Only uniquely-named globals
(UncloseVault, toggleUncloseaiEmbeddedModal, openTTSModal, etc)
remain on window directly for internal cross-module compat.
This commit is contained in:
russell@unturf.com 2026-02-23 19:55:28 -05:00
parent 310853195b
commit 5d117e50b9
2 changed files with 31 additions and 16 deletions

View file

@ -129,7 +129,7 @@ export function createChatFeature(container) {
<h4>AI Chat</h4>
<div class="widget-feature-container" data-chat-box></div>
<input type="text" placeholder="${getUIText("askAnythingPlaceholder")}" class="widget-input-field" data-chat-input>
<button onclick="handleCustomChat(this)" class="widget-send-btn">Send</button>
<button onclick="uncloseai.handleCustomChat(this)" class="widget-send-btn">Send</button>
`;
container.appendChild(chatDiv);
}

View file

@ -157,25 +157,40 @@ export { chatHistory } from "./src/chat.js";
// -------------------------
if (!__alreadyLoaded) {
// Export functions to global scope for HTML onclick handlers
window.handleUserInput = Chat.handleUserInput;
window.readPageWithHermes = PageReader.readPageWithHermes;
window.sendMessage = Chat.sendMessage;
window.speakText = TTS.speakText;
window.uploadFile = FileUpload.uploadFile;
window.openTTSModal = UI.openTTSModal;
window.openTranslateModal = UI.openTranslateModal;
// Export ALL functions under window.uncloseai namespace to avoid clobbering
// host page globals (e.g. a page's own sendMessage, speakText, etc.)
window.uncloseai = {
handleUserInput: Chat.handleUserInput,
readPageWithHermes: PageReader.readPageWithHermes,
sendMessage: Chat.sendMessage,
speakText: TTS.speakText,
uploadFile: FileUpload.uploadFile,
openTTSModal: UI.openTTSModal,
openTranslateModal: UI.openTranslateModal,
toggleUncloseaiEmbeddedModal: async () =>
await UI.toggleUncloseaiEmbeddedModal(),
extractWebpageContent: Content.extractWebpageContent,
getSelectedModel: Models.getSelectedModel,
getSelectedModelEndpoint: Models.getSelectedModelEndpoint,
showProgressIndicator: FileUpload.showProgressIndicator,
hideProgressIndicator: FileUpload.hideProgressIndicator,
handleTTSFromElement: UI.handleTTSFromElement,
handleUploadFromElement: UI.handleUploadFromElement,
handleSmartTranslate: UI.handleSmartTranslate,
UncloseVault: UncloseVault,
};
// Only set uniquely-named globals that internal extension modules depend on.
// NEVER set generic names (sendMessage, speakText, handleUserInput, uploadFile,
// getSelectedModel, etc.) directly on window — they clobber host page functions.
window.UncloseVault = UncloseVault;
window.toggleUncloseaiEmbeddedModal = async () =>
await UI.toggleUncloseaiEmbeddedModal();
window.extractWebpageContent = Content.extractWebpageContent;
window.getSelectedModel = Models.getSelectedModel;
window.getSelectedModelEndpoint = Models.getSelectedModelEndpoint;
window.showProgressIndicator = FileUpload.showProgressIndicator;
window.hideProgressIndicator = FileUpload.hideProgressIndicator;
window.openTTSModal = UI.openTTSModal;
window.openTranslateModal = UI.openTranslateModal;
window.handleTTSFromElement = UI.handleTTSFromElement;
window.handleUploadFromElement = UI.handleUploadFromElement;
window.handleSmartTranslate = UI.handleSmartTranslate;
window.UncloseVault = UncloseVault;
// Initialize on page load
window.addEventListener("load", async () => {
@ -213,7 +228,7 @@ if (!__alreadyLoaded) {
});
// Export helper functions for class-based integrations
window.handleCustomChat = async (button) => {
window.uncloseai.handleCustomChat = async (button) => {
const container = button.parentElement;
const input = container.querySelector("[data-chat-input]");
const chatBox = container.querySelector("[data-chat-box]");