@opencor/opencor 0.20250813.0
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.
- package/LICENSE +201 -0
- package/README.md +61 -0
- package/dist/index-BxzyBYAw.js +98574 -0
- package/dist/index.d.ts +8 -0
- package/dist/opencor.css +1 -0
- package/dist/opencor.es.js +5 -0
- package/dist/opencor.umd.js +6275 -0
- package/dist/quill-BGLY3Ud3.js +7521 -0
- package/package.json +90 -0
- package/src/App.vue +27 -0
- package/src/assets/app.css +14 -0
- package/src/assets/base.css +28 -0
- package/src/assets/logo.svg +17 -0
- package/src/common/common.ts +86 -0
- package/src/common/constants.ts +12 -0
- package/src/common/electron.ts +23 -0
- package/src/common/electronApi.ts +63 -0
- package/src/common/locCommon.ts +170 -0
- package/src/common/settings.ts +95 -0
- package/src/common/vueCommon.ts +50 -0
- package/src/components/BackgroundComponent.vue +26 -0
- package/src/components/ContentsComponent.vue +262 -0
- package/src/components/DragNDropComponent.vue +29 -0
- package/src/components/LoadOpencorComponent.vue +33 -0
- package/src/components/MainMenu.vue +220 -0
- package/src/components/OpenCOR.vue +546 -0
- package/src/components/SpinningWheelComponent.vue +15 -0
- package/src/components/dialogs/AboutDialog.vue +51 -0
- package/src/components/dialogs/BaseDialog.vue +11 -0
- package/src/components/dialogs/OpenRemoteDialog.vue +37 -0
- package/src/components/dialogs/ResetAllDialog.vue +13 -0
- package/src/components/dialogs/SettingsDialog.vue +42 -0
- package/src/components/dialogs/UpdateAvailableDialog.vue +16 -0
- package/src/components/dialogs/UpdateDownloadProgressDialog.vue +17 -0
- package/src/components/dialogs/UpdateErrorDialog.vue +18 -0
- package/src/components/dialogs/UpdateNotAvailableDialog.vue +12 -0
- package/src/components/propertyEditors/GraphsPropertyEditor.vue +3 -0
- package/src/components/propertyEditors/ParametersPropertyEditor.vue +3 -0
- package/src/components/propertyEditors/PropertyEditor.vue +61 -0
- package/src/components/propertyEditors/SimulationPropertyEditor.vue +45 -0
- package/src/components/propertyEditors/SolversPropertyEditor.vue +3 -0
- package/src/components/views/IssuesView.vue +37 -0
- package/src/components/views/SimulationExperimentUiView.vue +152 -0
- package/src/components/views/SimulationExperimentView.vue +214 -0
- package/src/components/widgets/GraphPanelWidget.vue +137 -0
- package/src/components/widgets/InputWidget.vue +128 -0
- package/src/libopencor/locApi.ts +167 -0
- package/src/libopencor/locFileApi.ts +263 -0
- package/src/libopencor/locLoggerApi.ts +36 -0
- package/src/libopencor/locSedApi.ts +486 -0
- package/src/libopencor/locUiJsonApi.ts +485 -0
- package/src/libopencor/locVersionApi.ts +17 -0
- package/src/libopencor/src/common.cpp +67 -0
- package/src/libopencor/src/common.h +27 -0
- package/src/libopencor/src/file.cpp +72 -0
- package/src/libopencor/src/file.h +15 -0
- package/src/libopencor/src/main.cpp +78 -0
- package/src/libopencor/src/sed.cpp +348 -0
- package/src/libopencor/src/sed.h +53 -0
- package/src/libopencor/src/version.cpp +8 -0
- package/src/libopencor/src/version.h +5 -0
- package/src/main.ts +5 -0
- package/src/types/types.d.ts +9 -0
package/package.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": {
|
|
3
|
+
"name": "Alan Garny",
|
|
4
|
+
"email": "a.garny@auckland.ac.nz"
|
|
5
|
+
},
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/opencor/webapp/issues"
|
|
8
|
+
},
|
|
9
|
+
"description": "A Web-based modelling environment for organising, editing, simulating, and analysing CellML files.",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"src",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://opencor.ws/",
|
|
17
|
+
"keywords": [
|
|
18
|
+
"vue",
|
|
19
|
+
"component",
|
|
20
|
+
"opencor",
|
|
21
|
+
"cellml",
|
|
22
|
+
"sed-ml",
|
|
23
|
+
"omex",
|
|
24
|
+
"combine"
|
|
25
|
+
],
|
|
26
|
+
"license": "Apache-2.0",
|
|
27
|
+
"main": "dist/opencor.umd.js",
|
|
28
|
+
"module": "dist/opencor.es.js",
|
|
29
|
+
"name": "@opencor/opencor",
|
|
30
|
+
"productName": "OpenCOR",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/opencor/webapp.git"
|
|
34
|
+
},
|
|
35
|
+
"type": "module",
|
|
36
|
+
"types": "dist/index.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"import": "./dist/opencor.es.js",
|
|
41
|
+
"require": "./dist/opencor.umd.js"
|
|
42
|
+
},
|
|
43
|
+
"./style.css": "./dist/opencor.css"
|
|
44
|
+
},
|
|
45
|
+
"version": "0.20250813.0",
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"vue": "^3.0.0"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@primeuix/themes": "^1.2.3",
|
|
51
|
+
"@primevue/auto-import-resolver": "^4.3.7",
|
|
52
|
+
"@tailwindcss/postcss": "^4.1.11",
|
|
53
|
+
"@tailwindcss/vite": "^4.1.11",
|
|
54
|
+
"@vueuse/core": "^13.6.0",
|
|
55
|
+
"js-cookie": "^3.0.5",
|
|
56
|
+
"jsonschema": "^1.5.0",
|
|
57
|
+
"mathjs": "^14.6.0",
|
|
58
|
+
"plotly.js-gl2d-dist-min": "^3.1.0",
|
|
59
|
+
"primeicons": "^7.0.0",
|
|
60
|
+
"primevue": "^4.3.7",
|
|
61
|
+
"quill": "^2.0.3",
|
|
62
|
+
"tailwindcss": "^4.1.11",
|
|
63
|
+
"tailwindcss-primeui": "^0.6.1",
|
|
64
|
+
"ua-parser-js": "^2.0.4"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@types/js-cookie": "^3.0.6",
|
|
68
|
+
"@types/node": "^24.2.1",
|
|
69
|
+
"@types/plotly.js": "^3.0.3",
|
|
70
|
+
"@vitejs/plugin-vue": "^6.0.1",
|
|
71
|
+
"@vue/eslint-config-prettier": "^10.2.0",
|
|
72
|
+
"@vue/eslint-config-typescript": "^14.6.0",
|
|
73
|
+
"@vue/tsconfig": "^0.7.0",
|
|
74
|
+
"autoprefixer": "^10.4.21",
|
|
75
|
+
"eslint": "^9.33.0",
|
|
76
|
+
"prettier": "^3.6.2",
|
|
77
|
+
"unplugin-vue-components": "^29.0.0",
|
|
78
|
+
"vite": "^7.1.2"
|
|
79
|
+
},
|
|
80
|
+
"scripts": {
|
|
81
|
+
"build": "vite build",
|
|
82
|
+
"build:lib": "vite build --config vite.lib.config.ts && cp index.d.ts dist/index.d.ts",
|
|
83
|
+
"clean": "node scripts/clean.js",
|
|
84
|
+
"dev": "vite dev",
|
|
85
|
+
"format": "prettier --log-level silent --write . && clang-format -i src/libopencor/src/*",
|
|
86
|
+
"format:check": "prettier --check . && clang-format --dry-run -Werror src/libopencor/src/*",
|
|
87
|
+
"lint": "eslint --fix .",
|
|
88
|
+
"serve": "pnpm build && vite preview"
|
|
89
|
+
}
|
|
90
|
+
}
|
package/src/App.vue
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div id="app">
|
|
3
|
+
<OpenCOR />
|
|
4
|
+
<!-- <OpenCOR omex="https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/lorenz.omex"/> -->
|
|
5
|
+
<!-- <OpenCOR omex="https://raw.githubusercontent.com/opencor/webapp/refs/heads/main/tests/models/ui/lorenz.omex"/> -->
|
|
6
|
+
<!-- <OpenCOR omex="https://models.physiomeproject.org/workspace/b7c/rawfile/e0ae8d2d56aaaa091e23e1ee7e84cacbda1dfb6b/lorenz.omex"/> -->
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup lang="ts">
|
|
11
|
+
import OpenCOR from './components/OpenCOR.vue'
|
|
12
|
+
|
|
13
|
+
function updateViewportHeight() {
|
|
14
|
+
document.documentElement.style.setProperty('--vh', `${String(window.innerHeight * 0.01)}px`)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
window.addEventListener('resize', updateViewportHeight)
|
|
18
|
+
|
|
19
|
+
updateViewportHeight()
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<style scoped>
|
|
23
|
+
#app {
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: calc(100 * var(--vh, 1vh));
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
@import 'tailwindcss';
|
|
2
|
+
@import 'tailwindcss-primeui';
|
|
3
|
+
|
|
4
|
+
:root {
|
|
5
|
+
--border-color: var(--p-content-border-color);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
body {
|
|
9
|
+
margin: 0;
|
|
10
|
+
font-family:
|
|
11
|
+
Inter,
|
|
12
|
+
-apple-system,
|
|
13
|
+
BlinkMacSystemFont,
|
|
14
|
+
'Segoe UI',
|
|
15
|
+
Roboto,
|
|
16
|
+
Oxygen,
|
|
17
|
+
Ubuntu,
|
|
18
|
+
Cantarell,
|
|
19
|
+
'Fira Sans',
|
|
20
|
+
'Droid Sans',
|
|
21
|
+
'Helvetica Neue',
|
|
22
|
+
sans-serif;
|
|
23
|
+
text-rendering: optimizeLegibility;
|
|
24
|
+
-webkit-font-smoothing: antialiased;
|
|
25
|
+
-moz-osx-font-smoothing: grayscale;
|
|
26
|
+
user-select: none;
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="OpenCOR logo" xml:space="preserve" height="704.92" width="828.12" version="1.1">
|
|
2
|
+
<defs>
|
|
3
|
+
<style>
|
|
4
|
+
@font-face {
|
|
5
|
+
font-family: "Brush Script MT";
|
|
6
|
+
src: url(data:application/font-woff;charset=utf-8;base64,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ADIvugAcACMAAyu6AAYAQgADK7gAQhC4ABPcugA7AEIABhESOTAxNzU2Ej4BMzIVFAYHDgEHPgMzMhYVFA4BBxYzMjcVDgIjIi4CJwYjIicOAgcGIyI1ND4CNxI3AgU+ATU0IyIGBzYWBIzLdlpEIjcrOW1FNo1ZVywcEUqKZSMldMNMkYA2FC0mPBAgBCMvIU82LRkKKzVNXBOeWOYBIGNhJTK1YEoy50aYAQyeQRoVUis4qYMqc0EmFB1MkZxcDbFIRHhICQ0YBQgcQMt4NxlMQo+AgyABEL/+6KtokiclpYwIBQAAAAAAAAEAAAAUAAEAAQAGAAAAAAAGAAj/5QAAAEADBgABAAAAAAAAACsAWAABAAAAAAABAA8ApAABAAAAAAACAAYAwgABAAAAAAADACsBIQABAAAAAAAEABYBewABAAAAAAAFAA8BsgABAAAAAAAGAA0B3gABAAAAAAAHADcCXAABAAAAAQACAAgELAABAAAAAQACAAgGxgABAAAAAQAEABgEZwABAAAAAQAEABgHAQABAAAAAgACAAYC/AABAAAAAgAEABYDMQABAAAAAwACAAcEkAABAAAAAwAEABcEyAABAAAABAACAAcE8AABAAAABAAEABcFKAABAAAABQACAAYFqAABAAAABQAEABYF3QABAAAABgACAAcDWAABAAAABgACAAcGZAABAAAABgAEABcDkAABAAAABgAEABcGnAABAAAABwACAAYCogABAAAABwAEABYC1wABAAAACAACAAcGBAABAAAACAAEABcGPAABAAAACQACAAYFTgABAAAACQAEABYFgwABAAAADQACAAoDvgABAAAADQAEABoD/wADAAEEBgACAAwClAADAAEEBgAEACwCqQADAAEEBwACAAwC7gADAAEEBwAEACwDAwADAAEECQAAAFYAAAADAAEECQABAB4AhAADAAEECQACAAwAtAADAAEECQADAFYAyQADAAEECQAEACwBTQADAAEECQAFAB4BkgADAAEECQAGABoBwgADAAEECQAHAG4B7AADAAEECgACAA4DSAADAAEECgAEAC4DYAADAAEECwACABQDqAADAAEECwAEADQDyQADAAEEDAACABAEGgADAAEEDAAEADAENQADAAEEEAACAA4EgAADAAEEEAAEAC4EmAADAAEEEwACAA4E4AAD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)
|
|
7
|
+
}
|
|
8
|
+
</style>
|
|
9
|
+
</defs>
|
|
10
|
+
<path id="manPath" d="m479.01,689.07c-6.711-8.5316-3.885-23.925,7.3448-40.009,6.5227-9.3421,8.5394-15.013,8.5902-24.157,0.0426-7.6638,3.5823-13.54,13.454-22.332,12.603-11.225,19.377-25.66,27.763-59.158,1.4627-5.842,3.7519-13.996,5.0871-18.12,1.3352-4.1238,3.6186-11.714,5.074-16.868,3.4-12.038,10.2-26.342,15.274-32.131,2.1902-2.4986,9.1468-8.3594,15.459-13.024,7.5348-5.5681,12.551-10.323,14.603-13.842,4.8433-8.3049,12.499-25.931,11.637-26.793-1.5593-1.5593-8.3533,2.4805-20.353,12.102-7.9026,6.3364-14.943,10.848-19.713,12.631-5.211,1.9488-9.1123,4.5679-13.104,8.7965-6.1064,6.47-9.695,7.4939-13.096,3.7364-3.1873-3.522-2.5026-8.2907,2.8215-19.652,6.2882-13.419,9.5502-17.551,18.687-23.674,8.5052-5.6997,10.366-8.3553,14.623-20.874,5.836-17.159,15.768-22.418,29.015-15.365,3.2277,1.7182,6.9977,3.1298,8.3778,3.1367,4.7076,0.0237,18.441-5.5735,20.177-8.2237,0.95053-1.4507,2.236-8.0044,2.8565-14.563,0.75928-8.0254,2.2164-14.528,4.4549-19.88,8.5121-20.354,8.5304-20.446,6.8585-34.822-1.2954-11.138-1.2334-14.789,0.41019-24.158,2.9914-17.05,8.1857-26.597,23.763-43.675,10.15-11.127,13.401-15.549,14.076-19.148,0.93499-4.9839-0.15067-31.713-1.4793-36.422-1.1495-4.0738-2.3541-3.5107-6.0757,2.84-4.3497,7.4223-17.489,21.394-23.793,25.3-2.7492,1.7039-7.9249,5.3259-11.502,8.0491-5.5424,4.2198-6.8044,5.9872-8.5417,11.963-5.1496,17.714-13.988,29.16-31.571,40.883-7.3786,4.9196-12.593,9.4637-15.164,13.215-4.5938,6.7023-11.219,22.862-11.281,27.514-0.0519,3.908,3.9652,15.954,6.7245,20.165,2.0534,3.134,1.5825,4.7101-1.4071,4.7101-0.94651,0-5.0995-2.8117-9.2288-6.2482-7.9932-6.652-11.313-7.5084-17.236-4.4457-5.2843,2.7326-16.431,15.397-22.408,25.459-2.9335,4.9379-6.1521,8.978-7.1524,8.978-2.283,0-2.3697,0.90262,1.2546-13.047,3.984-15.333,7.1237-21.29,18.763-35.593,5.2701-6.4765,10.89-14.357,12.489-17.512,4.192-8.2727,15.494-35.391,18.797-45.104,3.4554-10.159,7.8016-17.201,16.173-26.204,24.065-25.879,32.929-37.075,36.9-46.615,5.6516-13.576,15.262-28.965,26.508-42.45,5.2891-6.3415,12.037-14.569,14.996-18.283,12.466-15.65,19.098-17.962,48.492-16.903,21.374,0.77084,24.635,0.03699,26.766-6.022,1.0088-2.8684,0.57569-4.2373-2.8494-9.0065-8.1518-11.351-12.635-25.103-12.648-38.792-0.014-15.598,4.7185-25.657,14.876-31.622,5.1095-3.0004,7.224-3.4079,19.77-3.8105,0,0,8.9592,0.2885,12.471,1.2847,3.5116,0.99628,4.8222,1.4298,6.2553,2.8628,1.4331,1.4331,4.5874,6.4189,6.0012,11.378,1.162,4.0759,3.7378,10.291,5.7238,13.811,3.2609,5.7799,3.6109,7.5222,3.6109,17.975,0,14.781-1.6976,20.277-8.3457,27.02-5.7509,5.8335-7.0626,9.0047-6.4296,15.545,0.35106,3.6274,1.9723,5.3925,12.276,13.366,17.434,13.49,20.515,20.013,16.873,35.712-5.7979,24.984-16.688,44.336-36.158,64.255-10.351,10.59-12.356,13.509-23.611,34.365-6.7646,12.535-12.891,24.03-13.616,25.544-1.1628,2.4309-0.34785,3.7969,7.0001,11.733,20.255,21.879,41.128,55.237,43.922,70.201,0.48358,2.5895,0.47675,8.4665-0.0151,13.06-0.7584,7.0819-1.4928,8.9484-4.8293,12.275-6.8582,6.8369-25.179,12.375-64.199,19.406l-22.775,4.1038-8.9974,10.481c-4.9485,5.7644-11.761,12.965-15.139,16.003-3.3778,3.0369-8.3862,8.9948-11.13,13.24-5.906,9.1378-15.649,19.589-27.342,29.329-6.8075,5.6706-8.7247,8.0692-9.7711,12.225-1.6299,6.4728-10.835,21.869-21.372,35.746-10.031,13.21-33,41.835-37.601,46.861-5.7982,6.3329-15.863,24.69-23.796,43.401-4.1574,9.8069-10.563,23.489-14.235,30.405-3.6714,6.916-8.6659,17.511-11.099,23.544-8.7704,21.75-12.282,25.156-27.398,26.567-7.5393,0.70403-8.0689,0.57243-10.589-2.6314z" fill="#366092" />
|
|
11
|
+
<path id="greyDnaPath" fill="#a5a5a5" d="m564.03,260.47c-118.36,4.4375-430.18,44.788-529.25,184.25,1.3074-1.2904,2.6652-2.489,4.0312-3.5938,101.24-121.44,390.47-165.64,521.57-171.69,1.2255-2.9859,2.4343-5.9818,3.6562-8.9688zm-496.97,170.25c-15.686-0.16647-34.424,10.126-45.031,33.312-7.9791,17.44-12.616,41.654,0.34375,50.031,20.62,13.329,64.934-13.655,91.781-14.844,35.12-1.5562,5.2438,121.23,52.375,121.25-30.13-7.875-8.8325-114.3-42.062-127.56-33.301-13.294-80.6,30.822-100.78,17.375-14.828-9.88,1.292-40.04,10.351-51.78,12.401-16.08,43.904-35.53,58.813-9.53-3.236-11.64-13.581-18.12-25.782-18.25zm99.469,189.75c12.651,3.2016,23.09-9.6345,32.25-27.969,0.5587-1.1183,1.1069-2.2806,1.6562-3.4375-0.55254,1.1642-1.0942,2.3123-1.6562,3.4375-0.40776,0.81626-0.80575,1.644-1.2188,2.4375v23.594c0.14588,0.29907,0.28919,0.58447,0.4375,0.875,0.20385,0.4004,0.41686,0.80419,0.625,1.1875,0.13732,0.25268,0.26709,0.50463,0.40625,0.75,0.22094,0.38817,0.43042,0.75512,0.65625,1.125,0.12634,0.20752,0.27809,0.42237,0.40625,0.625,0.24537,0.38574,0.46728,0.76001,0.71875,1.125,0.12329,0.17823,0.24987,0.35791,0.375,0.53125,0.26611,0.36865,0.53906,0.71826,0.8125,1.0625,0.10864,0.13671,0.23388,0.2732,0.34375,0.40625,0.29174,0.35157,0.57592,0.70899,0.875,1.0312,0.10681,0.11597,0.20512,0.20138,0.3125,0.3125,0.31371,0.32349,0.64587,0.64697,0.96875,0.9375,0.0922,0.0842,0.18725,0.1682,0.28125,0.25,0.34728,0.29906,0.70362,0.58253,1.0625,0.84375,0.0726,0.0537,0.14545,0.10375,0.21875,0.15625v-53.406c2.4779-5.9788,4.8612-12.15,7.1875-18.312v71.312c0.39878-0.38384,0.79528-0.77942,1.1875-1.2188,0.31206-0.34954,0.62935-0.74156,0.9375-1.125-0.31051,0.38741-0.62299,0.77227-0.9375,1.125-0.39001,0.43739-0.79096,0.8367-1.1875,1.2188-0.99915,0.96263-2.017,1.7574-3.0625,2.3438,36.845,7.2625,43.186-120.39,81.969-135.88-16.232-3.495-28.053,10.806-37.688,31.344v-13c-2.4934-4.0796-5.4595-7.1055-9.0312-8.8438v44.156c-2.6768,7.4475-5.199,15.1-7.6562,22.656v-68.062c-0.33468,0.35491-0.69741,0.72315-1.0312,1.125,0.46534-0.56138,0.93915-1.0933,1.4062-1.5625-38.951,1.5759-42.944,118.04-71.625,116.84zm313.25-167.09c-0.24047,0.0623-0.48316,0.1706-0.71875,0.25-45.311,15.475-53.044,212.46-94.594,224.69-0.0592,0.017-0.1282,0.0141-0.1875,0.0312,0.0611,0.0256,0.1265,0.0693,0.1875,0.0937,60.972,24.462,73.98-191.37,95-224.56,0.0977-0.15381,0.2136-0.35229,0.3125-0.5zm-77.625,12.344c-46.454-0.63392-43.177,197.29-85.062,202.84,62.632,3.4058,60.715-180.97,86.156-202.78-0.37199-0.0298-0.72797-0.0575-1.0938-0.0625zm-172.56,51.375c-0.28205,0.58006-0.56136,1.1785-0.84375,1.7812v80.312c-2.1198,5.91-4.274,11.355-6.4688,16.062v-81.031c2.4735-6.317,4.8936-12.148,7.3125-17.125zm-12.04,106.9c-0.53442,0.82207-1.0794,1.5918-1.625,2.3125,0.54784-0.72162,1.0883-1.489,1.625-2.3125z" />
|
|
12
|
+
<path id="redDnaPath" fill="#953734" d="m138.79,506.86c36.515-4.4398,26.91,125.84,63.42,127.48,5.4828,0.24536,7.9876-2.638,7.9876-2.633-32.082-8.2044-23.244-153.11-72.789-127.89,0,0,1.3806,3.0481,1.3806,3.0481zm417.42,84.965c19.811,54.112,44.398,101.74,87.802,102.04-27.162-15.188-47.554-72.282-68.936-129.44-7.0508,9.2725-13.332,16.878-18.866,27.395zm-29.51,62.58c13.742,19.669,33.092,37.915,52.188,38.835-23.42,5.5005-45.488-3.1519-61.65-16.191,2.9834-5.9131,6.0254-16.956,9.4629-22.644zm-46.83-201.05c30.745-8.966,49.02,57.96,54.97,75.399,3.523-13.472,7.7808-26.171,11.266-34.974-9.1273-18.746-42.358-75.998-66.293-40.438-0.0146,0.022-0.009,0.0135-0.0244,0.0354,0.0233-0.006,0.0745-0.0208,0.0817-0.0233zm-389.52,18.338c-9.1288-30.038-53.605-21.662-73.904,25.688-8.59,20.025-3.4045,49.875,15.005,51.85,18.278,1.9544,63.08-25.884,94.562-40.154,0,0,0.99305,2.2472,0.99305,2.2472-40.202,31.22-156.88,86.395-95.096-21.715,11.522-20.162,41.856-50.915,58.439-17.915zm-49.802-31.95c103.36-114.51,411.66-147.7,512.75-151.59-3.8868,10.077-9.6631,14.556-12.739,19.656-78.036,1.9201-373.36,30.325-489.71,125.94-3.5412,1.3806-7.2339,3.7512-10.294,5.9912zm336.58,122.49v110.18c2.2412,2.3816,4.6198,4.3909,7.1649,5.9375v-153.45c3.7902-19.628,7.4872-36.824,12.047-47.952v192.05c-3.9844,5.354-9.726,10.327-16.82,9.917-60.574-3.512-56.559-154.82-83.391-180.36-1.153-1.0962-2.4988-2.0996-3.971-2.7259,1.7738-1.0327,6.33-1.6223,9.0576-1.5661,35.605,0.72754,39.414,106.93,63.865,159.3v-41.606c4.7803-15.458,8.6304-32.665,12.047-49.729zm58.612-52.331v35.481c-4.0918,16.229-8.0176,33.029-12.047,49.021v-110.62c-2.7014-4.6972-5.4516-8.5852-8.2886-11.506v152.61c-3.739,12.433-7.6929,23.558-12.047,32.415v-191.51c0.003,0.001,0.006,0.001,0.009,0.001-0.004,0-0.009-0.001-0.0125-0.001-0.0226-0.004-0.0385-0.006-0.0623-0.01,0.0244-0.0244,0.0305-0.0305,0.0549-0.0561,3.4576-3.5938,7.4054-5.741,11.979-6.0828,34.866-2.6062,57.636,76.17,85.888,142.72-8.3985,6.2036-11.223,16.429-11.675,21.378-0.4419,4.8279,0.78979,11.624-2.0105,15.44-22.281-39.828-37.268-92.562-51.788-129.29zm-187.37-11.86c54.431-4.7498,25.025,147.31,69.59,170.54-66.292,2.1692-33.405-164.74-79.802-164.92,2.0905-2.1985,6.3916-5.2771,10.212-5.6104z" />
|
|
13
|
+
<path id="opencorPath" fill="none" d="m27.782,611.49c103.7-139.25,419-177.25,535.91-181.85" />
|
|
14
|
+
<text id="opencorText" stroke-linejoin="miter" style="writing-mode:lr-tb;letter-spacing:0px;text-anchor:end;word-spacing:0px;text-align:end;" stroke-width="2.5" transform="translate(5.731,-211.10242)" font-family="Brush Script MT" xml:space="preserve" stroke-linecap="butt" font-size="160px" line-height="125%" stroke="#7f7f7f" font-stretch="normal" font-variant="normal" font-style="normal" stroke-dasharray="none" font-weight="normal" fill="#a5a5a5">
|
|
15
|
+
<textPath id="opencorTextPath" style="writing-mode:lr-tb;text-anchor:end;text-align:end;" xlink:href="#opencorPath" startOffset="100%" line-height="125%">Open<tspan id="tspan140" stroke-linejoin="miter" style="writing-mode:lr-tb;text-anchor:end;text-align:end;" stroke-width="2.5" font-family="Brush Script MT" stroke-linecap="butt" font-size="160px" line-height="125%" stroke="#244061" font-stretch="normal" font-variant="normal" font-style="normal" stroke-dasharray="none" font-weight="normal" fill="#366092">C</tspan>O<tspan id="tspan142" stroke-linejoin="miter" style="writing-mode:lr-tb;text-anchor:end;text-align:end;" stroke-width="2.5" font-family="Brush Script MT" stroke-linecap="butt" font-size="160px" line-height="125%" stroke="#632423" font-stretch="normal" font-variant="normal" font-style="normal" stroke-dasharray="none" font-weight="normal" fill="#953734">R</tspan></textPath>
|
|
16
|
+
</text>
|
|
17
|
+
</svg>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { UAParser } from 'ua-parser-js'
|
|
2
|
+
|
|
3
|
+
import { electronApi } from './electronApi.js'
|
|
4
|
+
|
|
5
|
+
// Some interfaces.
|
|
6
|
+
|
|
7
|
+
export interface ISettingsGeneral {
|
|
8
|
+
checkForUpdatesAtStartup: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ISettings {
|
|
12
|
+
general: ISettingsGeneral
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Some methods to determine the operating system, whether the application is running on a mobile device, etc.
|
|
16
|
+
|
|
17
|
+
const uaParser = new UAParser()
|
|
18
|
+
|
|
19
|
+
export function isWindows(): boolean {
|
|
20
|
+
return uaParser.getOS().name === 'Windows'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isLinux(): boolean {
|
|
24
|
+
return uaParser.getOS().name === 'Linux'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function isMacOs(): boolean {
|
|
28
|
+
return uaParser.getOS().name === 'macOS'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function isMobile(): boolean {
|
|
32
|
+
return uaParser.getDevice().type === 'mobile'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// A method to determine whether the Ctrl or Cmd key is pressed, depending on the operating system.
|
|
36
|
+
|
|
37
|
+
export function isCtrlOrCmd(event: KeyboardEvent): boolean {
|
|
38
|
+
return isMacOs() ? event.metaKey : event.ctrlKey
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// A method to enable/disable the main menu.
|
|
42
|
+
|
|
43
|
+
export function enableDisableMainMenu(enable: boolean): void {
|
|
44
|
+
electronApi?.enableDisableMainMenu(enable)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// A method to format a given number of milliseconds into a string.
|
|
48
|
+
|
|
49
|
+
export function formatTime(time: number): string {
|
|
50
|
+
const ms = Math.floor(time % 1000)
|
|
51
|
+
const s = Math.floor((time / 1000) % 60)
|
|
52
|
+
const m = Math.floor((time / (1000 * 60)) % 60)
|
|
53
|
+
const h = Math.floor((time / (1000 * 60 * 60)) % 24)
|
|
54
|
+
const d = Math.floor((time / (1000 * 60 * 60 * 24)) % 24)
|
|
55
|
+
let res = ''
|
|
56
|
+
|
|
57
|
+
if (d !== 0 || ((h !== 0 || m !== 0 || s !== 0 || ms !== 0) && res !== '')) {
|
|
58
|
+
res += `${res === '' ? '' : ' '}${String(d)}d`
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (h !== 0 || ((m !== 0 || s !== 0 || ms !== 0) && res !== '')) {
|
|
62
|
+
res += `${res === '' ? '' : ' '}${String(h)}h`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (m !== 0 || ((s !== 0 || ms !== 0) && res !== '')) {
|
|
66
|
+
res += `${res === '' ? '' : ' '}${String(m)}m`
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (s !== 0 || (ms !== 0 && res !== '')) {
|
|
70
|
+
res += `${res === '' ? '' : ' '}${String(s)}s`
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (ms !== 0 || res === '') {
|
|
74
|
+
res += `${res === '' ? '' : ' '}${String(ms)}ms`
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return res
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// A method to format an issue, i.e. make sure that it starts with a capital letter and ends with a period.
|
|
81
|
+
|
|
82
|
+
export function formatIssue(issue: string): string {
|
|
83
|
+
issue = issue.charAt(0).toUpperCase() + issue.slice(1)
|
|
84
|
+
|
|
85
|
+
return issue.endsWith('.') ? issue : `${issue}.`
|
|
86
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const URI_SCHEME = 'opencor'
|
|
2
|
+
export const FULL_URI_SCHEME = `${URI_SCHEME}://`
|
|
3
|
+
|
|
4
|
+
export const SHORT_DELAY = 69
|
|
5
|
+
export const MEDIUM_DELAY = 169
|
|
6
|
+
export const LONG_DELAY = 369
|
|
7
|
+
|
|
8
|
+
export const TOAST_LIFE = 3000
|
|
9
|
+
|
|
10
|
+
const currentYear = new Date().getFullYear()
|
|
11
|
+
|
|
12
|
+
export const COPYRIGHT = currentYear === 2025 ? '2025' : `2025-${String(currentYear)}`
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { is } from '@electron-toolkit/utils'
|
|
2
|
+
|
|
3
|
+
import electron from 'electron'
|
|
4
|
+
|
|
5
|
+
export function isPackaged(): boolean {
|
|
6
|
+
return electron.app.isPackaged
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function isDevMode(): boolean {
|
|
10
|
+
return is.dev && !!process.env.ELECTRON_RENDERER_URL
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isWindows(): boolean {
|
|
14
|
+
return process.platform === 'win32'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isLinux(): boolean {
|
|
18
|
+
return process.platform === 'linux'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isMacOs(): boolean {
|
|
22
|
+
return process.platform === 'darwin'
|
|
23
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type ISettings } from './common.js'
|
|
2
|
+
|
|
3
|
+
export interface ISplashScreenInfo {
|
|
4
|
+
copyright: string
|
|
5
|
+
version: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface IElectronApi {
|
|
9
|
+
// Note: this must be in sync with src/preload/index.ts.
|
|
10
|
+
|
|
11
|
+
// Some general methods.
|
|
12
|
+
|
|
13
|
+
operatingSystem: () => string
|
|
14
|
+
|
|
15
|
+
// Splash screen window.
|
|
16
|
+
|
|
17
|
+
onInitSplashScreenWindow: (callback: (info: ISplashScreenInfo) => void) => void
|
|
18
|
+
|
|
19
|
+
// Renderer process asking the main process to do something for it.
|
|
20
|
+
|
|
21
|
+
checkForUpdates: (atStartup: boolean) => void
|
|
22
|
+
downloadAndInstallUpdate: () => void
|
|
23
|
+
enableDisableMainMenu: (enable: boolean) => void
|
|
24
|
+
enableDisableFileCloseAndCloseAllMenuItems: (enable: boolean) => void
|
|
25
|
+
fileClosed: (filePath: string) => void
|
|
26
|
+
fileIssue: (filePath: string) => void
|
|
27
|
+
fileOpened: (filePath: string) => void
|
|
28
|
+
filePath: (file: File) => string
|
|
29
|
+
fileSelected(filePath: string): void
|
|
30
|
+
filesOpened(filePaths: string[]): void
|
|
31
|
+
installUpdateAndRestart: () => void
|
|
32
|
+
loadSettings: () => Promise<ISettings>
|
|
33
|
+
resetAll: () => void
|
|
34
|
+
saveSettings: (settings: ISettings) => void
|
|
35
|
+
|
|
36
|
+
// Renderer process listening to the main process.
|
|
37
|
+
|
|
38
|
+
onAbout: (callback: () => void) => void
|
|
39
|
+
onAction: (callback: (action: string) => void) => void
|
|
40
|
+
onCheckForUpdates: (callback: () => void) => void
|
|
41
|
+
onEnableDisableUi: (callback: (enable: boolean) => void) => void
|
|
42
|
+
onOpen: (callback: (filePath: string) => void) => void
|
|
43
|
+
onOpenRemote: (callback: () => void) => void
|
|
44
|
+
onOpenSampleLorenz: (callback: () => void) => void
|
|
45
|
+
onOpenSampleInteractiveLorenz: (callback: () => void) => void
|
|
46
|
+
onClose: (callback: () => void) => void
|
|
47
|
+
onCloseAll: (callback: () => void) => void
|
|
48
|
+
onResetAll: (callback: () => void) => void
|
|
49
|
+
onSelect: (callback: (filePath: string) => void) => void
|
|
50
|
+
onSettings: (callback: () => void) => void
|
|
51
|
+
onUpdateAvailable: (callback: (version: string) => void) => void
|
|
52
|
+
onUpdateCheckError: (callback: (issue: string) => void) => void
|
|
53
|
+
onUpdateDownloaded: (callback: () => void) => void
|
|
54
|
+
onUpdateDownloadError: (callback: (issue: string) => void) => void
|
|
55
|
+
onUpdateDownloadProgress: (callback: (percent: number) => void) => void
|
|
56
|
+
onUpdateNotAvailable: (callback: () => void) => void
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface IWindow {
|
|
60
|
+
electronApi: IElectronApi
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const electronApi: IElectronApi | undefined = (window as unknown as IWindow).electronApi
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { electronApi } from './electronApi.js'
|
|
2
|
+
import * as locApi from '../libopencor/locApi.js'
|
|
3
|
+
|
|
4
|
+
// Some file-related methods.
|
|
5
|
+
|
|
6
|
+
export function proxyUrl(url: string): string {
|
|
7
|
+
return `https://corsproxy.io/?url=${encodeURIComponent(url)}`
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function isRemoteFilePath(filePath: string): boolean {
|
|
11
|
+
return filePath.startsWith('http://') || filePath.startsWith('https://')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function filePath(fileOrFilePath: string | File): string {
|
|
15
|
+
return fileOrFilePath instanceof File
|
|
16
|
+
? electronApi !== undefined
|
|
17
|
+
? electronApi.filePath(fileOrFilePath)
|
|
18
|
+
: fileOrFilePath.name
|
|
19
|
+
: fileOrFilePath
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function file(fileOrFilePath: string | File): Promise<locApi.File> {
|
|
23
|
+
if (typeof fileOrFilePath === 'string') {
|
|
24
|
+
if (isRemoteFilePath(fileOrFilePath)) {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
fetch(proxyUrl(fileOrFilePath))
|
|
27
|
+
.then((response) => {
|
|
28
|
+
if (response.ok) {
|
|
29
|
+
return response.arrayBuffer()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
throw new Error(`The server responded with a status of ${String(response.status)}.`)
|
|
33
|
+
})
|
|
34
|
+
.then((arrayBuffer) => {
|
|
35
|
+
const fileContents = new Uint8Array(arrayBuffer)
|
|
36
|
+
|
|
37
|
+
resolve(new locApi.File(filePath(fileOrFilePath), fileContents))
|
|
38
|
+
})
|
|
39
|
+
.catch((error: unknown) => {
|
|
40
|
+
reject(error instanceof Error ? error : new Error(String(error)))
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
if (electronApi !== undefined) {
|
|
47
|
+
resolve(new locApi.File(filePath(fileOrFilePath)))
|
|
48
|
+
} else {
|
|
49
|
+
reject(new Error('Local files cannot be opened.'))
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
fileOrFilePath
|
|
56
|
+
.arrayBuffer()
|
|
57
|
+
.then((arrayBuffer) => {
|
|
58
|
+
const fileContents = new Uint8Array(arrayBuffer)
|
|
59
|
+
|
|
60
|
+
resolve(new locApi.File(filePath(fileOrFilePath), fileContents))
|
|
61
|
+
})
|
|
62
|
+
.catch((error: unknown) => {
|
|
63
|
+
reject(error instanceof Error ? error : new Error(String(error)))
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// A method to retrieve the simulation data information for a given name from an instance task.
|
|
69
|
+
|
|
70
|
+
export enum ESimulationDataInfoType {
|
|
71
|
+
UNKNOWN,
|
|
72
|
+
VOI,
|
|
73
|
+
STATE,
|
|
74
|
+
RATE,
|
|
75
|
+
CONSTANT,
|
|
76
|
+
COMPUTED_CONSTANT,
|
|
77
|
+
ALGEBRAIC
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface ISimulationDataInfo {
|
|
81
|
+
type: ESimulationDataInfoType
|
|
82
|
+
index: number
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function simulationDataInfo(instanceTask: locApi.SedInstanceTask, name: string): ISimulationDataInfo {
|
|
86
|
+
if (name === '') {
|
|
87
|
+
return {
|
|
88
|
+
type: ESimulationDataInfoType.UNKNOWN,
|
|
89
|
+
index: -1
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (name === instanceTask.voiName()) {
|
|
94
|
+
return {
|
|
95
|
+
type: ESimulationDataInfoType.VOI,
|
|
96
|
+
index: -1
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (let i = 0; i < instanceTask.stateCount(); i++) {
|
|
101
|
+
if (name === instanceTask.stateName(i)) {
|
|
102
|
+
return {
|
|
103
|
+
type: ESimulationDataInfoType.STATE,
|
|
104
|
+
index: i
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for (let i = 0; i < instanceTask.rateCount(); i++) {
|
|
110
|
+
if (name === instanceTask.rateName(i)) {
|
|
111
|
+
return {
|
|
112
|
+
type: ESimulationDataInfoType.RATE,
|
|
113
|
+
index: i
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
for (let i = 0; i < instanceTask.constantCount(); i++) {
|
|
119
|
+
if (name === instanceTask.constantName(i)) {
|
|
120
|
+
return {
|
|
121
|
+
type: ESimulationDataInfoType.CONSTANT,
|
|
122
|
+
index: i
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (let i = 0; i < instanceTask.computedConstantCount(); i++) {
|
|
128
|
+
if (name === instanceTask.computedConstantName(i)) {
|
|
129
|
+
return {
|
|
130
|
+
type: ESimulationDataInfoType.COMPUTED_CONSTANT,
|
|
131
|
+
index: i
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
for (let i = 0; i < instanceTask.algebraicCount(); i++) {
|
|
137
|
+
if (name === instanceTask.algebraicName(i)) {
|
|
138
|
+
return {
|
|
139
|
+
type: ESimulationDataInfoType.ALGEBRAIC,
|
|
140
|
+
index: i
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
type: ESimulationDataInfoType.UNKNOWN,
|
|
147
|
+
index: -1
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// A method to retrieve the simulation data for a given name from an instance task.
|
|
152
|
+
|
|
153
|
+
export function simulationData(instanceTask: locApi.SedInstanceTask, info: ISimulationDataInfo): number[] {
|
|
154
|
+
switch (info.type) {
|
|
155
|
+
case ESimulationDataInfoType.VOI:
|
|
156
|
+
return instanceTask.voi()
|
|
157
|
+
case ESimulationDataInfoType.STATE:
|
|
158
|
+
return instanceTask.state(info.index)
|
|
159
|
+
case ESimulationDataInfoType.RATE:
|
|
160
|
+
return instanceTask.rate(info.index)
|
|
161
|
+
case ESimulationDataInfoType.CONSTANT:
|
|
162
|
+
return instanceTask.constant(info.index)
|
|
163
|
+
case ESimulationDataInfoType.COMPUTED_CONSTANT:
|
|
164
|
+
return instanceTask.computedConstant(info.index)
|
|
165
|
+
case ESimulationDataInfoType.ALGEBRAIC:
|
|
166
|
+
return instanceTask.algebraic(info.index)
|
|
167
|
+
default:
|
|
168
|
+
return []
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import jsCookie from 'js-cookie'
|
|
2
|
+
|
|
3
|
+
import { type ISettings, type ISettingsGeneral } from './common.js'
|
|
4
|
+
import { electronApi } from './electronApi.js'
|
|
5
|
+
|
|
6
|
+
class Settings {
|
|
7
|
+
private static _instance: Settings | null = null
|
|
8
|
+
private _settings!: ISettings
|
|
9
|
+
private _isInitialised = false
|
|
10
|
+
private _initialisationListeners: (() => void)[] = []
|
|
11
|
+
|
|
12
|
+
private constructor() {
|
|
13
|
+
// Start with some default settings and then load them.
|
|
14
|
+
// Note: to have default settings is critical when running the desktop version of OpenCOR since they are loaded
|
|
15
|
+
// asynchronously, so we need to ensure that our settings are always defined. This is not the case for the
|
|
16
|
+
// web version of OpenCOR, where we can load our settings directly from the cookies.
|
|
17
|
+
|
|
18
|
+
this.reset()
|
|
19
|
+
this.load()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static instance(): Settings {
|
|
23
|
+
this._instance ??= new Settings()
|
|
24
|
+
|
|
25
|
+
return this._instance
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private emitInitialised(): void {
|
|
29
|
+
this._isInitialised = true
|
|
30
|
+
|
|
31
|
+
this._initialisationListeners.forEach((callback) => {
|
|
32
|
+
callback()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
this._initialisationListeners = []
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
onInitialised(callback: () => void): void {
|
|
39
|
+
if (this._isInitialised) {
|
|
40
|
+
callback()
|
|
41
|
+
} else {
|
|
42
|
+
this._initialisationListeners.push(callback)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
load(): void {
|
|
47
|
+
if (electronApi !== undefined) {
|
|
48
|
+
void electronApi.loadSettings().then((settings: ISettings) => {
|
|
49
|
+
this._settings = settings
|
|
50
|
+
|
|
51
|
+
this.emitInitialised()
|
|
52
|
+
})
|
|
53
|
+
} else {
|
|
54
|
+
const cookieData = jsCookie.get('settings')
|
|
55
|
+
|
|
56
|
+
if (cookieData !== undefined) {
|
|
57
|
+
try {
|
|
58
|
+
this._settings = JSON.parse(cookieData)
|
|
59
|
+
} catch (error: unknown) {
|
|
60
|
+
console.error('Failed to parse settings from cookie, so resetting to defaults:', error)
|
|
61
|
+
|
|
62
|
+
this.reset()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.emitInitialised()
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
save(): void {
|
|
71
|
+
if (electronApi !== undefined) {
|
|
72
|
+
electronApi.saveSettings(this._settings)
|
|
73
|
+
} else {
|
|
74
|
+
jsCookie.set('settings', JSON.stringify(this._settings), { expires: 365 })
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
reset(): void {
|
|
79
|
+
this._settings = {
|
|
80
|
+
general: {
|
|
81
|
+
checkForUpdatesAtStartup: true
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
toString(): string {
|
|
87
|
+
return JSON.stringify(this._settings, null, 2)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
get general(): ISettingsGeneral {
|
|
91
|
+
return this._settings.general
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const settings = Settings.instance()
|