forked from enviPath/enviPy
This will hack the ketcher submission to work again (see #207). The problem seems to be that the iframe loads slower than the script tag so the reference is not available on page load. Registering from within the code to poll until ketcher is ready is a bit messy. Tracked the introduced dept in #212. Reviewed-on: enviPath/enviPy#213 Co-authored-by: Tobias O <tobias.olenyi@envipath.com> Co-committed-by: Tobias O <tobias.olenyi@envipath.com>
227 lines
6.5 KiB
HTML
227 lines
6.5 KiB
HTML
{% extends "framework_modern.html" %}
|
|
{% load static %}
|
|
{% block content %}
|
|
<div class="mx-auto w-full p-8">
|
|
<h1 class="h1 mb-4 text-3xl font-bold">
|
|
Predict a Pathway
|
|
|
|
<span class="text-base-content/50 text-xs"
|
|
>in <strong>{{ meta.current_package.name|safe }}</strong>
|
|
</span>
|
|
</h1>
|
|
|
|
<form
|
|
id="predict_form"
|
|
accept-charset="UTF-8"
|
|
action="{{ meta.current_package.url }}/pathway"
|
|
method="post"
|
|
>
|
|
{% csrf_token %}
|
|
<div class="mb-8 flex flex-col gap-8 md:flex-row md:items-end">
|
|
<fieldset class="flex flex-col gap-4 md:flex-3/4">
|
|
<label class="floating-label" for="name">
|
|
<input
|
|
type="text"
|
|
name="name"
|
|
placeholder="Name"
|
|
id="name"
|
|
class="input input-md w-full"
|
|
autofocus
|
|
/>
|
|
<span>Name</span>
|
|
</label>
|
|
|
|
<label class="floating-label" for="description">
|
|
<input
|
|
type="text"
|
|
name="description"
|
|
placeholder="Description"
|
|
id="description"
|
|
class="input input-md w-full"
|
|
/>
|
|
<span>Description</span>
|
|
</label>
|
|
</fieldset>
|
|
<fieldset
|
|
class="fieldset flex shrink-0 flex-row items-start gap-3 md:flex-1/4 md:flex-col"
|
|
>
|
|
<label class="fieldset-label text-base-content/50">Mode</label>
|
|
<label class="label">
|
|
<input
|
|
type="radio"
|
|
name="predict"
|
|
id="radioPredict"
|
|
value="predict"
|
|
checked
|
|
class="radio radio-neutral"
|
|
/>
|
|
Predict
|
|
</label>
|
|
<label class="label">
|
|
<input
|
|
type="radio"
|
|
name="predict"
|
|
id="radioIncremental"
|
|
value="incremental"
|
|
class="radio radio-neutral"
|
|
/>
|
|
Incremental
|
|
</label>
|
|
<label class="label">
|
|
<input
|
|
type="radio"
|
|
name="predict"
|
|
id="radioBuild"
|
|
value="build"
|
|
class="radio radio-neutral"
|
|
/>
|
|
Build
|
|
</label>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<label class="floating-label" for="predict-smiles">
|
|
<input
|
|
type="text"
|
|
name="smiles"
|
|
placeholder="SMILES"
|
|
id="predict-smiles"
|
|
class="input input-md w-full"
|
|
/>
|
|
<span>SMILES</span>
|
|
</label>
|
|
|
|
<div class="divider text-base-content/50">OR</div>
|
|
|
|
<div class="mb-8 w-full">
|
|
<label class="text-base-content/50 mb-4 text-xs font-medium"
|
|
>Draw Structure</label
|
|
>
|
|
<iframe
|
|
id="predict-ketcher"
|
|
src="{% static '/js/ketcher2/ketcher.html' %}"
|
|
width="100%"
|
|
height="510"
|
|
></iframe>
|
|
</div>
|
|
|
|
<label class="select mb-8 w-full">
|
|
<span class="label">Predictor</span>
|
|
<select id="prediction-setting" name="prediction-setting">
|
|
<option disabled>Select a Setting</option>
|
|
{% for s in meta.available_settings %}
|
|
<option
|
|
value="{{ s.url }}"
|
|
{% if s.id == meta.user.default_setting.id %}selected{% endif %}
|
|
>
|
|
{{ s.name }}{% if s.id == meta.user.default_setting.id %}
|
|
(User default)
|
|
{% endif %}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</label>
|
|
|
|
<div class="flex justify-end gap-2">
|
|
<a href="{{ meta.current_package.url }}/pathway" class="btn btn-outline"
|
|
>Cancel</a
|
|
>
|
|
<button
|
|
type="submit"
|
|
id="predict-submit-button"
|
|
class="btn btn-primary"
|
|
>
|
|
Predict
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
{# prettier-ignore-start #}
|
|
<script>
|
|
// Helper function to safely get Ketcher instance from iframe
|
|
function getKetcherInstance(iframeId) {
|
|
const ketcherFrame = document.getElementById(iframeId);
|
|
if (!ketcherFrame) {
|
|
console.error("Ketcher iframe not found:", iframeId);
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
if ('contentWindow' in ketcherFrame && ketcherFrame.contentWindow.ketcher) {
|
|
return ketcherFrame.contentWindow.ketcher;
|
|
}
|
|
} catch (err) {
|
|
console.error("Cannot access Ketcher iframe - possible CORS issue:", err);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function predictKetcherToTextInput() {
|
|
$("#predict-smiles").val(this.ketcher.getSmiles());
|
|
}
|
|
|
|
$(function () {
|
|
$("#predict-ketcher").on("load", function () {
|
|
const checkKetcherReady = () => {
|
|
const win = this.contentWindow;
|
|
if (win.ketcher && "editor" in win.ketcher) {
|
|
window.predictKetcher = win.ketcher;
|
|
win.ketcher.editor.event.change.handlers.push({
|
|
once: false,
|
|
priority: 0,
|
|
f: predictKetcherToTextInput,
|
|
ketcher: win.ketcher,
|
|
});
|
|
} else {
|
|
setTimeout(checkKetcherReady, 100);
|
|
}
|
|
};
|
|
|
|
checkKetcherReady();
|
|
});
|
|
|
|
$("#predict-submit-button").on("click", function (e) {
|
|
e.preventDefault();
|
|
const button = $(this);
|
|
button.prop("disabled", true);
|
|
button.text("Predicting...");
|
|
|
|
// Get SMILES from either input or Ketcher
|
|
let smiles = $("#predict-smiles").val().trim();
|
|
|
|
// If SMILES input is empty, try to get from Ketcher
|
|
if (!smiles) {
|
|
const ketcher = getKetcherInstance('predict-ketcher');
|
|
if (ketcher && ketcher.getSmiles) {
|
|
try {
|
|
smiles = ketcher.getSmiles().trim();
|
|
if (smiles) {
|
|
$("#predict-smiles").val(smiles);
|
|
}
|
|
} catch (err) {
|
|
console.error("Failed to get SMILES from Ketcher:", err);
|
|
alert("Unable to extract structure from the drawing editor. Please enter a SMILES string instead.");
|
|
button.prop("disabled", false);
|
|
button.text("Predict");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Basic validation
|
|
if (!smiles) {
|
|
alert("Please enter a SMILES string or draw a structure.");
|
|
button.prop("disabled", false);
|
|
button.text("Predict");
|
|
return;
|
|
}
|
|
|
|
// Submit form
|
|
$("#predict_form").submit();
|
|
});
|
|
});
|
|
</script>
|
|
{# prettier-ignore-end #}
|
|
{% endblock content %}
|