File size: 6,223 Bytes
0deb5b7
c0a630f
 
0deb5b7
c0a630f
0deb5b7
 
 
 
 
 
c0a630f
 
 
0deb5b7
 
 
 
 
 
c0a630f
0deb5b7
 
 
 
c0a630f
 
 
776a711
 
 
0deb5b7
 
 
 
c0a630f
0deb5b7
 
c0a630f
0deb5b7
 
 
 
 
 
c0a630f
0deb5b7
c0a630f
0deb5b7
c0a630f
 
 
776a711
 
c0a630f
0deb5b7
c0a630f
0deb5b7
 
 
 
c0a630f
0deb5b7
 
 
c0a630f
0deb5b7
 
c0a630f
0deb5b7
c0a630f
 
 
0deb5b7
 
 
 
 
 
 
c0a630f
0deb5b7
 
 
 
 
 
 
c0a630f
 
0deb5b7
c0a630f
0deb5b7
c0a630f
 
0deb5b7
c0a630f
0deb5b7
 
 
 
 
 
 
c0a630f
0deb5b7
 
 
 
 
 
 
c0a630f
 
 
 
 
0deb5b7
 
 
 
 
 
 
c0a630f
0deb5b7
 
 
 
 
 
 
 
c0a630f
0deb5b7
 
 
 
 
 
 
 
c0a630f
0deb5b7
 
 
c0a630f
 
0deb5b7
 
 
c0a630f
0deb5b7
 
c0a630f
 
0deb5b7
 
 
 
 
 
 
c0a630f
0deb5b7
 
c0a630f
 
 
 
 
 
 
 
 
0deb5b7
c0a630f
0deb5b7
 
 
 
c0a630f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/**
 * @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();