Spaces:
Running
Running
/** | |
* @fileoverview ChemWriter integration with Gradio interface | |
* Handles bidirectional synchronization between ChemWriter editor and Gradio textbox | |
* @author Manny Cortes ('manny@derifyai.com') | |
* @version 0.3.0 | |
*/ | |
// ============================================================================ | |
// GLOBAL VARIABLES | |
// ============================================================================ | |
/** @type {Object|null} The ChemWriter editor instance */ | |
let editor = null; | |
let chemwriter = null; | |
// ============================================================================ | |
// CONSTANTS | |
// ============================================================================ | |
/** @const {string} Default SMILES for initial molecule (ethanol) */ | |
const DEFAULT_SMILES = "CN(C)CCC1=CNC2=C1C(=CC=C2)OP(=O)(O)O"; | |
/** @const {string} CSS selector for the Gradio SMILES input element */ | |
const SMILES_INPUT_SELECTOR = "#smiles_input textarea, #smiles_input input"; | |
/** @const {string} CSS selector for the Gradio Mol file input element */ | |
const MOL_INPUT_SELECTOR = "#mol_input textarea, #mol_input input"; | |
/** @const {string} CSS selector for the Gradio search button */ | |
const SEARCH_BUTTON_SELECTOR = "#search_btn"; | |
/** @const {number} Delay for paste event handling (ms) */ | |
const PASTE_DELAY = 50; | |
/** @const {number} Delay for initialization retry (ms) */ | |
const INIT_RETRY_DELAY = 250; | |
/** @const {string[]} Events to trigger for Gradio change detection */ | |
const GRADIO_CHANGE_EVENTS = ["input", "change"]; | |
// ============================================================================ | |
// CORE INITIALIZATION | |
// ============================================================================ | |
/** | |
* Initializes ChemWriter editor and sets up event handlers | |
*/ | |
function initializeChemWriter() { | |
try { | |
setupSmilesTextboxEventListeners(); | |
setupChemWriterEventListeners(); | |
editor.setSMILES(DEFAULT_SMILES); | |
// search after the rest of the gradio components load | |
setTimeout(() => document.getElementById("search_btn")?.click(), 500); | |
console.log("ChemWriter initialized successfully"); | |
} catch (error) { | |
console.error("Error initializing ChemWriter:", error); | |
} | |
} | |
// ============================================================================ | |
// GRADIO AND CHEMWRITER INTEGRATION | |
// ============================================================================ | |
/** | |
* Updates the mol_input Gradio textbox with a mol file string | |
* Triggers appropriate events to ensure Gradio detects the change | |
*/ | |
function updateGradioTextbox() { | |
try { | |
const molTextbox = document.querySelector(MOL_INPUT_SELECTOR); | |
const molFile = editor?.getMolfile(); | |
molTextbox.value = molFile; | |
// Trigger events to ensure Gradio detects the change | |
GRADIO_CHANGE_EVENTS.forEach((eventType) => { | |
const event = new Event(eventType, { | |
bubbles: true, | |
cancelable: true, | |
}); | |
molTextbox.dispatchEvent(event); | |
}); | |
} catch (error) { | |
console.error("Error updating Gradio textbox:", error); | |
} | |
} | |
/** | |
* Updates the ChemWriter editor with a SMILES string from the textbox | |
* @param {string} smiles - The SMILES string to display in ChemWriter | |
*/ | |
function updateChemWriterFromTextbox(smiles) { | |
try { | |
smiles = smiles.trim(); | |
editor?.setSMILES(smiles); | |
} catch (error) { | |
console.error("Error updating ChemWriter from textbox:", error); | |
} | |
} | |
// ============================================================================ | |
// UI MONITORING | |
// ============================================================================ | |
function setupSmilesTextboxEventListeners() { | |
const textbox = document.querySelector(SMILES_INPUT_SELECTOR); | |
if (!textbox) { | |
return; | |
} | |
textbox.addEventListener("input", handleTextboxChange); | |
textbox.addEventListener("change", handleTextboxChange); | |
textbox.addEventListener("paste", handleTextboxPaste); | |
} | |
function setupChemWriterEventListeners() { | |
window.addEventListener("resize", () => editor.jd()); | |
editor.addEventListener('document-edited', updateGradioTextbox); | |
} | |
/** | |
* Handles textbox change events | |
* @param {Event} event - The change event | |
*/ | |
function handleTextboxChange(event) { | |
updateChemWriterFromTextbox(event.target.value); | |
} | |
/** | |
* Handles textbox paste events with a delay to ensure content is available | |
* @param {Event} event - The paste event | |
*/ | |
function handleTextboxPaste(event) { | |
setTimeout(() => { | |
updateChemWriterFromTextbox(event.target.value); | |
}, PASTE_DELAY); | |
} | |
// ============================================================================ | |
// PUBLIC API | |
// ============================================================================ | |
/** | |
* Sets ChemWriter SMILES string | |
* @param {string} smiles - The SMILES string to set | |
* @public | |
*/ | |
window.setCWSmiles = function (smiles) { | |
updateChemWriterFromTextbox(smiles); | |
}; | |
/** | |
* Clears both ChemWriter and Gradio textbox | |
* @public | |
*/ | |
window.clearCW = function () { | |
editor.setMolfile('\nCWRITER06142521562D\nCreated with ChemWriter - https://chemwriter.com\n 0 0 0 0 0 0 0 0 0 0999 V2000\nM END'); | |
}; | |
// ============================================================================ | |
// INITIALIZATION LOGIC | |
// ============================================================================ | |
/** | |
* Checks if ChemWriter library is loaded and initializes ChemWriter editor | |
*/ | |
function initializeWhenReady() { | |
chemwriter = window?.chemwriter; | |
// The ChemWriter library normally sets up a window load event listener: window.addEventListener("load", function(){Z.De()}, false) | |
// However, due to race conditions, the "load" event listener may not be added or triggered in time for proper initialization. | |
// So we call the initialization function directly here. | |
chemwriter?.System?.De(); | |
editor = chemwriter?.components?.editor; | |
if (typeof chemwriter?.System?.De !== "undefined" && typeof editor !== "undefined") { | |
console.log("ChemWriter library loaded, initializing..."); | |
chemwriter.System.ready(initializeChemWriter); | |
} else { | |
console.log("ChemWriter library not ready, retrying..."); | |
setTimeout(initializeWhenReady, INIT_RETRY_DELAY); | |
} | |
} | |
initializeWhenReady(); | |