Commit 123afe60 authored by jdurrant's avatar jdurrant
Browse files

Working towards compatibility with updated file-loading system.

parent 1ff8d3dd
# Changes # Changes
## 2.2
1. Updated file loader system.
## 2.1 ## 2.1
1. Web-browser app: changes to how interactions are displayed. 1. Web-browser app: changes to how interactions are displayed.
......
This diff is collapsed.
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
"devDependencies": { "devDependencies": {
"@types/file-saver": "^2.0.1", "@types/file-saver": "^2.0.1",
"@types/jquery": "^3.5.4", "@types/jquery": "^3.5.4",
"@types/jszip": "^3.4.1",
"clean-webpack-plugin": "^3.0.0", "clean-webpack-plugin": "^3.0.0",
"closure-webpack-plugin": "^2.3.0", "closure-webpack-plugin": "^2.3.0",
"copy-webpack-plugin": "^5.1.2", "copy-webpack-plugin": "^5.1.2",
...@@ -44,7 +45,8 @@ ...@@ -44,7 +45,8 @@
"bootstrap-vue": "^2.21.2", "bootstrap-vue": "^2.21.2",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"google-closure-compiler": "^20210601.0.0", "google-closure-compiler": "^20210601.0.0",
"jszip": "^3.5.0", "jszip": "^3.7.1",
"localforage": "^1.10.0",
"markdown-it": "^12.2.0", "markdown-it": "^12.2.0",
"neo-blessed": "^0.2.0", "neo-blessed": "^0.2.0",
"popper.js": "^1.16.1", "popper.js": "^1.16.1",
......
...@@ -29,6 +29,8 @@ self.onmessage = function(e) { ...@@ -29,6 +29,8 @@ self.onmessage = function(e) {
params.push(paramVal); params.push(paramVal);
} }
debugger;
binana["run"](params); binana["run"](params);
// Get the output. // Get the output.
......
// Released under the Apache 2.0 License. See LICENSE.md or go to
// https://opensource.org/licenses/Apache-2.0 for full details. Copyright 2022
// Jacob D. Durrant.
// A place to put properties that are common to multiple components.
// Common to mol-loader, and file loaders.
export var commonMultipleFilesProps = {
"multipleFiles": {
"type": Boolean,
"default": false
},
"saveMultipleFilesToDatabase": {
// Saves copies of files to database for use elsewhere (even after page
// reload). But I can imagine scenarios when you'd want to load multiple
// files without realoading the page, so false by default.
"type": Boolean,
"default": false
},
}
// Properties common to file load, from PDB, from URL, etc.
export var commonFileLoaderProps = {
"id": {
"type": String,
"required": false
},
"required": {
"type": Boolean,
"default": true,
},
"accept": {
"type": String,
"default": "", // e.g., ".pdbqt, .out, .pdb"
},
"convert": {
"type": String,
"default": "", // e.g., ".sdf, .mol2"
},
"valid": {
"type": Boolean,
"default": true
}
}
export var commonProteinEditingProps = {
"allowAtomExtract": {
"type": Boolean,
"default": false
},
"allowAtomDelete": {
"type": Boolean,
"default": true
}
}
// Used in both queue-catcher and queue-controller.
export var commonQueueProps = {
"trigger": {
"type": Boolean,
"default": false,
"required": true
},
"countDownSeconds": {
"type": Number,
"default": 5
},
"molLoaderIds": {
"type": Array,
"required": true
},
"outputZipFilename": {
"type": String,
"default": "output.zip"
}
}
\ No newline at end of file
// This file is released under the Apache 2.0 License. See // This file is released under the Apache 2.0 License. See
// https://opensource.org/licenses/Apache-2.0 for full details. Copyright 2021 // https://opensource.org/licenses/Apache-2.0 for full details. Copyright 2022
// Jacob D. Durrant. // Jacob D. Durrant.
import { addCSS } from "../Utils"; import { addCSS } from "../Utils";
...@@ -54,9 +54,9 @@ export function setupFileLoaderFormGroup(): void { ...@@ -54,9 +54,9 @@ export function setupFileLoaderFormGroup(): void {
:label="label" :label="label"
:label-for="id" :label-for="id"
:id="'input-group-' + id" :id="'input-group-' + id"
:style="styl" :style="styl + ';max-width:none !important;'"
label-cols="0" :label-cols="label ? 12 : 0"
label-cols-xl="1" :label-cols-sm="label ? 2 : 0"
> >
<slot></slot> <slot></slot>
<small <small
...@@ -75,7 +75,10 @@ export function setupFileLoaderFormGroup(): void { ...@@ -75,7 +75,10 @@ export function setupFileLoaderFormGroup(): void {
</span> </span>
`, `,
"props": { "props": {
"label": String, "label": {
"type": String,
"default": undefined
},
"id": String, "id": String,
"styl": String, "styl": String,
"description": String, "description": String,
...@@ -91,7 +94,6 @@ export function setupFileLoaderFormGroup(): void { ...@@ -91,7 +94,6 @@ export function setupFileLoaderFormGroup(): void {
"methods": {}, "methods": {},
"mounted"() { "mounted"() {
addCSS(`.file-loader-form-group .col-form-label { hyphens: auto; }`); addCSS(`.file-loader-form-group .col-form-label { hyphens: auto; }`);
// max-width: 100px !important;
} }
}) })
} }
// This file is released under the Apache 2.0 License. See // This file is released under the Apache 2.0 License. See
// https://opensource.org/licenses/Apache-2.0 for full details. Copyright 2021 // https://opensource.org/licenses/Apache-2.0 for full details. Copyright 2022
// Jacob D. Durrant. // Jacob D. Durrant.
declare var Vue; declare var Vue;
...@@ -20,20 +20,33 @@ export function setupFileLoaderTextInput(): void { ...@@ -20,20 +20,33 @@ export function setupFileLoaderTextInput(): void {
}; };
}, },
"methods": { "methods": {
/**
* Runs when the file is loaded.
* @returns void
*/
"onLoad"(): void { "onLoad"(): void {
this.$emit("onLoad", this["value"]); this.$emit("onLoad", this["value"]);
}, },
/**
* Detect keypress to submit on enter.
* @param {KeyboardEvent} e
* @returns void
*/
"keydown"(e: KeyboardEvent): void { "keydown"(e: KeyboardEvent): void {
if (e.key === "Enter") { if (e.key === "Enter") {
this["onLoad"](); this["onLoad"]();
} }
}, },
/**
* Detect keyup for v-bind.
* @param {KeyboardEvent} e
* @returns void
*/
"keyup"(e: KeyboardEvent) : void { "keyup"(e: KeyboardEvent) : void {
this.$emit("input", this["localValue"]); this.$emit("input", this["localValue"]);
} }
// "clearText"(): void {
// this["val"] = "";
// }
}, },
"template": /*html*/ ` "template": /*html*/ `
<b-input-group> <b-input-group>
......
// This file is released under the Apache 2.0 License. See // This file is released under the Apache 2.0 License. See
// https://opensource.org/licenses/Apache-2.0 for full details. Copyright 2021 // https://opensource.org/licenses/Apache-2.0 for full details. Copyright 2022
// Jacob D. Durrant. // Jacob D. Durrant.
import { ISelection, ParentMol } from "../Mols/ParentMol";
export interface IVueXVar { export interface IVueXVar {
name: string; name: string;
val: any; val: any;
} }
export interface IConvert extends IFileInfo{ export interface IConvert extends IFileInfo {
onConvertDone: Function; onConvertDone: Function; // Must return IFileInfo
onConvertCancel: Function; onConvertCancel: Function;
} }
export interface IFileInfo { export interface IFileInfo {
filename: string; filename: string;
fileContents: string; mol: ParentMol;
// onConvertDone: IConvert;
// convertedResolveFunc?: Function;
// convertedRejectFunc?: Function;
// id?: string; // associated component id
} }
export interface IFileLoadError { export interface IFileLoadError {
...@@ -26,20 +24,32 @@ export interface IFileLoadError { ...@@ -26,20 +24,32 @@ export interface IFileLoadError {
body: string; body: string;
} }
// export interface IFileFromTextField {
// placeholder: string;
// tabName: string;
// loadFunc: Function
// onSuccess: Function;
// onError: Function;
// }
export interface IAllFiles { export interface IAllFiles {
selectedFilename: string; selectedFilename: string;
allFiles: {[key: string]: string}; // filename => contents allFiles: {[key: string]: string}; // filename => contents
} }
export interface IResidueInfo { export interface IExtractInfo {
residueId: string[], selection: ISelection[],
residuePdbLines: string pdbLines: string,
origFilename: string,
suggestedNewFilename: string
}
/**
* Converts ISelection to a string for labelling.
* @param {ISelection} sel
* @returns string
*/
export function iSelectionToStr(sel: ISelection): string {
if (sel["chains"] && !sel["resnames"] && !sel["resids"]) {
// Only has chain.
return "Chain: " + sel["chains"];
}
let prts = [];
if (sel["resnames"]) { prts.push(sel["resnames"]); }
if (sel["resids"]) { prts.push(sel["resids"]); }
if (sel["chains"]) { prts.push(sel["chains"]); }
return prts.join(":");
} }
\ No newline at end of file
You can omit this if this component is registered globally (lots of other
components you use might already be using this one).
\ No newline at end of file
// This file is released under the Apache 2.0 License. See
// https://opensource.org/licenses/Apache-2.0 for full details. Copyright 2022
// Jacob D. Durrant.
declare var Vue;
/** An object containing the vue-component computed functions. */
let computedFunctions = {}
/**
* Setup the small-pill-btn Vue commponent.
* @returns void
*/
export function setupSmallPillBtn(): void {
Vue.component('small-pill-btn', {
/**
* Get the data associated with this component.
* @returns any The data.
*/
"data": function() {
return {}
},
"computed": computedFunctions,
"template": /* html */ `
<b-button
pill :variant="actionStyling === 'delete' ? 'secondary' : 'outline-secondary'" size="sm"
class="py-0 px-1"
style="line-height:14px; font-size:90%; margin-right:2px;"
@click="onClick"
>
<span
v-if="actionStyling === 'extract'"
style="display:inline-block; transform: scaleX(-1);">&#10138;
</span>
<span v-else>&#10006;</span>
<slot></slot>
</b-button>
<!-- style="line-height:14px; font-size:80%;" -->
`,
"props": {
"actionStyling": {
"type": String,
"default": "delete" // Can also be "extract"
}
},
"methods": {
"onClick"(): void {
this.$emit("click");
}
},
"mounted"() {}
})
}
// This file is released under the Apache 2.0 License. See // This file is released under the Apache 2.0 License. See
// https://opensource.org/licenses/Apache-2.0 for full details. Copyright 2021 // https://opensource.org/licenses/Apache-2.0 for full details. Copyright 2022
// Jacob D. Durrant. // Jacob D. Durrant.
import { getMol } from "../Mols";
import { ParentMol } from "../Mols/ParentMol";
import { IFileInfo, IFileLoadError } from "./Interfaces"; import { IFileInfo, IFileLoadError } from "./Interfaces";
/**
* Takes a string of extensions and returns an array of extensions.
* @param {string} exts A string containing a list of extensions separated by
* commas.
* @returns array
*/
export function extsStrToList(exts: string): string[] { export function extsStrToList(exts: string): string[] {
return exts return exts
.toLowerCase() .toLowerCase()
...@@ -14,19 +22,103 @@ export function extsStrToList(exts: string): string[] { ...@@ -14,19 +22,103 @@ export function extsStrToList(exts: string): string[] {
); );
} }
export function getExt(filename: string): string { /**
* Given a filename, return the basename of the file
* @param {string} filename The filename to get the basename of.
* @param {boolean} [extensive=true] If true, considers multi-component
* extensions (e.g., .pdb.txt).
* @returns {string}
*/
export function getBasename(filename: string, extensive = true): string {
let ext = getExt(filename, extensive);
return filename.substring(0, filename.length - ext.length - 1);
}
/**
* Given a filename, return the extension of the file
* @param {string} filename The filename to get the extension from.
* @param {boolean} [extensive=true] If true, considers multi-component
* extensions (e.g., .pdb.txt).
* @returns {string}
*/
export function getExt(filename: string, extensive = true): string {
if (filename === undefined) {
return "";
}
let fileNameParts = filename.toLowerCase().split(/\./g); let fileNameParts = filename.toLowerCase().split(/\./g);
let ext = fileNameParts[fileNameParts.length - 1]; let ext = fileNameParts[fileNameParts.length - 1];
if (extensive) {
for (let i = fileNameParts.length - 2; i > 0; i--) {
// Note that because length -2 and i > 0 (not i > -1), doesn't get
// last (always included) or first (never included) parts. Assuming
// here that if any part has more than four characters, no longer
// extension. This is an arbitrary choice.
let prt = fileNameParts[i];
if (prt.length > 4) {
break;
}
ext = prt + "." + ext;
}
}
return ext; return ext;
} }
/**
* Get the type of a file given the extension.
* @param {string} ext The extension.
* @param {string[]} [choices=undefined] The file-type options.
* @returns {string} The detected type (one of the elements ni choices, if it's
* given).
*/
export function getFileTypeFromExt(ext: string, choices: string[] = undefined): string {
// Remove first letter from ext if it is "."
if (ext.substring(0, 1) === ".") { ext = ext.substring(1); }
// Get the extension parts
let extPrts = ext.split(/\./g);
if (choices === undefined) {
return extPrts.pop().toLowerCase();
}
// Choices need to be lower case
let choicesLowerCase = choices.map(c => c.toLowerCase());
// In windows, text files often have the ".txt" extension, even if they are
// other formats (e.g., pdb.txt).
if (extPrts[extPrts.length - 1] === "txt") {
// But if txt is one of the choicesLowerCase, choose that.
if (choicesLowerCase.indexOf("txt") !== -1) {
return "txt";
}
extPrts.pop();
}
let lastExtPrt = extPrts.pop();
let idx = choicesLowerCase.indexOf(lastExtPrt);
if (idx === -1) {
// Not one of the choicesLowerCase
return undefined;
}
return choices[idx];
}
// let fileType = getFileTypeFromExt(".pdb.txt", ["pdb"]);
// fileType = getFileTypeFromExt(".pdb.txt", ["pdb", "txt"]);
// fileType = getFileTypeFromExt(".pdb", ["pdb"]);
// fileType = getFileTypeFromExt(".pdb", undefined);
/** /**
* Given a file object, returns a promise that resolves the text * Given a file object, returns a promise that resolves the text
* in that file. * in that file.
* @param {*} fileObj The file object. * @param {*} fileObj The file object.
* @returns Promise * @returns Promise
*/ */
export function getFileObjContents(fileObj): Promise<any> { export function getFileObjContents(fileObj): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var fr = new FileReader(); var fr = new FileReader();
fr.onload = () => { fr.onload = () => {
...@@ -35,17 +127,15 @@ export function getFileObjContents(fileObj): Promise<any> { ...@@ -35,17 +127,15 @@ export function getFileObjContents(fileObj): Promise<any> {
resolve(new TextDecoder("utf-8").decode(data)); resolve(new TextDecoder("utf-8").decode(data));
}; };
fr.readAsArrayBuffer(fileObj); fr.readAsArrayBuffer(fileObj);
// Reset the show non-protein atom's link.
// if (this["id"] === "receptor") {
// this.$store.commit("setVar", {
// name: "showKeepProteinOnlyLink",
// val: true,
// });
// }
}); });
} }
/**
* Loads a remote file and sends it to the relevant Vue component.
* @param {string} url The URL of the remote file to load.
* @param {*} vueComp The Vue component.
* @returns {Promise<boolean>}
*/
export function loadRemote(url: string, vueComp: any): Promise<boolean> { export function loadRemote(url: string, vueComp: any): Promise<boolean> {
let urlUpper = url.toUpperCase(); let urlUpper = url.toUpperCase();
if ( if (
...@@ -77,7 +167,7 @@ export function loadRemote(url: string, vueComp: any): Promise<boolean> { ...@@ -77,7 +167,7 @@ export function loadRemote(url: string, vueComp: any): Promise<boolean> {
let filesInfo: IFileInfo[] = [{ let filesInfo: IFileInfo[] = [{
filename: flnm, filename: flnm,
fileContents: text mol: getMol(flnm, text)
} as IFileInfo] } as IFileInfo]
let allFilesLoaded = vueComp.onFilesLoaded(filesInfo); let allFilesLoaded = vueComp.onFilesLoaded(filesInfo);
...@@ -95,10 +185,10 @@ export function loadRemote(url: string, vueComp: any): Promise<boolean> { ...@@ -95,10 +185,10 @@ export function loadRemote(url: string, vueComp: any): Promise<boolean> {
}) })
} }