Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The rules for this file:
talagayev

### Added
- Added extensions in `OpenMMDL Setup` (2026-03-01, PR#189)
- Added `Back` button in `OpenMMDL Setup` (2026-02-28, PR#188)
- Added Drag & Drop option for file upload in `OpenMMDL Setup` (2026-02-28, PR#187)

Expand Down
26 changes: 13 additions & 13 deletions openmmdl/openmmdl_setup/templates/AmberOptions.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{% extends "layout.html" %}
{% block title %}Prepare Amber Files{% endblock %}

{% macro fileinput(id, title="") %}
{% macro fileinput(id, title="", accept="") %}
<div class="input-group om-filedrop" data-file-input="{{ id }}">
<label class="btn btn-default btn-file input-group-addon" >
Browse... <input type="file" name="{{ id }}" id="{{ id }}" style="display: none" onchange="optionChanged()" />
Browse... <input type="file" name="{{ id }}" id="{{ id }}" style="display: none" {% if accept %}accept="{{ accept }}"{% endif %} onchange="if (omValidateFileInput(this)) optionChanged()" />
</label>
<span id="{{ id }}_label" class="form-control om-filedrop-label" style="overflow: hidden; overflow-wrap: anywhere;" title="{{ title }}"></span>
</div>
Expand Down Expand Up @@ -55,7 +55,7 @@
<div class="row">
<div class="col-lg-6" style="padding-left: 30px">
<label for="protLabel"> Receptor File (.pdb) </label>
{{ fileinput('protFile') }}
{{ fileinput('protFile', accept='.pdb') }}
</div>

<div class="col-lg-4" >
Expand Down Expand Up @@ -93,9 +93,9 @@
<div id="dnaOptions">
<div class="form-group">
<div class="row">
<div class="col-lg-4" style="padding-left: 30px">
<div class="col-lg-6" style="padding-left: 30px">
<label for="dnaFile"> Receptor File (.pdb) </label>
{{ fileinput('dnaFile') }}
{{ fileinput('dnaFile', accept='.pdb') }}
</div>

<div class="col-lg-4">
Expand Down Expand Up @@ -126,9 +126,9 @@
<div id="rnaOptions">
<div class="form-group">
<div class="row">
<div class="col-lg-4" style="padding-left: 30px">
<div class="col-lg-6" style="padding-left: 30px">
<label for="rnaFile"> Receptor File (.pdb) </label>
{{ fileinput('rnaFile') }}
{{ fileinput('rnaFile', accept='.pdb') }}
</div>

<div class="col-lg-4">
Expand Down Expand Up @@ -162,9 +162,9 @@
<div id="carboOptions">
<div class="form-group">
<div class="row">
<div class="col-lg-4" style="padding-left: 30px">
<div class="col-lg-6" style="padding-left: 30px">
<label for="carboFile"> Receptor File (.pdb) </label>
{{ fileinput('carboFile') }}
{{ fileinput('carboFile', accept='.pdb') }}
</div>

<div class="col-lg-4">
Expand Down Expand Up @@ -205,7 +205,7 @@
<div class="col-lg-6">
<div class="form-group">
<label for="nmLigFile1">PDB/SDF File</label>
{{ fileinput('nmLigFile') }}
{{ fileinput('nmLigFile', accept='.sdf,.pdb') }}
</div>

<div class="form-group">
Expand Down Expand Up @@ -268,17 +268,17 @@
<div class="col-lg-12">
<div class="form-group">
<label for="spLigFile1" class=" control-label col-md-3">PDB File</label>
<div class="col-md-9" style="margin-bottom: 15px">{{ fileinput('spLigFile', 'As the special ligand usually comes with receptor from RCSB website, here we would ask the user to submit it only in pdb format.') }}</div>
<div class="col-md-9" style="margin-bottom: 15px">{{ fileinput('spLigFile', 'As the special ligand usually comes with receptor from RCSB website, here we would ask the user to submit it only in pdb format.', accept='.pdb') }}</div>
</div>

<div class="form-group">
<label for="prepcFile1" class="control-label col-md-3">Prepc File</label>
<div class="col-md-9" style="margin-bottom: 15px" >{{ fileinput('prepcFile') }}</div>
<div class="col-md-9" style="margin-bottom: 15px" >{{ fileinput('prepcFile', accept='.prepc') }}</div>
</div>

<div class="form-group">
<label for="frcmodFile1" class="control-label col-md-3">Frcmod File</label>
<div class="col-md-9" style="margin-bottom: 15px">{{ fileinput('frcmodFile') }}</div>
<div class="col-md-9" style="margin-bottom: 15px">{{ fileinput('frcmodFile', accept='.frcmod') }}</div>
</div>
</div>

Expand Down
8 changes: 4 additions & 4 deletions openmmdl/openmmdl_setup/templates/configureAmberFiles.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{% extends "layout.html" %}

{% macro fileinput(id) %}
{% macro fileinput(id, accept="") %}
<div class="input-group om-filedrop" data-file-input="{{ id }}">
<label class="btn btn-default btn-file input-group-addon">
Browse... <input type="file" name="{{ id }}" id="{{ id }}" style="display: none" {{'disabled' if disabled else ''}} onchange="optionChanged()" />
Browse... <input type="file" name="{{ id }}" id="{{ id }}" style="display: none" {% if accept %}accept="{{ accept }}"{% endif %} {{'disabled' if disabled else ''}} onchange="if (omValidateFileInput(this)) optionChanged()" />
</label>
<span id="{{ id }}_label" class="form-control om-filedrop-label"></span>
</div>
Expand All @@ -29,11 +29,11 @@
<div class="col-lg-12">
<div class="form-group">
<label for="prmtopFile" class="control-label col-md-2">Prmtop File</label>
<div class="col-md-10">{{ fileinput('prmtopFile') }}</div>
<div class="col-md-10">{{ fileinput('prmtopFile', accept='.prmtop') }}</div>
</div>
<div class="form-group">
<label for="inpcrdFile" class="control-label col-md-2">Inpcrd File</label>
<div class="col-md-10" >{{ fileinput('inpcrdFile') }}</div>
<div class="col-md-10" >{{ fileinput('inpcrdFile', accept='.inpcrd') }}</div>
</div>
</div>

Expand Down
8 changes: 4 additions & 4 deletions openmmdl/openmmdl_setup/templates/configurePdbFile.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{% extends "layout.html" %}

{% macro fileinput(id) %}
{% macro fileinput(id, accept="") %}
<div class="input-group om-filedrop" data-file-input="{{ id }}">
<label class="btn btn-default btn-file input-group-addon">
<span title="Select File"style=" font-weight: 700;">Browse... </span>
<input type="file" name="{{ id }}" id="{{ id }}" style="display: none" onchange="optionChanged()"/>
<input type="file" name="{{ id }}" id="{{ id }}" style="display: none" {% if accept %}accept="{{ accept }}"{% endif %} onchange="if (omValidateFileInput(this)) optionChanged()"/>
</label>
<span id="{{ id }}_label" class="form-control om-filedrop-label"></span>
</div>
Expand All @@ -21,7 +21,7 @@
<form method="post" enctype="multipart/form-data" action="{{ url_for('configureFiles') }}" class="form-horizontal">
<div class="form-group">
<label for="filename" class="control-label col-md-2">PDB File</label>
<div class="col-md-10">{{ fileinput('file') }}</div>
<div class="col-md-10">{{ fileinput('file', accept='.pdb') }}</div>
</div>
<div class="form-group">
<label for="forcefield" class="control-label col-md-2">Force Field</label>
Expand All @@ -45,7 +45,7 @@
</p>
<div class="form-group">
<label for="filename" class="control-label col-md-2">Ligand File</label>
<div class="col-md-10" title="The supported formats are SDF, MOL and MOL2"> {{fileinput('sdfFile') }}</div>
<div class="col-md-10" title="The supported formats are SDF, MOL and MOL2"> {{ fileinput('sdfFile', accept='.sdf,.mol,.mol2') }}</div>
</div>
<div class="form-group">
<label for="smallMoleculeForceField" class="control-label col-md-2">Small Molecule Force Field</label>
Expand Down
72 changes: 64 additions & 8 deletions openmmdl/openmmdl_setup/templates/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,64 @@
}
</script>

<script>
// File extension validation based on <input accept="..."> (works for Browse + drag&drop).
function omParseAcceptExts(accept) {
if (!accept) return [];
return accept.split(',')
.map(function(s){ return (s || '').trim().toLowerCase(); })
.filter(function(s){ return s && s[0] === '.'; });
}

function omNameMatchesExt(name, exts) {
var n = (name || '').toLowerCase();
for (var i = 0; i < exts.length; i++) {
if (n.endsWith(exts[i])) return true;
}
return false;
}

function omClearFileInput(input) {
try { input.value = ''; } catch (e) {}
// Clear label if present.
var lbl = document.getElementById(input.id + "_label");
if (lbl) lbl.textContent = "";
}

// Called by onchange in templates. Return true if OK; false if rejected and cleared.
function omValidateFileInput(input) {
var allowed = omParseAcceptExts(input.getAttribute('accept'));
if (!allowed.length) return true; // no restriction
if (!input.files || input.files.length === 0) return true;

for (var i = 0; i < input.files.length; i++) {
var f = input.files[i];
if (!omNameMatchesExt(f.name, allowed)) {
alert("Invalid file type: " + f.name + "\nAllowed: " + allowed.join(', '));
omClearFileInput(input);
return false;
}
}
return true;
}

// Used by drag&drop to keep only acceptable files (or reject entirely if none acceptable).
function omFilterFilesForInput(input, files) {
var allowed = omParseAcceptExts(input.getAttribute('accept'));
if (!allowed.length) return Array.prototype.slice.call(files);
var kept = [];
for (var i = 0; i < files.length; i++) {
if (omNameMatchesExt(files[i].name, allowed)) kept.push(files[i]);
}
if (!kept.length) {
alert("Invalid file type.\nAllowed: " + allowed.join(', '));
return null;
}
if (!input.multiple && kept.length > 1) kept = [kept[0]];
return kept;
}
</script>

<script>
/* File drag & drop */
(function() {
Expand Down Expand Up @@ -140,14 +198,12 @@
var files = (e.dataTransfer && e.dataTransfer.files) ? e.dataTransfer.files : null;
if (!files || files.length === 0) return;

// Respect single-file inputs.
if (!input.multiple && files.length > 1) {
var dt = new DataTransfer();
dt.items.add(files[0]);
input.files = dt.files;
} else {
input.files = files;
}
var filtered = omFilterFilesForInput(input, files);
if (!filtered || filtered.length === 0) return;

var dt = new DataTransfer();
for (var i = 0; i < filtered.length; i++) dt.items.add(filtered[i]);
input.files = dt.files;

// Trigger existing onchange handlers (optionChanged()).
input.dispatchEvent(new Event('change', { bubbles: true }));
Expand Down
Loading