Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add comment in index.html.tmpl #750

Open
wants to merge 3 commits into
base: refactor/extract-scripting-api
Choose a base branch
from
Open
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
133 changes: 133 additions & 0 deletions src/eterna/FoldingAPIApp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import * as log from 'loglevel';
import ExternalInterface, {ExternalInterfaceCtx} from './util/ExternalInterface';
import Vienna from './folding/Vienna';
import Vienna2 from './folding/Vienna2';
import NuPACK from './folding/NuPACK';
import Contrafold from './folding/Contrafold';
import EternaFold from './folding/Eternafold';
import EternaFoldThreshknot from './folding/EternafoldThreshknot';
import RNAFoldBasic from './folding/RNAFoldBasic';
import FolderManager from './folding/FolderManager';
import LinearFoldC from './folding/LinearFoldC';
import LinearFoldE from './folding/LinearFoldE';
import LinearFoldV from './folding/LinearFoldV';
import Folder from './folding/Folder';
import FoldingAPI from './eternaScript/FoldingAPI';
import addSelectFolderAPIToInterface from './eternaScript/SelectFolderAPI';

interface FoldingAppParams {
containerID?: string;
folderName?: string;
}

interface ProcessedFoldingAppParams {
containerID: string;
folderName: string;
}

export class WasmNotSupportedError extends Error {}

export class ContainerElementNotFound extends Error {}

/**
* Entry point for the folding API provider.
*
* This is an alternate version of EternaJS, only exposing the API needed for scripts to work
* (e.g. `Lib.fold` via `document.getElementById("maingame").fold`).
* */
export default class FoldingAPIApp {
constructor(params: FoldingAppParams) {
// Default param values
params.containerID = params.containerID || 'maingame';
params.folderName = 'vienna';

this._params = {containerID: params.containerID, folderName: params.folderName};

const appContainer: HTMLElement | null = document.getElementById(params.containerID);
if (!appContainer) {
throw new ContainerElementNotFound(`Could not find HTML element with ID ${params.containerID}`);
}
this._appContainer = appContainer;

ExternalInterface.init(appContainer);
}

private static isWebAssemblySupported() {
return typeof WebAssembly === 'object';
}

public async run(): Promise<void> {
if (!FoldingAPIApp.isWebAssemblySupported()) {
throw new WasmNotSupportedError(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to leave handling this error to the Vue app trying to import it. Does it make sense?

Currently it wouldn't propagate to the vue app because of how I used it in folding-api.html.tmpl

"Can't initialize the folding API app, since the browser doesn't support WASM"
);
}

await this.initFoldingEngines();
this.initScriptInterface();
}

public disposeNow(): void {
this._appContainer.innerHTML = '';

FolderManager.dispose();
ExternalInterface.dispose();
}

private async initFoldingEngines(): Promise<void> {
log.info('Initializing folding engines...');
const folders: (Folder | null)[] = await Promise.all([
Vienna.create(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Folders duplication with EternaApp.ts - I should probably move this to a LoadAllFolders.ts thing, so that new folders wouldn't be missed

Vienna2.create(),
NuPACK.create(),
LinearFoldC.create(),
LinearFoldE.create(),
LinearFoldV.create(),
Contrafold.create(),
EternaFold.create(),
EternaFoldThreshknot.create(),
RNAFoldBasic.create()]);

log.info('Folding engines intialized');
for (const folder of folders) {
if (folder !== null) {
FolderManager.instance.addFolder(folder);
}
}

const folder = FolderManager.instance.getFolder(this._params.folderName);
if (folder === null) {
log.warn(`No such folder '${this._params.folderName}'`);
} else {
this._folder = folder;
}
}

private trySelectFolder(folderName: string): boolean {
const folder = FolderManager.instance.getFolder(folderName);
if (folder === null) {
log.warn(`No such folder '${this._params.folderName}'`);
return false;
} else {
return true;
}
}

private initScriptInterface(): void {
new FoldingAPI({
getFolder: () => this._folder,
getIsPseudoknot: () => false
}).registerToScriptInterface(this._scriptInterface);
addSelectFolderAPIToInterface({
selectFolder: (folderName) => this.trySelectFolder(folderName),
scriptInterface: this._scriptInterface
});

ExternalInterface.pushContext(this._scriptInterface);
}

private readonly _params: ProcessedFoldingAppParams;
private readonly _scriptInterface: ExternalInterfaceCtx = new ExternalInterfaceCtx();
private readonly _appContainer: HTMLElement;
private _folder: Folder;
}
3 changes: 3 additions & 0 deletions src/eterna/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as log from 'loglevel';
import EternaApp from 'eterna/EternaApp';
import FoldingAPIApp from 'eterna/FoldingAPIApp';
import * as PIXI from 'pixi.js';

const isProduction = process.env.NODE_ENV === 'production';
Expand All @@ -8,9 +9,11 @@ log.setLevel(isProduction ? 'info' : 'trace');
declare global {
interface Window {
EternaApp: typeof EternaApp;
FoldingAPIApp: typeof FoldingAPIApp;
app: EternaApp; // this syntax is used in index.html.tmpl, at least...
__PIXI_APP__?: PIXI.Application;
}
}

window.EternaApp = EternaApp;
window.FoldingAPIApp = FoldingAPIApp;
Comment on lines +12 to +19
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally I'd use a different index.ts for folding-api.html, so that we don't have to import pixi in the script editor - I'm not sure what is the relationship between eterna/index.ts and index.html though.

73 changes: 73 additions & 0 deletions src/folding-api.html.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<!DOCTYPE html>
<html style="height: 100%;">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>EternaJS</title>

<!--
These scripts are all grabbed from https://github.com/EteRNAgame/website/tree/master/frontend
-->

<link type="text/css" rel="stylesheet" media="all" href="./frontend/themes/css/eterna.css" />

<script>
// The Coffeescript code exposes a Comment object, which clobbers a browser global, which we do not use,
// but the browser global is used by DOMPurify
__comment_bak = Comment;
</script>

<script src="./frontend/jscripts/jquery/jquery-1.7.2.min.js"></script>
<script src="./frontend/jscripts/jquery/jquery-unselectable.js"></script>
<script src="./frontend/jscripts/jquery-ui/jquery-ui-1.8.7.custom.min.js"></script>
<script src="./frontend/jscripts/json/json2.js"></script>

<script src="./frontend/jscripts/application.js"></script>
<script src="./frontend/jscripts/utils.js"></script>
<script src="./frontend/jscripts/ajaxmanager.js"></script>
<script src="./frontend/jscripts/datamanager.js"></script>
<script src="./frontend/jscripts/usermanager.js"></script>

<script src="./frontend/jscripts/eterna/eterna-application.js"></script>
<script src="./frontend/jscripts/eterna/eterna-utils.js"></script>
<script src="./frontend/jscripts/eterna/script-library.js"></script>
<script src="./frontend/jscripts/eterna/script-interface.js"></script>
<script src="./frontend/jscripts/eterna/presenter.js"></script>
Comment on lines +20 to +35
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure which of these is necessary - I would rather not have all of them in the script editor


<script>
// The Coffeescript code exposes a Comment object, which clobbers a browser global, which we do not use,
// but the browser global is used by DOMPurify
Comment = __comment_bak;
</script>
</head>
<body style="margin: 0; padding: 0; height: 100%; display: flex; flex-direction: column;">

<!-- Scripts expect that an element with "maingame" will exist, so this name shouldn't be changed -->
<div id="maingame"></div>

<!-- Load our webpack bundles -->
<%= htmlWebpackPlugin.tags.bodyTags %>

<script>
// Wrapping the code in a function to prevent variables from leaking into the global scope.
(() => {
Application.GET_URI = "<%= htmlWebpackPlugin.options.process.env.APP_SERVER_URL %>/get/";
Application.POST_URI = "<%= htmlWebpackPlugin.options.process.env.APP_SERVER_URL %>/post/";

const params = new URLSearchParams(window.location.search);
const containerID = "maingame";

const app = new FoldingAPIApp({
containerID: containerID,
folderName: params.get("folder"),
})

app.run();

window.stopApp = () => {
app.disposeNow();
}
})();
</script>
</body>
</html>
2 changes: 2 additions & 0 deletions src/index.html.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<link type="text/css" rel="stylesheet" media="all" href="./frontend/themes/css/eterna.css" />

<script>
// The Coffeescript code exposes a Comment object, which clobbers a browser global, which we do not use,
// but the browser global is used by DOMPurify
__comment_bak = Comment;
</script>

Expand Down
27 changes: 20 additions & 7 deletions webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function getEngineLocation() {

module.exports = {
devtool: "inline-source-map",

entry: {
main: ['core-js/stable', 'regenerator-runtime/runtime', "./src/eterna/index.ts"],
vendor: vendorDependencies
Expand Down Expand Up @@ -73,7 +73,7 @@ module.exports = {
path: false
}
},

module: {
rules: [
{
Expand All @@ -95,7 +95,7 @@ module.exports = {
}
],
},

// When importing a module whose path matches one of the following, just
// assume a corresponding global variable exists and use that instead.
// This is important because it allows us to avoid bundling all of our
Expand Down Expand Up @@ -124,12 +124,12 @@ module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
},
},
},
plugins: [

plugins: [
new webpack.EnvironmentPlugin(Object.keys(process.env)),

// Generate an index.html that includes our webpack bundles
new HtmlWebpackPlugin({
template: 'src/index.html.tmpl',
Expand All @@ -142,6 +142,19 @@ module.exports = {
}
}),

// Generate folding=api.html, for the scripts page
new HtmlWebpackPlugin({
template: 'src/folding-api.html.tmpl',
filename: "folding-api.html",
inject: false,
scriptLoading: 'blocking',
process: {
env: {
...process.env
}
}
}),

// Generate a manifest.json file containing our entry point file names:
// https://github.com/danethurber/webpack-manifest-plugin#hooks-options
new WebpackManifestPlugin({
Expand Down