psdi-data-conversion 0.0.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- psdi_data_conversion/__init__.py +11 -0
- psdi_data_conversion/app.py +242 -0
- psdi_data_conversion/bin/linux/atomsk +0 -0
- psdi_data_conversion/bin/linux/c2x +0 -0
- psdi_data_conversion/bin/mac/atomsk +0 -0
- psdi_data_conversion/bin/mac/c2x +0 -0
- psdi_data_conversion/constants.py +185 -0
- psdi_data_conversion/converter.py +459 -0
- psdi_data_conversion/converters/__init__.py +6 -0
- psdi_data_conversion/converters/atomsk.py +32 -0
- psdi_data_conversion/converters/base.py +702 -0
- psdi_data_conversion/converters/c2x.py +32 -0
- psdi_data_conversion/converters/openbabel.py +239 -0
- psdi_data_conversion/database.py +1064 -0
- psdi_data_conversion/dist.py +87 -0
- psdi_data_conversion/file_io.py +216 -0
- psdi_data_conversion/log_utility.py +241 -0
- psdi_data_conversion/main.py +776 -0
- psdi_data_conversion/scripts/atomsk.sh +32 -0
- psdi_data_conversion/scripts/c2x.sh +26 -0
- psdi_data_conversion/security.py +38 -0
- psdi_data_conversion/static/content/accessibility.htm +254 -0
- psdi_data_conversion/static/content/convert.htm +121 -0
- psdi_data_conversion/static/content/convertato.htm +65 -0
- psdi_data_conversion/static/content/convertc2x.htm +65 -0
- psdi_data_conversion/static/content/documentation.htm +94 -0
- psdi_data_conversion/static/content/feedback.htm +53 -0
- psdi_data_conversion/static/content/header-links.html +8 -0
- psdi_data_conversion/static/content/index-versions/header-links.html +8 -0
- psdi_data_conversion/static/content/index-versions/psdi-common-footer.html +99 -0
- psdi_data_conversion/static/content/index-versions/psdi-common-header.html +28 -0
- psdi_data_conversion/static/content/psdi-common-footer.html +99 -0
- psdi_data_conversion/static/content/psdi-common-header.html +28 -0
- psdi_data_conversion/static/content/report.htm +103 -0
- psdi_data_conversion/static/data/data.json +143940 -0
- psdi_data_conversion/static/img/colormode-toggle-dm.svg +3 -0
- psdi_data_conversion/static/img/colormode-toggle-lm.svg +3 -0
- psdi_data_conversion/static/img/psdi-icon-dark.svg +136 -0
- psdi_data_conversion/static/img/psdi-icon-light.svg +208 -0
- psdi_data_conversion/static/img/psdi-logo-darktext.png +0 -0
- psdi_data_conversion/static/img/psdi-logo-lighttext.png +0 -0
- psdi_data_conversion/static/img/social-logo-bluesky-black.svg +4 -0
- psdi_data_conversion/static/img/social-logo-bluesky-white.svg +4 -0
- psdi_data_conversion/static/img/social-logo-instagram-black.svg +1 -0
- psdi_data_conversion/static/img/social-logo-instagram-white.svg +1 -0
- psdi_data_conversion/static/img/social-logo-linkedin-black.png +0 -0
- psdi_data_conversion/static/img/social-logo-linkedin-white.png +0 -0
- psdi_data_conversion/static/img/social-logo-mastodon-black.svg +4 -0
- psdi_data_conversion/static/img/social-logo-mastodon-white.svg +4 -0
- psdi_data_conversion/static/img/social-logo-x-black.svg +3 -0
- psdi_data_conversion/static/img/social-logo-x-white.svg +3 -0
- psdi_data_conversion/static/img/social-logo-youtube-black.png +0 -0
- psdi_data_conversion/static/img/social-logo-youtube-white.png +0 -0
- psdi_data_conversion/static/img/ukri-epsr-logo-darktext.png +0 -0
- psdi_data_conversion/static/img/ukri-epsr-logo-lighttext.png +0 -0
- psdi_data_conversion/static/img/ukri-logo-darktext.png +0 -0
- psdi_data_conversion/static/img/ukri-logo-lighttext.png +0 -0
- psdi_data_conversion/static/javascript/accessibility.js +196 -0
- psdi_data_conversion/static/javascript/common.js +42 -0
- psdi_data_conversion/static/javascript/convert.js +296 -0
- psdi_data_conversion/static/javascript/convert_common.js +252 -0
- psdi_data_conversion/static/javascript/convertato.js +107 -0
- psdi_data_conversion/static/javascript/convertc2x.js +107 -0
- psdi_data_conversion/static/javascript/data.js +176 -0
- psdi_data_conversion/static/javascript/format.js +611 -0
- psdi_data_conversion/static/javascript/load_accessibility.js +89 -0
- psdi_data_conversion/static/javascript/psdi-common.js +177 -0
- psdi_data_conversion/static/javascript/report.js +381 -0
- psdi_data_conversion/static/styles/format.css +147 -0
- psdi_data_conversion/static/styles/psdi-common.css +705 -0
- psdi_data_conversion/templates/index.htm +114 -0
- psdi_data_conversion/testing/__init__.py +5 -0
- psdi_data_conversion/testing/constants.py +12 -0
- psdi_data_conversion/testing/conversion_callbacks.py +394 -0
- psdi_data_conversion/testing/conversion_test_specs.py +208 -0
- psdi_data_conversion/testing/utils.py +522 -0
- psdi_data_conversion-0.0.23.dist-info/METADATA +663 -0
- psdi_data_conversion-0.0.23.dist-info/RECORD +81 -0
- psdi_data_conversion-0.0.23.dist-info/WHEEL +4 -0
- psdi_data_conversion-0.0.23.dist-info/entry_points.txt +2 -0
- psdi_data_conversion-0.0.23.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
/**
|
2
|
+
* @file common.js
|
3
|
+
* @date 2025-02-14
|
4
|
+
* @author Bryan Gillis
|
5
|
+
*/
|
6
|
+
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Gets whether or not the app is operating in "Service mode"
|
10
|
+
*
|
11
|
+
* This is the mode used for the public web app.
|
12
|
+
*
|
13
|
+
* @return {bool} True indicates service mode, False indicates local mode
|
14
|
+
*/
|
15
|
+
export function getServiceMode() {
|
16
|
+
return sessionStorage.getItem("service_mode");
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Sets the service mode for the CSS document of the current page
|
21
|
+
*/
|
22
|
+
export function loadServiceMode() {
|
23
|
+
document.documentElement.setAttribute("service-mode", getServiceMode());
|
24
|
+
}
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Gets whether or not the app is operating in "Production mode"
|
28
|
+
*
|
29
|
+
* This is the mode used in staging/production deployments, but not dev deployments
|
30
|
+
*
|
31
|
+
* @return {bool} True indicates production mode, False indicates dev mode
|
32
|
+
*/
|
33
|
+
export function getProductionMode() {
|
34
|
+
return sessionStorage.getItem("production_mode");
|
35
|
+
}
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Sets the production mode for the CSS document of the current page
|
39
|
+
*/
|
40
|
+
export function loadProductionMode() {
|
41
|
+
document.documentElement.setAttribute("production-mode", getProductionMode());
|
42
|
+
}
|
@@ -0,0 +1,296 @@
|
|
1
|
+
/*
|
2
|
+
convert.js
|
3
|
+
Version 1.0, 24th January 2025
|
4
|
+
|
5
|
+
This is the JavaScript which makes the convert.htm gui work.
|
6
|
+
*/
|
7
|
+
|
8
|
+
|
9
|
+
import { getInputFlags, getOutputFlags, getInputArgFlags, getOutputArgFlags } from "./data.js";
|
10
|
+
import { commonConvertReady, convertFile, getExtCheck, splitArchiveExt, isArchiveExt } from "./convert_common.js"
|
11
|
+
|
12
|
+
var token = "",
|
13
|
+
max_file_size = 0,
|
14
|
+
in_ext = "",
|
15
|
+
out_ext = "",
|
16
|
+
in_str = "",
|
17
|
+
out_str = "";
|
18
|
+
|
19
|
+
$(document).ready(function () {
|
20
|
+
[token, max_file_size, in_str, in_ext, out_str, out_ext] = commonConvertReady("Open Babel");
|
21
|
+
|
22
|
+
$('input[name="coordinates"]').change(coordOptionAvailability);
|
23
|
+
$("#uploadButton").click(submitFile);
|
24
|
+
$("#inFlags").click(blurBox);
|
25
|
+
$("#outFlags").click(blurBox);
|
26
|
+
|
27
|
+
getFlags("in", in_str);
|
28
|
+
getFlags("out", out_str);
|
29
|
+
getFlags("in_arg", in_str);
|
30
|
+
getFlags("out_arg", out_str);
|
31
|
+
});
|
32
|
+
|
33
|
+
// On clicking on an option flag, the select box loses focus so that the light font and dark background (Chrome) appears immediately.
|
34
|
+
function blurBox(event) {
|
35
|
+
this.blur();
|
36
|
+
}
|
37
|
+
|
38
|
+
// On ticking a checkbox, a text box for entry of an option flag argument appears next to it. On unticking, the text box disappears.
|
39
|
+
function enterArgument(event) {
|
40
|
+
var arg_id = this.id.replace('check', 'text'),
|
41
|
+
arg_label_id = this.id.replace('check', 'label');
|
42
|
+
|
43
|
+
if ($('#' + this.id).is(':checked')) {
|
44
|
+
// Show appropriate text box and its label
|
45
|
+
$('#' + arg_id).show();
|
46
|
+
$('#' + arg_label_id).show();
|
47
|
+
}
|
48
|
+
else {
|
49
|
+
// Hide appropriate text box (empty) and its label
|
50
|
+
$('#' + arg_id).val('').hide();
|
51
|
+
$('#' + arg_label_id).hide();
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
// Uploads a user-supplied file
|
56
|
+
function submitFile() {
|
57
|
+
const file = $("#fileToUpload")[0].files[0],
|
58
|
+
[fname, ext] = splitArchiveExt(file.name);
|
59
|
+
|
60
|
+
|
61
|
+
var quality = sessionStorage.getItem("success"),
|
62
|
+
start = quality.indexOf(':') + 2,
|
63
|
+
finish = quality.lastIndexOf('(') - 1;
|
64
|
+
|
65
|
+
quality = quality.substring(start, finish);
|
66
|
+
|
67
|
+
const read_flags_text = $("#inFlags").find(":selected").text(),
|
68
|
+
read_flags = extractFlags(read_flags_text);
|
69
|
+
|
70
|
+
const write_flags_text = $("#outFlags").find(":selected").text(),
|
71
|
+
write_flags = extractFlags(write_flags_text);
|
72
|
+
|
73
|
+
var read_arg_flags = '',
|
74
|
+
write_arg_flags = '',
|
75
|
+
read_args = '',
|
76
|
+
write_args = '',
|
77
|
+
all_args_entered = true;
|
78
|
+
|
79
|
+
const checked_in = $('input[name=in_arg_check]:checked'),
|
80
|
+
checked_out = $('input[name=out_arg_check]:checked');
|
81
|
+
|
82
|
+
checked_in.each(function () {
|
83
|
+
read_arg_flags += $("#" + this.id).val()[0];
|
84
|
+
const arg = $("#in_arg_text" + this.id.substring(this.id.length - 1, this.id.length)).val();
|
85
|
+
|
86
|
+
if (/\S/.test(arg)) {
|
87
|
+
read_args += arg.trim() + '£';
|
88
|
+
}
|
89
|
+
else {
|
90
|
+
all_args_entered = false;
|
91
|
+
}
|
92
|
+
})
|
93
|
+
|
94
|
+
checked_out.each(function () {
|
95
|
+
write_arg_flags += $("#" + this.id).val()[0];
|
96
|
+
const arg = $("#out_arg_text" + this.id.substring(this.id.length - 1, this.id.length)).val();
|
97
|
+
|
98
|
+
if (/\S/.test(arg)) {
|
99
|
+
write_args += arg.trim() + '£';
|
100
|
+
}
|
101
|
+
else {
|
102
|
+
all_args_entered = false;
|
103
|
+
}
|
104
|
+
})
|
105
|
+
|
106
|
+
if (!all_args_entered) {
|
107
|
+
alert('All ticked option flags need additional information to be entered into the associated text box.');
|
108
|
+
return;
|
109
|
+
}
|
110
|
+
|
111
|
+
const coordinates = $('input[name="coordinates"]:checked').val(),
|
112
|
+
coordOption = $('input[name="coordOptions"]:checked').val();
|
113
|
+
|
114
|
+
// If the uploaded file was an archive, we'll expect to download one too. Otherwise we'll expect to download
|
115
|
+
// something with the output extension
|
116
|
+
const download_fname = isArchiveExt(ext) ? fname + "-" + out_ext + "." + ext : fname + "." + out_ext;
|
117
|
+
|
118
|
+
var form_data = new FormData();
|
119
|
+
|
120
|
+
form_data.append("token", token);
|
121
|
+
form_data.append("converter", 'Open Babel');
|
122
|
+
form_data.append("from", in_ext);
|
123
|
+
form_data.append("to", out_ext);
|
124
|
+
form_data.append("from_full", sessionStorage.getItem("in_str"));
|
125
|
+
form_data.append("to_full", sessionStorage.getItem("out_str"));
|
126
|
+
form_data.append("success", quality);
|
127
|
+
form_data.append("from_flags", read_flags);
|
128
|
+
form_data.append("to_flags", write_flags);
|
129
|
+
form_data.append("from_arg_flags", read_arg_flags);
|
130
|
+
form_data.append("from_args", read_args);
|
131
|
+
form_data.append("to_arg_flags", write_arg_flags);
|
132
|
+
form_data.append("to_args", write_args);
|
133
|
+
form_data.append("coordinates", coordinates);
|
134
|
+
form_data.append("coordOption", coordOption);
|
135
|
+
form_data.append("fileToUpload", file);
|
136
|
+
form_data.append("upload_file", true);
|
137
|
+
form_data.append("check_ext", getExtCheck());
|
138
|
+
|
139
|
+
convertFile(form_data, download_fname, fname);
|
140
|
+
}
|
141
|
+
|
142
|
+
// Retrieves option flags from selected text
|
143
|
+
function extractFlags(flags_text) {
|
144
|
+
var flags = "",
|
145
|
+
regex = /: /g,
|
146
|
+
match = "";
|
147
|
+
|
148
|
+
while ((match = regex.exec(flags_text)) != null) {
|
149
|
+
flags += flags_text[match.index - 1];
|
150
|
+
}
|
151
|
+
|
152
|
+
return flags;
|
153
|
+
}
|
154
|
+
|
155
|
+
// Retrieves read or write option flags associated with a file format
|
156
|
+
function getFlags(type, str) {
|
157
|
+
|
158
|
+
try {
|
159
|
+
const [ext, note] = str.split(": ");
|
160
|
+
|
161
|
+
if (type == "in") {
|
162
|
+
getInputFlags(ext, note).then((flags) => {
|
163
|
+
populateFlagBox(flags, type);
|
164
|
+
});
|
165
|
+
}
|
166
|
+
else if (type === "out") {
|
167
|
+
getOutputFlags(ext, note).then((flags) => {
|
168
|
+
populateFlagBox(flags, type);
|
169
|
+
});
|
170
|
+
}
|
171
|
+
else if (type == "in_arg") {
|
172
|
+
|
173
|
+
const in_arg_str_array = str.split(": "),
|
174
|
+
in_arg_ext = in_arg_str_array[0], // e.g. "ins"
|
175
|
+
in_arg_note = in_arg_str_array[1]; // e.g. "ShelX"
|
176
|
+
|
177
|
+
getInputArgFlags(in_arg_ext, in_arg_note).then((argFlags) => {
|
178
|
+
addCheckboxes(argFlags, "in_arg");
|
179
|
+
});
|
180
|
+
}
|
181
|
+
else if (type == "out_arg") {
|
182
|
+
|
183
|
+
const out_arg_str_array = str.split(": "),
|
184
|
+
out_arg_ext = out_arg_str_array[0], // e.g. "ins"
|
185
|
+
out_arg_note = out_arg_str_array[1]; // e.g. "ShelX"
|
186
|
+
|
187
|
+
getOutputArgFlags(out_arg_ext, out_arg_note).then((argFlags) => {
|
188
|
+
addCheckboxes(argFlags, "out_arg");
|
189
|
+
});
|
190
|
+
}
|
191
|
+
|
192
|
+
return true;
|
193
|
+
}
|
194
|
+
catch (e) {
|
195
|
+
return false;
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
// Adds checkboxes for read or write option flags requiring an argument
|
200
|
+
function addCheckboxes(argFlags, type) {
|
201
|
+
|
202
|
+
var container = $(`#${type}Flags`),
|
203
|
+
flagCount = 0;
|
204
|
+
|
205
|
+
if (argFlags.length > 0) {
|
206
|
+
|
207
|
+
$(`#${type}Label`).show();
|
208
|
+
|
209
|
+
for (const argFlag of argFlags) {
|
210
|
+
|
211
|
+
const flag = argFlag.flag;
|
212
|
+
const brief = argFlag.brief.replace(/^N\/A$/, "");
|
213
|
+
const description = argFlag.description.replace(/^N\/A$/, "");
|
214
|
+
const furtherInfo = argFlag.further_info.replace(/^N\/A$/, "");
|
215
|
+
|
216
|
+
container.append(`
|
217
|
+
<tr>
|
218
|
+
<td><input type='checkbox' id="${type}_check${flagCount}" name=${type}_check value="${flag}"></input></td>
|
219
|
+
<td><label for="${type}_check${flagCount}">${flag} [${brief}]: ${description}<label></td>
|
220
|
+
<td><input type='text' id=${type}_text${flagCount} placeholder='-- type info. here --'></input></td>
|
221
|
+
<td><span id= ${type}_label${flagCount}>${furtherInfo}</span></td>
|
222
|
+
</tr>`);
|
223
|
+
|
224
|
+
$(`#${type}_text${flagCount}`).hide();
|
225
|
+
$(`#${type}_label${flagCount}`).hide();
|
226
|
+
$(`#${type}_check${flagCount}`).change(enterArgument);
|
227
|
+
|
228
|
+
flagCount++;
|
229
|
+
}
|
230
|
+
|
231
|
+
container.append(`<br>`);
|
232
|
+
}
|
233
|
+
else {
|
234
|
+
$(`#${type}Label`).hide();
|
235
|
+
|
236
|
+
if (type == 'in_arg') {
|
237
|
+
$("#flag_break").hide();
|
238
|
+
}
|
239
|
+
}
|
240
|
+
}
|
241
|
+
|
242
|
+
// Populates a read or write option flag box
|
243
|
+
function populateFlagBox(entries, type) {
|
244
|
+
|
245
|
+
const el = $("#" + type + "Flags");
|
246
|
+
const disp = $("#" + type + "FlagList");
|
247
|
+
const flagInfo = $("#" + type + "FlagInfo");
|
248
|
+
|
249
|
+
let infoLines = [];
|
250
|
+
|
251
|
+
if (entries.length != 0) {
|
252
|
+
|
253
|
+
disp.css({ display: "inline" });
|
254
|
+
|
255
|
+
for (const entry of entries) {
|
256
|
+
|
257
|
+
el.append(new Option(`${entry.flag}: ${entry.description}`));
|
258
|
+
|
259
|
+
const info = `${entry.flag}: ${entry.further_info}`;
|
260
|
+
|
261
|
+
if (!info.match(/.: N\/A/)) {
|
262
|
+
infoLines.push(info);
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
266
|
+
} else {
|
267
|
+
|
268
|
+
$("#" + type + "_label").hide();
|
269
|
+
$("#" + type + "_flag_break").hide();
|
270
|
+
el.hide();
|
271
|
+
}
|
272
|
+
|
273
|
+
el.append(new Option(""));
|
274
|
+
|
275
|
+
for (const infoLine of infoLines) {
|
276
|
+
|
277
|
+
const div = $("<div>");
|
278
|
+
|
279
|
+
div.text(infoLine);
|
280
|
+
|
281
|
+
flagInfo.append(div);
|
282
|
+
}
|
283
|
+
}
|
284
|
+
|
285
|
+
// Disable coordinate options if calculation type is 'neither,' otherwise enable
|
286
|
+
function coordOptionAvailability(event) {
|
287
|
+
const calcType = $('input[name="coordinates"]:checked').val();
|
288
|
+
|
289
|
+
if (calcType == 'neither') {
|
290
|
+
$('input[name="coordOptions"]').prop({ disabled: true });
|
291
|
+
}
|
292
|
+
else {
|
293
|
+
$('input[name="coordOptions"]').prop({ disabled: false });
|
294
|
+
}
|
295
|
+
}
|
296
|
+
|
@@ -0,0 +1,252 @@
|
|
1
|
+
/*
|
2
|
+
convert_common.js
|
3
|
+
Version 1.0, 17th December 2024
|
4
|
+
*/
|
5
|
+
|
6
|
+
const SECOND = 1000; // Milliseconds
|
7
|
+
const CONVERT_TIMEOUT = 60 * SECOND;
|
8
|
+
const MEGABYTE = 1024 * 1024;
|
9
|
+
|
10
|
+
const ZIP_EXT = "zip"
|
11
|
+
const TAR_EXT = "tar"
|
12
|
+
const GZ_EXT = "gz"
|
13
|
+
const BZ_EXT = "bz"
|
14
|
+
const XZ_EXT = "gz"
|
15
|
+
const TARGZ_EXT = "tar.gz"
|
16
|
+
const TARBZ_EXT = "tar.bz"
|
17
|
+
const TARXZ_EXT = "tar.xz"
|
18
|
+
|
19
|
+
// Whether or not file extensions will be checked
|
20
|
+
let extCheck = true;
|
21
|
+
|
22
|
+
// Whether or not the user wants to also get the log file
|
23
|
+
let requestLog = false;
|
24
|
+
|
25
|
+
var token = "",
|
26
|
+
max_file_size = 0,
|
27
|
+
in_ext = "",
|
28
|
+
out_ext = "",
|
29
|
+
in_str = "",
|
30
|
+
out_str = "";
|
31
|
+
|
32
|
+
export function commonConvertReady(converter) {
|
33
|
+
token = sessionStorage.getItem("token");
|
34
|
+
max_file_size = sessionStorage.getItem("max_file_size");
|
35
|
+
|
36
|
+
in_str = sessionStorage.getItem("in_str");
|
37
|
+
out_str = sessionStorage.getItem("out_str");
|
38
|
+
|
39
|
+
// $$$$$ FUNCTION FOR THIS? $$$$$
|
40
|
+
const in_str_array = in_str.split(": ");
|
41
|
+
in_ext = in_str_array[0]; // e.g. "ins"
|
42
|
+
const in_note = in_str_array[1]; // e.g. "ShelX"
|
43
|
+
|
44
|
+
const out_str_array = out_str.split(": ");
|
45
|
+
out_ext = out_str_array[0];
|
46
|
+
const out_note = out_str_array[1];
|
47
|
+
|
48
|
+
$("#heading").html("Convert from \'" + in_ext + "\' (" + in_note + ") to \'" + out_ext + "\' (" + out_note +
|
49
|
+
") using " + converter);
|
50
|
+
|
51
|
+
$("#extCheck").click(setExtCheck);
|
52
|
+
$("#requestLog").click(setRequestLog);
|
53
|
+
$("#fileToUpload").change(checkFile);
|
54
|
+
|
55
|
+
return [token, max_file_size, in_str, in_ext, out_str, out_ext];
|
56
|
+
}
|
57
|
+
|
58
|
+
// Converts user-supplied file to another format and downloads the resulting file
|
59
|
+
export function convertFile(form_data, download_fname, fname) {
|
60
|
+
|
61
|
+
let convertTimedOut = false;
|
62
|
+
|
63
|
+
var jqXHR = $.ajax({
|
64
|
+
url: `/convert/`,
|
65
|
+
type: "POST",
|
66
|
+
data: form_data,
|
67
|
+
processData: false,
|
68
|
+
contentType: false,
|
69
|
+
timeout: CONVERT_TIMEOUT,
|
70
|
+
success: async function () {
|
71
|
+
if (!convertTimedOut) {
|
72
|
+
await downloadFile(`../downloads/${download_fname}`, download_fname)
|
73
|
+
|
74
|
+
let msg = "To the best of our knowledge, this conversion has worked. A download prompt for your " +
|
75
|
+
"converted file should now be open for you.";
|
76
|
+
if (requestLog) {
|
77
|
+
msg += " A download prompt for the log will appear when you close this box.\n\n" +
|
78
|
+
"You may need to tell your browser to allow this site to download multiple files and try the " +
|
79
|
+
"conversion again if your browser initially disallows the download of the log file.";
|
80
|
+
}
|
81
|
+
alert(msg);
|
82
|
+
|
83
|
+
if (requestLog) {
|
84
|
+
await downloadFile(`../downloads/${fname}.log.txt`, fname + '.log.txt')
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
var fdata = new FormData();
|
89
|
+
|
90
|
+
fdata.append("filename", download_fname);
|
91
|
+
fdata.append("logname", fname + '.log.txt');
|
92
|
+
|
93
|
+
$.ajax({
|
94
|
+
url: `/delete/`,
|
95
|
+
type: "POST",
|
96
|
+
data: fdata,
|
97
|
+
processData: false,
|
98
|
+
contentType: false
|
99
|
+
})
|
100
|
+
.fail(function (e) {
|
101
|
+
// For debugging
|
102
|
+
console.log("Error deleting remote files after download");
|
103
|
+
console.log(e.status);
|
104
|
+
console.log(e.responseText);
|
105
|
+
})
|
106
|
+
},
|
107
|
+
error: function (xmlhttprequest, textstatus, message) {
|
108
|
+
if (textstatus === "timeout") {
|
109
|
+
convertTimedOut = true;
|
110
|
+
alert("ERROR: Conversion attempt timed out. This may be because the conversion is too complicated, " +
|
111
|
+
"or because the server is currently busy.");
|
112
|
+
console.log("ERROR: Conversion timed out")
|
113
|
+
}
|
114
|
+
}
|
115
|
+
})
|
116
|
+
.fail(function (e, textstatus, message) {
|
117
|
+
let errLog = `/static/downloads/${fname}.log.txt`;
|
118
|
+
|
119
|
+
fetch(errLog, { cache: "no-store" })
|
120
|
+
.then(function (response) {
|
121
|
+
if (response.status == 404) {
|
122
|
+
alert("An unknown error occurred, which produced no error log. If you are using the web " +
|
123
|
+
"app, please provide feedback on the conversion that you were attempting by clicking on " +
|
124
|
+
"'Contact' in the navigation bar.\n" +
|
125
|
+
"If you were trying to run this locally, check your terminal for error messages which " +
|
126
|
+
"may help explain what went wrong.");
|
127
|
+
return "";
|
128
|
+
}
|
129
|
+
else if (!convertTimedOut) {
|
130
|
+
return response.text();
|
131
|
+
}
|
132
|
+
})
|
133
|
+
.then(function (text) {
|
134
|
+
if (text != "" && text != null)
|
135
|
+
alert("ERROR: Request to the backend converter returned status '" + textstatus +
|
136
|
+
"' and message: " + message + "\n" + text);
|
137
|
+
})
|
138
|
+
|
139
|
+
// For debugging
|
140
|
+
console.log("Error converting file");
|
141
|
+
console.log(e.status);
|
142
|
+
console.log(e.responseText);
|
143
|
+
})
|
144
|
+
}
|
145
|
+
|
146
|
+
function setExtCheck(event) {
|
147
|
+
extCheck = this.checked;
|
148
|
+
}
|
149
|
+
|
150
|
+
export function getExtCheck() {
|
151
|
+
return extCheck;
|
152
|
+
}
|
153
|
+
|
154
|
+
function setRequestLog(event) {
|
155
|
+
requestLog = this.checked;
|
156
|
+
}
|
157
|
+
|
158
|
+
export function splitArchiveExt(filename) {
|
159
|
+
const filename_segments = filename.split(".");
|
160
|
+
// Check for extreme cases
|
161
|
+
if (filename_segments.length == 0) {
|
162
|
+
return ["", ""];
|
163
|
+
} else if (filename_segments.length == 1) {
|
164
|
+
return [filename, ""];
|
165
|
+
}
|
166
|
+
|
167
|
+
let base;
|
168
|
+
let ext = filename_segments.at(-1);
|
169
|
+
|
170
|
+
if ([GZ_EXT, BZ_EXT, XZ_EXT].includes(ext)) {
|
171
|
+
// In the case that the extension is one of the second parts of tarball extensions, check if the prior
|
172
|
+
// extension is "tar"
|
173
|
+
let prior_ext = filename_segments.at(-2);
|
174
|
+
if (prior_ext == TAR_EXT && filename_segments.length > 2) {
|
175
|
+
base = filename_segments.slice(0, -2).join(".");
|
176
|
+
ext = prior_ext + "." + ext;
|
177
|
+
} else {
|
178
|
+
base = filename_segments.slice(0, -1).join(".");
|
179
|
+
}
|
180
|
+
} else {
|
181
|
+
base = filename_segments.slice(0, -1).join(".");
|
182
|
+
}
|
183
|
+
|
184
|
+
return [base, ext];
|
185
|
+
}
|
186
|
+
|
187
|
+
export function isArchiveExt(ext) {
|
188
|
+
return [ZIP_EXT, TAR_EXT, TARGZ_EXT, TARBZ_EXT, TARXZ_EXT].includes(ext);
|
189
|
+
}
|
190
|
+
|
191
|
+
// Check that the file meets requirements for upload
|
192
|
+
function checkFile(event) {
|
193
|
+
|
194
|
+
let allGood = true;
|
195
|
+
let file = this.files[0];
|
196
|
+
let message = "";
|
197
|
+
|
198
|
+
// Check file has the proper extension if checking is enabled
|
199
|
+
if (extCheck) {
|
200
|
+
|
201
|
+
const file_name = file.name;
|
202
|
+
|
203
|
+
const [_, ext] = splitArchiveExt(file_name);
|
204
|
+
|
205
|
+
if (![in_ext, ZIP_EXT, TAR_EXT, TARGZ_EXT, TARBZ_EXT, TARXZ_EXT].includes(ext)) {
|
206
|
+
message += "The file extension is not " + in_ext + " or a zip or tar archive extension" +
|
207
|
+
": If you're confident this file is the correct type, untick the box above to disable file extension " +
|
208
|
+
"enforcement (note that zip/tar archives MUST have the correct extension, regardless of this " +
|
209
|
+
"tickbox). Otherwise, please select another file or change the 'from' format on the 'Home' page.";
|
210
|
+
allGood = false;
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
// Check file does not exceed maximum size
|
215
|
+
if (max_file_size > 0 && file.size > max_file_size) {
|
216
|
+
if (message !== "")
|
217
|
+
message += "\n\n";
|
218
|
+
message += "The file exceeds the maximum size limit of " + (max_file_size / MEGABYTE).toFixed(2) +
|
219
|
+
" MB; its size is " + (file.size / MEGABYTE).toFixed(2) + " MB.";
|
220
|
+
allGood = false;
|
221
|
+
}
|
222
|
+
|
223
|
+
if (allGood) {
|
224
|
+
$("#uploadButton").css({ "background-color": "var(--ifm-color-primary)", "color": "var(--ifm-hero-text-color)" });
|
225
|
+
$("#uploadButton").prop({ disabled: false });
|
226
|
+
} else {
|
227
|
+
$("#uploadButton").css({ "background-color": "var(--psdi-bg-color-secondary)", "color": "gray" });
|
228
|
+
$("#uploadButton").prop({ disabled: true });
|
229
|
+
alert(message);
|
230
|
+
}
|
231
|
+
}
|
232
|
+
|
233
|
+
/**
|
234
|
+
* Start a download of a file
|
235
|
+
*
|
236
|
+
* The file is first fetched as a blob, then a link to download it is created, clicked, and removed
|
237
|
+
*
|
238
|
+
* @param {str} path The path to the file to be downloaded
|
239
|
+
* @param {str} filename The desired filename of the downloaded file
|
240
|
+
* @returns {Promise<Response>}
|
241
|
+
*/
|
242
|
+
async function downloadFile(path, filename) {
|
243
|
+
return fetch(path)
|
244
|
+
.then(res => res.blob())
|
245
|
+
.then(data => {
|
246
|
+
var a = document.createElement("a");
|
247
|
+
a.href = window.URL.createObjectURL(data);
|
248
|
+
a.download = filename;
|
249
|
+
a.click();
|
250
|
+
a.remove();
|
251
|
+
});
|
252
|
+
}
|
@@ -0,0 +1,107 @@
|
|
1
|
+
/*
|
2
|
+
convertato.js
|
3
|
+
Version 1.0, 8th November 2024
|
4
|
+
|
5
|
+
This is the JavaScript which makes the convertato.htm gui work.
|
6
|
+
*/
|
7
|
+
|
8
|
+
import { commonConvertReady, convertFile, getExtCheck, splitArchiveExt, isArchiveExt } from "./convert_common.js"
|
9
|
+
|
10
|
+
var token = "",
|
11
|
+
max_file_size = 0,
|
12
|
+
in_ext = "",
|
13
|
+
out_ext = "",
|
14
|
+
in_str = "",
|
15
|
+
out_str = "";
|
16
|
+
|
17
|
+
$(document).ready(function () {
|
18
|
+
[token, max_file_size, in_str, in_ext, out_str, out_ext] = commonConvertReady("Atomsk");
|
19
|
+
$("#uploadButton").click(submitFile);
|
20
|
+
});
|
21
|
+
|
22
|
+
// Uploads a user-supplied file
|
23
|
+
function submitFile() {
|
24
|
+
const file = $("#fileToUpload")[0].files[0],
|
25
|
+
[fname, ext] = splitArchiveExt(file.name);
|
26
|
+
|
27
|
+
var quality = sessionStorage.getItem("success"),
|
28
|
+
start = quality.indexOf(':') + 2,
|
29
|
+
finish = quality.lastIndexOf('(') - 1;
|
30
|
+
|
31
|
+
quality = quality.substring(start, finish);
|
32
|
+
|
33
|
+
const read_flags_text = $("#inFlags").find(":selected").text(),
|
34
|
+
read_flags = '';
|
35
|
+
|
36
|
+
const write_flags_text = $("#outFlags").find(":selected").text(),
|
37
|
+
write_flags = '';
|
38
|
+
|
39
|
+
var count = 0,
|
40
|
+
read_arg_flags = '',
|
41
|
+
write_arg_flags = '',
|
42
|
+
read_args = '',
|
43
|
+
write_args = '',
|
44
|
+
all_args_entered = true;
|
45
|
+
|
46
|
+
const checked_in = $('input[name=in_arg_check]:checked'),
|
47
|
+
checked_out = $('input[name=out_arg_check]:checked');
|
48
|
+
|
49
|
+
checked_in.each(function () {
|
50
|
+
read_arg_flags += $("#" + this.id).val()[0];
|
51
|
+
const arg = $("#in_arg_text" + this.id.substring(this.id.length - 1, this.id.length)).val();
|
52
|
+
|
53
|
+
if (/\S/.test(arg)) {
|
54
|
+
read_args += arg.trim() + '£';
|
55
|
+
}
|
56
|
+
else {
|
57
|
+
all_args_entered = false;
|
58
|
+
}
|
59
|
+
})
|
60
|
+
|
61
|
+
checked_out.each(function () {
|
62
|
+
write_arg_flags += $("#" + this.id).val()[0];
|
63
|
+
const arg = $("#out_arg_text" + this.id.substring(this.id.length - 1, this.id.length)).val();
|
64
|
+
|
65
|
+
if (/\S/.test(arg)) {
|
66
|
+
write_args += arg.trim() + '£';
|
67
|
+
}
|
68
|
+
else {
|
69
|
+
all_args_entered = false;
|
70
|
+
}
|
71
|
+
})
|
72
|
+
|
73
|
+
if (!all_args_entered) {
|
74
|
+
alert('All ticked option flags need additional information to be entered into the associated text box.');
|
75
|
+
return;
|
76
|
+
}
|
77
|
+
|
78
|
+
const coordinates = 'neither', //$('input[name="coordinates"]:checked').val(),
|
79
|
+
coordOption = 'medium'; //$('input[name="coordOptions"]:checked').val(),
|
80
|
+
|
81
|
+
// If the uploaded file was an archive, we'll expect to download one too. Otherwise we'll expect to download
|
82
|
+
// something with the output extension
|
83
|
+
const download_fname = isArchiveExt(ext) ? fname + "-" + out_ext + "." + ext : fname + "." + out_ext;
|
84
|
+
|
85
|
+
var form_data = new FormData();
|
86
|
+
|
87
|
+
form_data.append("token", token);
|
88
|
+
form_data.append("converter", 'Atomsk');
|
89
|
+
form_data.append("from", in_ext);
|
90
|
+
form_data.append("to", out_ext);
|
91
|
+
form_data.append("from_full", sessionStorage.getItem("in_str"));
|
92
|
+
form_data.append("to_full", sessionStorage.getItem("out_str"));
|
93
|
+
form_data.append("success", quality);
|
94
|
+
form_data.append("from_flags", read_flags);
|
95
|
+
form_data.append("to_flags", write_flags);
|
96
|
+
form_data.append("from_arg_flags", read_arg_flags);
|
97
|
+
form_data.append("from_args", read_args);
|
98
|
+
form_data.append("to_arg_flags", write_arg_flags);
|
99
|
+
form_data.append("to_args", write_args);
|
100
|
+
form_data.append("coordinates", coordinates);
|
101
|
+
form_data.append("coordOption", coordOption);
|
102
|
+
form_data.append("fileToUpload", file);
|
103
|
+
form_data.append("upload_file", true);
|
104
|
+
form_data.append("check_ext", getExtCheck());
|
105
|
+
|
106
|
+
convertFile(form_data, download_fname, fname);
|
107
|
+
}
|