From 79224f4f9a6f2c5df2510bd35196734fea49d20d Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Sun, 29 Nov 2015 18:44:59 -0800 Subject: [PATCH] more react changes, incomplete --- .babelrc | 20 + .eslintrc | 21 + .gitignore | 5 - .travis.yml | 2 - app/icons/bin.svg | 7 - app/icons/cogs.svg | 6 - app/icons/coriolis.svg | 8 - app/icons/download.svg | 6 - app/icons/eddb.svg | 28 -- app/icons/embed.svg | 4 - app/icons/equalizer.svg | 3 - app/icons/floppy-disk.svg | 3 - app/icons/fuel.svg | 3 - app/icons/github-mark.svg | 3 - app/icons/hammer.svg | 6 - app/icons/infinite.svg | 5 - app/icons/info.svg | 8 - app/icons/link.svg | 7 - app/icons/mount-F.svg | 7 - app/icons/mount-G.svg | 4 - app/icons/mount-T.svg | 5 - app/icons/no-power.svg | 3 - app/icons/notification.svg | 6 - app/icons/power.svg | 3 - app/icons/question.svg | 6 - app/icons/rocket.svg | 6 - app/icons/spinner11.svg | 3 - app/icons/station-coriolis.svg | 6 - app/icons/station-ocellus.svg | 7 - app/icons/station-orbis.svg | 6 - app/icons/station-outpost.svg | 7 - app/icons/stats-bars.svg | 6 - app/icons/switch.svg | 4 - app/icons/upload.svg | 6 - app/icons/warning.svg | 8 - app/js/Coriolis.jsx | 55 --- app/js/components/Header.jsx | 118 ----- .../components/directive-component-select.js | 90 ---- app/js/components/directive-header.js | 114 ----- app/js/components/directive-loader.js | 9 - app/js/components/directive-slot-hardpoint.js | 13 - app/js/components/directive-slot-internal.js | 13 - app/js/i18n/Language.js | 52 --- app/js/old-app.js | 114 ----- app/js/pages/NotFoundPage.jsx | 12 - app/js/pages/ShipyardPage.jsx | 180 ------- app/js/pages/controller-delete.js | 7 - app/js/pages/controller-error.js | 29 -- app/js/pages/controller-export.js | 19 - app/js/pages/controller-import.js | 316 ------------- app/js/pages/controller-link.js | 16 - app/js/pages/controller-modal.js | 14 - app/js/utils/ShortenUrl.js | 10 - app/less/background-images.less | 8 - app/less/fonts.less | 26 -- app/views/_modal.html | 3 - app/views/_slot-hardpoint.html | 17 - app/views/_slot-internal.html | 22 - app/views/modal-about.html | 29 -- app/views/modal-delete.html | 4 - app/views/modal-export.html | 6 - app/views/modal-import.html | 46 -- app/views/modal-link.html | 9 - app/views/page-comparison.html | 74 --- app/views/page-error.html | 21 - devServer.js | 27 ++ gulpfile.js | 281 ----------- nginx.conf | 58 --- package.json | 64 +-- scripts/json-to-db.js | 90 ---- src/app/Coriolis.jsx | 110 +++++ {app/js => src/app}/Router.js | 24 +- src/app/components/ActiveLink.jsx | 20 + src/app/components/AvailableModulesMenu.jsx | 103 ++++ src/app/components/HardpointSlot.jsx | 38 ++ src/app/components/HardpointsSlotSection.jsx | 87 ++++ src/app/components/Header.jsx | 251 ++++++++++ src/app/components/InternalSlot.jsx | 38 ++ src/app/components/InternalSlotSection.jsx | 69 +++ src/app/components/Link.jsx | 31 ++ src/app/components/ModalDeleteAll.jsx | 22 + src/app/components/ModalExport.jsx | 49 ++ src/app/components/ModalImport.jsx | 439 ++++++++++++++++++ src/app/components/ModalPermalink.jsx | 41 ++ src/app/components/ShipSummaryTable.jsx | 94 ++++ src/app/components/Slot.jsx | 61 +++ src/app/components/SlotSection.jsx | 73 +++ src/app/components/StandardSlot.jsx | 60 +++ src/app/components/StandardSlotSection.jsx | 167 +++++++ src/app/components/SvgIcons.jsx | 302 ++++++++++++ src/app/components/TranslatedComponent.jsx | 24 + src/app/components/UtilitySlotSection.jsx | 64 +++ .../app}/components/directive-area-chart.js | 0 .../app}/components/directive-bar-chart.js | 0 .../components/directive-comparison-table.js | 0 .../app}/components/directive-line-chart.js | 0 .../app}/components/directive-power-bands.js | 0 .../app}/components/directive-slider.js | 0 src/app/i18n/Language.jsx | 72 +++ {app/js => src/app}/i18n/de.js | 0 {app/js => src/app}/i18n/en.js | 0 {app/js => src/app}/i18n/es.js | 0 {app/js => src/app}/i18n/fr.js | 0 {app/js => src/app}/i18n/it.js | 0 {app/js => src/app}/i18n/ru.js | 0 src/app/index.js | 6 + src/app/pages/AboutPage.jsx | 41 ++ src/app/pages/ComparisonPage.jsx | 216 +++++++++ src/app/pages/ErrorPage.jsx | 61 +++ src/app/pages/NotFoundPage.jsx | 16 + src/app/pages/OutfittingPage.jsx | 132 ++++++ src/app/pages/Page.jsx | 36 ++ src/app/pages/ShipyardPage.jsx | 235 ++++++++++ .../app}/pages/controller-comparison.js | 0 .../js => src/app}/pages/controller-outfit.js | 0 {app/js => src/app}/shipyard/Calculations.js | 0 {app/js => src/app}/shipyard/Constants.js | 3 +- {app/js => src/app}/shipyard/ModuleSet.js | 10 +- {app/js => src/app}/shipyard/ModuleUtils.js | 47 +- src/app/shipyard/Modules.js | 96 ++++ {app/js => src/app/shipyard}/Serializer.js | 14 +- {app/js => src/app}/shipyard/Ship.js | 99 ++-- src/app/shipyard/Ships.js | 59 +++ {app/js => src/app}/stores/Persist.js | 71 ++- {app/js => src/app}/utils/BBCode.js | 0 src/app/utils/InterfaceEvents.js | 39 ++ src/app/utils/ShortenUrl.js | 19 + src/app/utils/shallowEqual.js | 27 ++ {app => src}/fonts/eurostile.eot | Bin {app => src}/fonts/eurostile.svg | 0 {app => src}/fonts/eurostile.ttf | Bin {app => src}/fonts/eurostile.woff | Bin {app => src}/fonts/eurostile.woff2 | Bin .../fonts/orbitron-regular-webfont.eot | Bin .../fonts/orbitron-regular-webfont.svg | 0 .../fonts/orbitron-regular-webfont.ttf | Bin .../fonts/orbitron-regular-webfont.woff | Bin .../fonts/orbitron-regular-webfont.woff2 | Bin {app => src}/images/logo/144x144.png | Bin {app => src}/images/logo/192x192.png | Bin {app => src}/images/logo/72x72.png | Bin {app => src}/images/logo/96x96.png | Bin .../logo/apple-touch-icon-precomposed.png | Bin {app => src}/images/logo/apple-touch-icon.png | Bin {app => src}/images/logo/browserconfig.xml | 0 {app => src}/images/logo/favicon.ico | Bin {app => src}/images/logo/manifest.json | 0 {app => src}/images/logo/mstile-144x144.png | Bin {app => src}/images/logo/mstile-150x150.png | Bin {app => src}/images/logo/mstile-310x150.png | Bin {app => src}/images/logo/mstile-310x310.png | Bin {app => src}/images/logo/mstile-70x70.png | Bin {app => src}/images/splash/1024x748.png | Bin {app => src}/images/splash/1136x640.png | Bin {app => src}/images/splash/1242x2148.png | Bin {app => src}/images/splash/1280x720.png | Bin {app => src}/images/splash/1334x750.png | Bin {app => src}/images/splash/1536x2008.png | Bin {app => src}/images/splash/200x320.png | Bin {app => src}/images/splash/2048x1496.png | Bin {app => src}/images/splash/2208x1242.png | Bin {app => src}/images/splash/320x200.png | Bin {app => src}/images/splash/320x460.png | Bin {app => src}/images/splash/320x480.png | Bin {app => src}/images/splash/480x320.png | Bin {app => src}/images/splash/480x800.png | Bin {app => src}/images/splash/640x1096.png | Bin {app => src}/images/splash/640x920.png | Bin {app => src}/images/splash/720x1280.png | Bin {app => src}/images/splash/750x1294.png | Bin {app => src}/images/splash/768x1004.png | Bin {app => src}/images/splash/800x480.png | Bin {app => src}/images/splash/960x640.png | Bin {app => src}/index.html | 15 +- {app => src}/less/app.less | 16 +- {app => src}/less/buttons.less | 0 {app => src}/less/chart-tooltip.less | 0 {app => src}/less/charts.less | 0 {app => src}/less/colors.less | 0 {app => src}/less/comparison.less | 0 {app => src}/less/error.less | 0 src/less/fonts.less | 26 ++ {app => src}/less/header.less | 1 + {app => src}/less/icons.less | 0 {app => src}/less/list.less | 0 {app => src}/less/loader.less | 2 +- {app => src}/less/modal.less | 3 - {app => src}/less/outfit.less | 0 {app => src}/less/responsive.less | 0 {app => src}/less/select.less | 0 {app => src}/less/shipyard.less | 0 {app => src}/less/slider.less | 0 {app => src}/less/slot.less | 0 {app => src}/less/sortable.less | 1 + {app => src}/less/table.less | 0 {app => src}/less/utilities.less | 0 {app => src}/schemas/ship-loadout/1.json | 0 {app => src}/schemas/ship-loadout/2.json | 0 {app => src}/views/page-outfit.html | 91 ---- webpack.config.dev.js | 41 ++ webpack.config.prod.js | 57 +++ 201 files changed, 3594 insertions(+), 2329 deletions(-) create mode 100644 .babelrc create mode 100644 .eslintrc delete mode 100755 app/icons/bin.svg delete mode 100755 app/icons/cogs.svg delete mode 100755 app/icons/coriolis.svg delete mode 100755 app/icons/download.svg delete mode 100644 app/icons/eddb.svg delete mode 100755 app/icons/embed.svg delete mode 100644 app/icons/equalizer.svg delete mode 100755 app/icons/floppy-disk.svg delete mode 100755 app/icons/fuel.svg delete mode 100755 app/icons/github-mark.svg delete mode 100755 app/icons/hammer.svg delete mode 100755 app/icons/infinite.svg delete mode 100755 app/icons/info.svg delete mode 100755 app/icons/link.svg delete mode 100755 app/icons/mount-F.svg delete mode 100755 app/icons/mount-G.svg delete mode 100755 app/icons/mount-T.svg delete mode 100644 app/icons/no-power.svg delete mode 100755 app/icons/notification.svg delete mode 100644 app/icons/power.svg delete mode 100755 app/icons/question.svg delete mode 100755 app/icons/rocket.svg delete mode 100755 app/icons/spinner11.svg delete mode 100644 app/icons/station-coriolis.svg delete mode 100644 app/icons/station-ocellus.svg delete mode 100644 app/icons/station-orbis.svg delete mode 100644 app/icons/station-outpost.svg delete mode 100755 app/icons/stats-bars.svg delete mode 100755 app/icons/switch.svg delete mode 100755 app/icons/upload.svg delete mode 100755 app/icons/warning.svg delete mode 100644 app/js/Coriolis.jsx delete mode 100644 app/js/components/Header.jsx delete mode 100755 app/js/components/directive-component-select.js delete mode 100755 app/js/components/directive-header.js delete mode 100644 app/js/components/directive-loader.js delete mode 100755 app/js/components/directive-slot-hardpoint.js delete mode 100755 app/js/components/directive-slot-internal.js delete mode 100644 app/js/i18n/Language.js delete mode 100755 app/js/old-app.js delete mode 100644 app/js/pages/NotFoundPage.jsx delete mode 100755 app/js/pages/ShipyardPage.jsx delete mode 100755 app/js/pages/controller-delete.js delete mode 100755 app/js/pages/controller-error.js delete mode 100755 app/js/pages/controller-export.js delete mode 100755 app/js/pages/controller-import.js delete mode 100755 app/js/pages/controller-link.js delete mode 100755 app/js/pages/controller-modal.js delete mode 100644 app/js/utils/ShortenUrl.js delete mode 100755 app/less/background-images.less delete mode 100755 app/less/fonts.less delete mode 100755 app/views/_modal.html delete mode 100755 app/views/_slot-hardpoint.html delete mode 100755 app/views/_slot-internal.html delete mode 100755 app/views/modal-about.html delete mode 100755 app/views/modal-delete.html delete mode 100755 app/views/modal-export.html delete mode 100755 app/views/modal-import.html delete mode 100755 app/views/modal-link.html delete mode 100755 app/views/page-comparison.html delete mode 100755 app/views/page-error.html create mode 100644 devServer.js delete mode 100755 gulpfile.js delete mode 100755 nginx.conf delete mode 100755 scripts/json-to-db.js create mode 100644 src/app/Coriolis.jsx rename {app/js => src/app}/Router.js (93%) create mode 100644 src/app/components/ActiveLink.jsx create mode 100644 src/app/components/AvailableModulesMenu.jsx create mode 100644 src/app/components/HardpointSlot.jsx create mode 100644 src/app/components/HardpointsSlotSection.jsx create mode 100644 src/app/components/Header.jsx create mode 100644 src/app/components/InternalSlot.jsx create mode 100644 src/app/components/InternalSlotSection.jsx create mode 100644 src/app/components/Link.jsx create mode 100644 src/app/components/ModalDeleteAll.jsx create mode 100644 src/app/components/ModalExport.jsx create mode 100644 src/app/components/ModalImport.jsx create mode 100644 src/app/components/ModalPermalink.jsx create mode 100644 src/app/components/ShipSummaryTable.jsx create mode 100644 src/app/components/Slot.jsx create mode 100644 src/app/components/SlotSection.jsx create mode 100644 src/app/components/StandardSlot.jsx create mode 100644 src/app/components/StandardSlotSection.jsx create mode 100644 src/app/components/SvgIcons.jsx create mode 100644 src/app/components/TranslatedComponent.jsx create mode 100644 src/app/components/UtilitySlotSection.jsx rename {app/js => src/app}/components/directive-area-chart.js (100%) rename {app/js => src/app}/components/directive-bar-chart.js (100%) rename {app/js => src/app}/components/directive-comparison-table.js (100%) rename {app/js => src/app}/components/directive-line-chart.js (100%) rename {app/js => src/app}/components/directive-power-bands.js (100%) rename {app/js => src/app}/components/directive-slider.js (100%) create mode 100644 src/app/i18n/Language.jsx rename {app/js => src/app}/i18n/de.js (100%) rename {app/js => src/app}/i18n/en.js (100%) rename {app/js => src/app}/i18n/es.js (100%) rename {app/js => src/app}/i18n/fr.js (100%) rename {app/js => src/app}/i18n/it.js (100%) rename {app/js => src/app}/i18n/ru.js (100%) create mode 100644 src/app/index.js create mode 100644 src/app/pages/AboutPage.jsx create mode 100644 src/app/pages/ComparisonPage.jsx create mode 100644 src/app/pages/ErrorPage.jsx create mode 100644 src/app/pages/NotFoundPage.jsx create mode 100644 src/app/pages/OutfittingPage.jsx create mode 100644 src/app/pages/Page.jsx create mode 100755 src/app/pages/ShipyardPage.jsx rename {app/js => src/app}/pages/controller-comparison.js (100%) rename {app/js => src/app}/pages/controller-outfit.js (100%) rename {app/js => src/app}/shipyard/Calculations.js (100%) rename {app/js => src/app}/shipyard/Constants.js (98%) rename {app/js => src/app}/shipyard/ModuleSet.js (95%) rename {app/js => src/app}/shipyard/ModuleUtils.js (88%) create mode 100644 src/app/shipyard/Modules.js rename {app/js => src/app/shipyard}/Serializer.js (95%) mode change 100755 => 100644 rename {app/js => src/app}/shipyard/Ship.js (85%) create mode 100644 src/app/shipyard/Ships.js rename {app/js => src/app}/stores/Persist.js (81%) rename {app/js => src/app}/utils/BBCode.js (100%) create mode 100644 src/app/utils/InterfaceEvents.js create mode 100644 src/app/utils/ShortenUrl.js create mode 100644 src/app/utils/shallowEqual.js rename {app => src}/fonts/eurostile.eot (100%) rename {app => src}/fonts/eurostile.svg (100%) rename {app => src}/fonts/eurostile.ttf (100%) rename {app => src}/fonts/eurostile.woff (100%) rename {app => src}/fonts/eurostile.woff2 (100%) rename {app => src}/fonts/orbitron-regular-webfont.eot (100%) rename {app => src}/fonts/orbitron-regular-webfont.svg (100%) rename {app => src}/fonts/orbitron-regular-webfont.ttf (100%) rename {app => src}/fonts/orbitron-regular-webfont.woff (100%) rename {app => src}/fonts/orbitron-regular-webfont.woff2 (100%) rename {app => src}/images/logo/144x144.png (100%) rename {app => src}/images/logo/192x192.png (100%) rename {app => src}/images/logo/72x72.png (100%) rename {app => src}/images/logo/96x96.png (100%) rename {app => src}/images/logo/apple-touch-icon-precomposed.png (100%) rename {app => src}/images/logo/apple-touch-icon.png (100%) rename {app => src}/images/logo/browserconfig.xml (100%) rename {app => src}/images/logo/favicon.ico (100%) rename {app => src}/images/logo/manifest.json (100%) rename {app => src}/images/logo/mstile-144x144.png (100%) rename {app => src}/images/logo/mstile-150x150.png (100%) rename {app => src}/images/logo/mstile-310x150.png (100%) rename {app => src}/images/logo/mstile-310x310.png (100%) rename {app => src}/images/logo/mstile-70x70.png (100%) rename {app => src}/images/splash/1024x748.png (100%) rename {app => src}/images/splash/1136x640.png (100%) rename {app => src}/images/splash/1242x2148.png (100%) rename {app => src}/images/splash/1280x720.png (100%) rename {app => src}/images/splash/1334x750.png (100%) rename {app => src}/images/splash/1536x2008.png (100%) rename {app => src}/images/splash/200x320.png (100%) rename {app => src}/images/splash/2048x1496.png (100%) rename {app => src}/images/splash/2208x1242.png (100%) rename {app => src}/images/splash/320x200.png (100%) rename {app => src}/images/splash/320x460.png (100%) rename {app => src}/images/splash/320x480.png (100%) rename {app => src}/images/splash/480x320.png (100%) rename {app => src}/images/splash/480x800.png (100%) rename {app => src}/images/splash/640x1096.png (100%) rename {app => src}/images/splash/640x920.png (100%) rename {app => src}/images/splash/720x1280.png (100%) rename {app => src}/images/splash/750x1294.png (100%) rename {app => src}/images/splash/768x1004.png (100%) rename {app => src}/images/splash/800x480.png (100%) rename {app => src}/images/splash/960x640.png (100%) rename {app => src}/index.html (93%) rename {app => src}/less/app.less (92%) rename {app => src}/less/buttons.less (100%) rename {app => src}/less/chart-tooltip.less (100%) rename {app => src}/less/charts.less (100%) rename {app => src}/less/colors.less (100%) rename {app => src}/less/comparison.less (100%) rename {app => src}/less/error.less (100%) create mode 100755 src/less/fonts.less rename {app => src}/less/header.less (99%) rename {app => src}/less/icons.less (100%) rename {app => src}/less/list.less (100%) rename {app => src}/less/loader.less (96%) rename {app => src}/less/modal.less (96%) rename {app => src}/less/outfit.less (100%) rename {app => src}/less/responsive.less (100%) rename {app => src}/less/select.less (100%) rename {app => src}/less/shipyard.less (100%) rename {app => src}/less/slider.less (100%) rename {app => src}/less/slot.less (100%) rename {app => src}/less/sortable.less (95%) rename {app => src}/less/table.less (100%) rename {app => src}/less/utilities.less (100%) rename {app => src}/schemas/ship-loadout/1.json (100%) rename {app => src}/schemas/ship-loadout/2.json (100%) rename {app => src}/views/page-outfit.html (82%) create mode 100644 webpack.config.dev.js create mode 100644 webpack.config.prod.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..a3a2c1d4 --- /dev/null +++ b/.babelrc @@ -0,0 +1,20 @@ +{ + "stage": 0, + "env": { + "development": { + "plugins": ["react-transform"], + "extra": { + "react-transform": { + "transforms": [{ + "transform": "react-transform-hmr", + "imports": ["react"], + "locals": ["module"] + }, { + "transform": "react-transform-catch-errors", + "imports": ["react", "redbox-react"] + }] + } + } + } + } +} diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..329eec0b --- /dev/null +++ b/.eslintrc @@ -0,0 +1,21 @@ +{ + "ecmaFeatures": { + "jsx": true, + "modules": true + }, + "env": { + "browser": true, + "node": true + }, + "parser": "babel-eslint", + "rules": { + "quotes": [2, "single"], + "strict": [2, "never"], + "react/jsx-uses-react": 2, + "react/jsx-uses-vars": 2, + "react/react-in-jsx-scope": 2 + }, + "plugins": [ + "react" + ] +} diff --git a/.gitignore b/.gitignore index a06816f3..e5c4dc84 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,5 @@ node_modules -bower_components -bower_components/* build .DS_Store *.log -app/js/db.js -app/db.json nginx.pid -template_cache.js \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 52561dc0..e573baac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,12 +7,10 @@ node_js: cache: directories: - node_modules - - bower_components before_script: - npm install -g gulp - npm install -g bower - - bower install script: - gulp lint - gulp build-prod diff --git a/app/icons/bin.svg b/app/icons/bin.svg deleted file mode 100755 index 4b05b645..00000000 --- a/app/icons/bin.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/app/icons/cogs.svg b/app/icons/cogs.svg deleted file mode 100755 index f065a951..00000000 --- a/app/icons/cogs.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/icons/coriolis.svg b/app/icons/coriolis.svg deleted file mode 100755 index 471b720d..00000000 --- a/app/icons/coriolis.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/icons/download.svg b/app/icons/download.svg deleted file mode 100755 index 10bc0a02..00000000 --- a/app/icons/download.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/icons/eddb.svg b/app/icons/eddb.svg deleted file mode 100644 index 81baeb6a..00000000 --- a/app/icons/eddb.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - diff --git a/app/icons/embed.svg b/app/icons/embed.svg deleted file mode 100755 index 35df51e9..00000000 --- a/app/icons/embed.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/icons/equalizer.svg b/app/icons/equalizer.svg deleted file mode 100644 index b1d72f2b..00000000 --- a/app/icons/equalizer.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/app/icons/floppy-disk.svg b/app/icons/floppy-disk.svg deleted file mode 100755 index dabe06b3..00000000 --- a/app/icons/floppy-disk.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/icons/fuel.svg b/app/icons/fuel.svg deleted file mode 100755 index 69ff2074..00000000 --- a/app/icons/fuel.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/icons/github-mark.svg b/app/icons/github-mark.svg deleted file mode 100755 index 4aca53bf..00000000 --- a/app/icons/github-mark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/icons/hammer.svg b/app/icons/hammer.svg deleted file mode 100755 index 3bac473c..00000000 --- a/app/icons/hammer.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/icons/infinite.svg b/app/icons/infinite.svg deleted file mode 100755 index 7eb3a117..00000000 --- a/app/icons/infinite.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/app/icons/info.svg b/app/icons/info.svg deleted file mode 100755 index 7571aede..00000000 --- a/app/icons/info.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/app/icons/link.svg b/app/icons/link.svg deleted file mode 100755 index 8b24b301..00000000 --- a/app/icons/link.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/app/icons/mount-F.svg b/app/icons/mount-F.svg deleted file mode 100755 index 7e5fd98d..00000000 --- a/app/icons/mount-F.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/icons/mount-G.svg b/app/icons/mount-G.svg deleted file mode 100755 index f57ffd33..00000000 --- a/app/icons/mount-G.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/icons/mount-T.svg b/app/icons/mount-T.svg deleted file mode 100755 index bb301efe..00000000 --- a/app/icons/mount-T.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/icons/no-power.svg b/app/icons/no-power.svg deleted file mode 100644 index 00f7a9b5..00000000 --- a/app/icons/no-power.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/icons/notification.svg b/app/icons/notification.svg deleted file mode 100755 index 2c9c22fd..00000000 --- a/app/icons/notification.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/icons/power.svg b/app/icons/power.svg deleted file mode 100644 index 08d19243..00000000 --- a/app/icons/power.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/icons/question.svg b/app/icons/question.svg deleted file mode 100755 index 4eec41ab..00000000 --- a/app/icons/question.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/icons/rocket.svg b/app/icons/rocket.svg deleted file mode 100755 index af2684f1..00000000 --- a/app/icons/rocket.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/icons/spinner11.svg b/app/icons/spinner11.svg deleted file mode 100755 index b6588c71..00000000 --- a/app/icons/spinner11.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/icons/station-coriolis.svg b/app/icons/station-coriolis.svg deleted file mode 100644 index 7287b5a2..00000000 --- a/app/icons/station-coriolis.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/icons/station-ocellus.svg b/app/icons/station-ocellus.svg deleted file mode 100644 index 9e037fee..00000000 --- a/app/icons/station-ocellus.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/icons/station-orbis.svg b/app/icons/station-orbis.svg deleted file mode 100644 index 1acf2a16..00000000 --- a/app/icons/station-orbis.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/icons/station-outpost.svg b/app/icons/station-outpost.svg deleted file mode 100644 index bd9309f3..00000000 --- a/app/icons/station-outpost.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/icons/stats-bars.svg b/app/icons/stats-bars.svg deleted file mode 100755 index 5ff267a5..00000000 --- a/app/icons/stats-bars.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/icons/switch.svg b/app/icons/switch.svg deleted file mode 100755 index a3949c0d..00000000 --- a/app/icons/switch.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/icons/upload.svg b/app/icons/upload.svg deleted file mode 100755 index 45e3ae6c..00000000 --- a/app/icons/upload.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/icons/warning.svg b/app/icons/warning.svg deleted file mode 100755 index d7e2c9f8..00000000 --- a/app/icons/warning.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/app/js/Coriolis.jsx b/app/js/Coriolis.jsx deleted file mode 100644 index fe00af05..00000000 --- a/app/js/Coriolis.jsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Component } from 'react'; -import Router from 'Router'; -import ShipyardPage from 'pages/ShipyardPage'; -import NotFoundPage from 'pages/NotFoundPage'; -import Header from '../components/Header'; - -class Coriolis extends Component { - - constructor(props) { - super(props); - this.setPage = this.setPage.bind(this); - this.state.standAlone = isStandAlone(); - window.onerror = errorPage.bind(this); - - Router('/', () => this.setPage()); - // Router('/outfitting/:ship', outfitting); - // Router('/outfitting/:ship/:code', outfitting); - // Router('/compare/:name', compare); - // Router('/comparison/:code', comparison); - // Router('/settings', settings); - Router('*', () => this.setPage(null)); - - if (window.applicationCache) { - // Listen for appcache updated event, present refresh to update view - window.applicationCache.addEventListener('updateready', () => { - if (window.applicationCache.status == window.applicationCache.UPDATEREADY) { - // Browser downloaded a new app cache. - this.setState({appCacheUpdate: true}); - } - }, false); - } - - Router.start(); - console.log('Root page created'); - } - - setPage(page) { - this.setState({ page: page }); - } - - onError(msg, scriptUrl, line, col, errObj) { - this.setPage(
Some errors occured!!
); - } - - render() { - return ( -
- {/*
*/} - {this.state.page || } -
- ); - } -} - -ReactDOM.render(, document.getElementById('coriolis')); diff --git a/app/js/components/Header.jsx b/app/js/components/Header.jsx deleted file mode 100644 index 6f3fcda2..00000000 --- a/app/js/components/Header.jsx +++ /dev/null @@ -1,118 +0,0 @@ -import { Component } from 'react'; - -export default class Header extends Component { - - - render() { - let openedMenu = this.state.openedMenu; - if (this.props.appCacheUpdate) { - return
{ 'PHRASE_UPDATE_RDY' | translate }
; - } - - return ( -
- - - - - - - - - -
- ); - } - - getShipsMenu() { - return (); - } - - getBuildsMenu() { - return (); - } - - getComparisonsMenu() { - return (); - } - - getSettingsMenu() { - return (); - } - -} \ No newline at end of file diff --git a/app/js/components/directive-component-select.js b/app/js/components/directive-component-select.js deleted file mode 100755 index dba65e9e..00000000 --- a/app/js/components/directive-component-select.js +++ /dev/null @@ -1,90 +0,0 @@ -angular.module('app').directive('componentSelect', ['$translate', function($translate) { - - // Generting the HTML in this manner is MUCH faster than using an angular template. - - function appendGroup(list, opts, cid, mass, checkWarning) { - var prevClass = null, prevRating = null; - for (var i = 0; i < opts.length; i++) { - var o = opts[i]; - var id = o.id || (o.class + o.rating); // Standard components' ID is their class and rating - - if (i > 0 && opts.length > 3 && o.class != prevClass && (o.rating != prevRating || o.mode) && o.grp != 'pa') { - list.push('
'); - } - - list.push('
  • '); - - if (o.mode) { - list.push(' '); - } - - list.push('', o.class, o.rating); - - if (o.missile) { - list.push('/' + o.missile); - } - - - if (o.name) { - list.push(' ' + $translate.instant(o.name)); - } - - list.push('
  • '); - prevClass = o.class; - prevRating = o.rating; - } - } - - return { - restrict: 'A', - scope: { - opts: '=', // Component Options object - groups: '=', // Groups of Component Options - mass: '=', // Current ship mass - s: '=', // Current Slot - warning: '=' // Check warning function - }, - link: function(scope, element) { - var list = []; - var cid = scope.s.id; // Slot's current component id - var component = scope.s.c; // Slot's Current Component (may be null/undefined) - var opts = scope.opts; - var groups = scope.groups; - var mass = (scope.mass ? scope.mass : 0) - (component && component.mass ? component.mass : 0); // Mass minus the currently selected component - - if (groups) { - // At present time slots with grouped options (Hardpoints and Internal) can be empty - list.push('
    ', $translate.instant('empty'), '
    '); - for (var g in groups) { - var grp = groups[g]; - var grpCode = grp[Object.keys(grp)[0]].grp; // Nasty operation to get the grp property of the first/any single component - list.push('
    ', $translate.instant(g), '
      '); - appendGroup(list, grp, cid, mass, scope.warning); - list.push('
    '); - } - } else { - list.push('
      '); - appendGroup(list, opts, cid, mass, scope.warning); - list.push('
    '); - } - - element.html(list.join('')); - // If groups are present and a component is already selectd - if (groups && component && component.grp) { - var groupElement = angular.element(document.getElementById(component.grp)); - var parentElem = element[0].parentElement; - parentElem.scrollTop = groupElement[0].offsetTop; // Scroll to currently selected group - } - } - }; -}]); diff --git a/app/js/components/directive-header.js b/app/js/components/directive-header.js deleted file mode 100755 index eab4601b..00000000 --- a/app/js/components/directive-header.js +++ /dev/null @@ -1,114 +0,0 @@ -angular.module('app').directive('shipyardHeader', ['lodash', '$window', '$rootScope', '$state', 'Persist', 'Serializer', 'ShipsDB', function(_, $window, $rootScope, $state, Persist, Serializer, ships) { - - - return { - restrict: 'E', - templateUrl: 'views/_header.html', - scope: true, - link: function(scope) { - scope.openedMenu = null; - scope.ships = ships; - scope.allBuilds = Persist.builds; - scope.buildsList = Object.keys(scope.allBuilds).sort(); - scope.allComparisons = Object.keys(Persist.comparisons).sort(); - scope.bs = Persist.state; - - var win = angular.element($window); // Angularized window object for event triggering - var insIndex = _.findIndex($rootScope.insurance.opts, 'name', Persist.getInsurance()); - var savedDiscounts = Persist.getDiscount() || [1, 1]; - $rootScope.insurance.current = $rootScope.insurance.opts[insIndex != -1 ? insIndex : 0]; - $rootScope.discounts.ship = savedDiscounts[0]; - $rootScope.discounts.components = savedDiscounts[1]; - - /** - * Save selected insurance option - */ - scope.updateInsurance = function() { - Persist.setInsurance($rootScope.insurance.current.name); - }; - - /** - * Save selected discount option - */ - scope.updateDiscount = function() { - Persist.setDiscount([$rootScope.discounts.ship, $rootScope.discounts.components]); - $rootScope.$broadcast('discountChange'); - }; - - scope.backup = function(e) { - e.preventDefault(); - e.stopPropagation(); - scope.openedMenu = null; - $state.go('modal.export', { - title: 'backup', - data: Persist.getAll(), - description: 'PHRASE_BACKUP_DESC' - }); - }; - - scope.detailedExport = function(e) { - e.preventDefault(); - e.stopPropagation(); - scope.openedMenu = null; - $state.go('modal.export', { - title: 'detailed export', - data: Serializer.toDetailedExport(scope.allBuilds), - description: 'PHRASE_EXPORT_DESC' - }); - }; - - scope.cleanedBuildList = function(shipId) { - return Object.keys(scope.allBuilds[shipId]); - }; - - scope.openMenu = function(e, menu) { - e.stopPropagation(); - if (menu == scope.openedMenu) { - scope.openedMenu = null; - return; - } - - if ((menu == 'comp' || menu == 'b') && !scope.bs.hasBuilds) { - scope.openedMenu = null; - return; - } - - if (menu == 'comp') { - scope.allComparisons = Object.keys(Persist.comparisons).sort(); - } - - scope.openedMenu = menu; - }; - - // Close menus if a navigation change event occurs - $rootScope.$on('$stateChangeStart', function() { - scope.openedMenu = null; - }); - - // Listen to close event to close opened menus or modals - $rootScope.$on('close', function() { - scope.openedMenu = null; - }); - - scope.textSizeChange = function(size) { - if (size != $rootScope.sizeRatio) { - $rootScope.sizeRatio = size; - document.getElementById('main').style.fontSize = size + 'em'; - Persist.setSizeRatio(size); - win.triggerHandler('resize'); - } - }; - - scope.resetTextSize = function() { - if ($rootScope.sizeRatio != 1) { - scope.textSizeChange(1); - scope.$broadcast('reset', 1); - } - }; - - scope.$watchCollection('allBuilds', function() { - scope.buildsList = Object.keys(scope.allBuilds).sort(); - }); - } - }; -}]); diff --git a/app/js/components/directive-loader.js b/app/js/components/directive-loader.js deleted file mode 100644 index b7743337..00000000 --- a/app/js/components/directive-loader.js +++ /dev/null @@ -1,9 +0,0 @@ -angular.module('app').directive('loader', function() { - return { - restrict: 'A', - link: function(scope, element) { - element.addClass('loader'); - element.html(''); - } - }; -}); diff --git a/app/js/components/directive-slot-hardpoint.js b/app/js/components/directive-slot-hardpoint.js deleted file mode 100755 index dbfa50b8..00000000 --- a/app/js/components/directive-slot-hardpoint.js +++ /dev/null @@ -1,13 +0,0 @@ -angular.module('app').directive('slotHardpoint', ['$rootScope', function($r) { - return { - restrict: 'A', - scope: { - hp: '=', - size: '=' - }, - templateUrl: 'views/_slot-hardpoint.html', - link: function(scope) { - scope.$r = $r; - } - }; -}]); diff --git a/app/js/components/directive-slot-internal.js b/app/js/components/directive-slot-internal.js deleted file mode 100755 index afc148d6..00000000 --- a/app/js/components/directive-slot-internal.js +++ /dev/null @@ -1,13 +0,0 @@ -angular.module('app').directive('slotInternal', ['$rootScope', function($r) { - return { - restrict: 'A', - scope: { - c: '=slot', - fuel: '=' - }, - templateUrl: 'views/_slot-internal.html', - link: function(scope) { - scope.$r = $r; - } - }; -}]); diff --git a/app/js/i18n/Language.js b/app/js/i18n/Language.js deleted file mode 100644 index 8966bb67..00000000 --- a/app/js/i18n/Language.js +++ /dev/null @@ -1,52 +0,0 @@ -import EN from 'en'; -import DE from 'de'; -import ES from 'es'; -import FR from 'fr'; -import IT from 'it'; -import RU from 'RU'; -import d3 from 'd3'; - -let fallbackTerms = EN.terms; -let currentLanguage; -let currentTerms; -let format = { - rPct: d3.format('%') -}; - -export format; - -export function setLanguage(langCode) { - let lang; - - switch (langCode) { - case 'de': lang = DE; break; - case 'es': lang = ES; break; - case 'fr': lang = FR; break; - case 'it': lang = IT; break; - case 'ru': lang = RU; break; - default: lang = EN; - } - - currentTerms = lang.terms; - d3Locale = d3.locale(lang.formats); - - format.gen = d3Locale.numberFormat('n'); - format.crd = d3Locale.numberFormat(',.0f'); - format.pwr = d3Locale.numberFormat(',.2f'); - format.round = (d) => format.gen(d3.round(d, 2)); - format.pct = d3Locale.numberFormat('.2%'); - format.pct1 = d3Locale.numberFormat('.1%'); -} - -export const Languages = { - en: 'English', - de: 'Deutsh', - it: 'Italiano', - es: 'Español', - fr: 'Français', - ru: 'ру́сский' -}; - -export function term(t) { - return currentTerms[t] || fallbackTerms[t]; -} diff --git a/app/js/old-app.js b/app/js/old-app.js deleted file mode 100755 index 7b9441b5..00000000 --- a/app/js/old-app.js +++ /dev/null @@ -1,114 +0,0 @@ -angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', 'shipyard', 'ngLodash', 'app.templates', 'pascalprecht.translate']) -.run(['$rootScope', '$location', '$window', '$document', '$state', '$translate', 'localeFormat', 'Persist', 'Discounts', 'Languages', 'SizeMap', -function($rootScope, $location, $window, $doc, $state, $translate, localeFormat, Persist, Discounts, Languages, SizeMap) { - // App is running as a standalone web app on tablet/mobile - var isStandAlone; - // This was causing issues on Windows phones ($window.external was causing Angular js to throw an exception). Backup is to try this and set isStandAlone to false if this fails. - try { - isStandAlone = $window.navigator.standalone || ($window.external && $window.external.msIsSiteMode && $window.external.msIsSiteMode()); - } catch (ex) { - isStandAlone = false; - } - - // Redirect any state transition errors to the error controller/state - $rootScope.$on('$stateChangeError', function(e, toState, toParams, fromState, fromParams, error) { - e.preventDefault(); - $state.go('error', error, { location: false, reload: true }); // Go to error state, reload the controller, keep the current URL - }); - - // Track on Google analytics if available - $rootScope.$on('$stateChangeSuccess', function(e, to, toParams, from, fromParams) { - $rootScope.prevState = { name: from.name, params: fromParams }; - - if (to.url) { // Only track states that have a URL - if ($window.ga) { - ga('send', 'pageview', { page: $location.path() }); - } - - if (isStandAlone) { - // Persist the current state - Persist.setState({ name: to.name, params: toParams }); - } - } - }); - - $rootScope.language = { - opts: Languages, - current: Languages[Persist.getLangCode()] ? Persist.getLangCode() : 'en' - }; - $rootScope.localeFormat = d3.locale(localeFormat.get($rootScope.language.current)); - updateNumberFormat(); - - // Global Reference variables - $rootScope.insurance = { opts: [{ name: 'standard', pct: 0.05 }, { name: 'alpha', pct: 0.025 }, { name: 'beta', pct: 0.0375 }] }; - $rootScope.discounts = { opts: Discounts }; - $rootScope.sizeRatio = Persist.getSizeRatio(); - $rootScope.SZM = SizeMap; - $rootScope.title = 'Coriolis'; - - $rootScope.changeLanguage = function() { - $translate.use($rootScope.language.current); - $rootScope.localeFormat = d3.locale(localeFormat.get($rootScope.language.current)); - updateNumberFormat(); - $rootScope.$broadcast('languageChanged', $rootScope.language.current); - }; - - // Formatters - $rootScope.fRPct = d3.format('%'); - $rootScope.fTime = function(d) { return Math.floor(d / 60) + ':' + ('00' + Math.floor(d % 60)).substr(-2, 2); }; - - function updateNumberFormat() { - var locale = $rootScope.localeFormat; - var fGen = $rootScope.fGen = locale.numberFormat('n'); - $rootScope.fCrd = locale.numberFormat(',.0f'); - $rootScope.fPwr = locale.numberFormat(',.2f'); - $rootScope.fRound = function(d) { return fGen(d3.round(d, 2)); }; - $rootScope.fPct = locale.numberFormat('.2%'); - $rootScope.f1Pct = locale.numberFormat('.1%'); - } - - /** - * Returns the name of the component mounted in the specified slot - * @param {Object} slot The slot object - * @return {String} The component name - */ - $rootScope.cName = function(slot) { - return $translate.instant(slot.c ? slot.c.name ? slot.c.name : slot.c.grp : null); - }; - - // Global Event Listeners - $doc.bind('keyup', function(e) { - if (e.keyCode == 27) { // Escape Key - $rootScope.$broadcast('close', e); - $rootScope.$apply(); - } else { - $rootScope.$broadcast('keyup', e); - } - }); - - $rootScope.bgClicked = function(e) { - $rootScope.$broadcast('close', e); - }; - - if ($window.applicationCache) { - // Listen for appcache updated event, present refresh to update view - $window.applicationCache.addEventListener('updateready', function() { - if ($window.applicationCache.status == $window.applicationCache.UPDATEREADY) { - // Browser downloaded a new app cache. - $rootScope.appCacheUpdate = true; - $rootScope.$apply(); - } - }, false); - } - - if (isStandAlone) { - var state = Persist.getState(); - // If a previous state has been stored, load that state - if (state && state.name && state.params) { - $state.go(state.name, state.params, { location: 'replace' }); - } else { - $state.go('shipyard', null, { location: 'replace' }); // Default to home page - } - } - -}]); diff --git a/app/js/pages/NotFoundPage.jsx b/app/js/pages/NotFoundPage.jsx deleted file mode 100644 index 0dabb937..00000000 --- a/app/js/pages/NotFoundPage.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Component } from 'react'; - -export default class ShipyardPage extends Component { - - constructor(props) { - super(props); - } - - render() { - return
    Page {this.props.path} Not Found
    ; - } -} diff --git a/app/js/pages/ShipyardPage.jsx b/app/js/pages/ShipyardPage.jsx deleted file mode 100755 index 5d697aea..00000000 --- a/app/js/pages/ShipyardPage.jsx +++ /dev/null @@ -1,180 +0,0 @@ -import { Component } from 'react'; -import { Ships, Components } from 'coriolis-data'; -import cn from 'classnames'; -import Ship from 'Ship'; - -function countHp(slot) { - this.hp[slot.maxClass]++; - this.hpCount++; -} - -function countInt(slot) { - var crEligible = !slot.eligible || slot.eligible.cr; - this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment - this.intCount++; - this.maxCargo += crEligible ? Components.findInternal('cr', slot.maxClass, 'E').capacity : 0; -} - -function shipSummary(shipId, shipData) { - let summary = { - id: shipId, - hpCount: 0, - intCount: 0, - maxCargo: 0, - hp: [0, 0, 0, 0, 0], // Utility, Small, Medium, Large, Huge - int: [0, 0, 0, 0, 0, 0, 0, 0] // Sizes 1 - 8 - }; - Object.assign(summary, shipData.properties); - let ship = new Ship(shipId, shipData.properties, shipData.slots); - - // Build Ship - ship.buildWith(shipData.defaults); // Populate with stock/default components - ship.hardpoints.forEach(countHp.bind(summary)); // Count Hardpoints by class - ship.internal.forEach(countInt.bind(summary)); // Count Internal Compartments by class - summary.retailCost = ship.totalCost; // Record Stock/Default/retail cost - ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range - summary.maxJumpRange = ship.unladenRange; // Record Jump Range - ship.optimizeMass({ th: ship.standard[1].maxClass + 'A' }); // Optmize mass with Max Thrusters - summary.topSpeed = ship.topSpeed; - summary.topBoost = ship.topBoost; - - return summary; -} - -let shipSummaries = []; - -for (var s in Ships) { - shipSummaries.push(shipSummary(s, Ships[s])); -} - -export default class ShipyardPage extends Component { - - constructor(props) { - super(props); - this.state = { - title: 'Coriolis - Shipyard', - shipPredicate: 'properties.name', - shipDesc = false - }; - } - - shouldComponentUpdate(nextProps, nextState) { - // Only on language change. Context? - return false; - } - - /** - * Sort ships - * @param {object} key Sort predicate - */ - _sortShips(shipPredicate, shipPredicateIndex) { - let shipDesc = this.state.shipPredicate == shipPredicate ? !this.state.shipDesc : this.state.shipDesc; - this.setState({ shipPredicate, shipDesc, shipPredicateIndex }); - }; - - render() { - let sortShips = this._sortShips.bind(this); - let shipPredicate = this.state.shipPredicate; - let shipPredicateIndex = this.state.shipPredicateIndex; - let shipRows = []; - - // Sort shipsOverview - shipSummaries.sort((a, b) => { - let valA = a[shipPredicate], valB = b[shipPredicate]; - - if (shipPredicateIndex != undefined) { - valA = valA[shipPredicateIndex]; - valB = valB[shipPredicateIndex]; - } - - return this.state.shipDesc ? (valA > valB) : (valB > valA); - }); - - for (s of shipSummaries) { - shipRows.push( - - {s.name} - {s.manufacturer} - {SZM[s.class] | translate} - {{fCrd(s.speed)}} m/s - {{fCrd(s.boost)}} m/s - {s.baseArmour} - {{fCrd(s.baseShieldStrength)}} Mj - {{fCrd(s.topSpeed)}} m/s - {{fCrd(s.topBoost)}} m/s - {{fRound(s.maxJumpRange)}} LY - {{fCrd(s.maxCargo)}} T - {s.hp[1]} - {s.hp[2]} - {s.hp[3]} - {s.hp[4]} - {s.hp[0]} - {s.int[0]} - {s.int[1]} - {s.int[2]} - {s.int[3]} - {s.int[4]} - {s.int[5]} - {s.int[6]} - {s.int[7]} - {fCrd(s.hullMass)} T - {s.masslock} - {fCrd(s.retailCost)} CR - - ); - } - - return ( -
    -
    - - - - - - - - - - - - - - - - {/* Base */} - - - - - {/* Max */} - - - - - {/* Hardpoints */} - - - - - - {/* Internal */} - - - - - - - - - - - - {shipRows} - -
    12345678
    -
    -
    - ); - } -} diff --git a/app/js/pages/controller-delete.js b/app/js/pages/controller-delete.js deleted file mode 100755 index 5aec906e..00000000 --- a/app/js/pages/controller-delete.js +++ /dev/null @@ -1,7 +0,0 @@ -angular.module('app').controller('DeleteController', ['$scope', 'Persist', function($scope, Persist) { - $scope.deleteAll = function() { - Persist.deleteAll(); - $scope.$parent.dismiss(); - }; - -}]); diff --git a/app/js/pages/controller-error.js b/app/js/pages/controller-error.js deleted file mode 100755 index b1f19cf1..00000000 --- a/app/js/pages/controller-error.js +++ /dev/null @@ -1,29 +0,0 @@ -angular.module('app') -.controller('ErrorController', ['$window', '$rootScope', '$scope', '$stateParams', '$location', function($window, $rootScope, $scope, $p, $location) { - $rootScope.title = 'Error'; - $scope.path = $location.path(); - $scope.type = $p.type || 'unknown'; - $scope.browser = $window.navigator.userAgent; - - switch ($scope.type) { - case 404: - $scope.msgPre = 'Page'; - $scope.msgHighlight = $scope.path; - $scope.msgPost = 'Not Found'; - break; - case 'no-ship': - $scope.msgPre = 'Ship'; - $scope.msgHighlight = $p.message; - $scope.msgPost = 'does not exist'; - break; - case 'build-fail': - $scope.msgPre = 'Build Failure!'; - $scope.details = $p.details; - break; - default: - $scope.msgPre = 'Uh, Jameson, we have a problem..'; - $scope.errorMessage = $p.message; - $scope.details = $p.details; - } - -}]); diff --git a/app/js/pages/controller-export.js b/app/js/pages/controller-export.js deleted file mode 100755 index d2ade80c..00000000 --- a/app/js/pages/controller-export.js +++ /dev/null @@ -1,19 +0,0 @@ -angular.module('app').controller('ExportController', ['$scope', '$stateParams', function($scope, $stateParams) { - - $scope.title = $stateParams.title || 'Export'; - $scope.description = $stateParams.description; - - if ($stateParams.promise) { - $scope.export = 'Generating...'; - $stateParams.promise.then(function(data) { - $scope.export = (typeof data === 'object') ? angular.toJson(data, true) : data; - }); - } else { - $scope.export = angular.toJson($stateParams.data, true); - } - - $scope.onTextClick = function($event) { - $event.target.select(); - }; - -}]); diff --git a/app/js/pages/controller-import.js b/app/js/pages/controller-import.js deleted file mode 100755 index 10ced797..00000000 --- a/app/js/pages/controller-import.js +++ /dev/null @@ -1,316 +0,0 @@ -angular.module('app').controller('ImportController', ['lodash', '$rootScope', '$scope', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'GroupMap', 'Persist', 'Serializer', function(_, $rootScope, $scope, $stateParams, Ships, Ship, Components, GroupMap, Persist, Serializer) { - $scope.importValid = false; - $scope.importString = null; - $scope.errorMsg = null; - $scope.canEdit = true; - $scope.builds = $stateParams.obj || null; - $scope.ships = Ships; - - var textBuildRegex = new RegExp('^\\[([\\w \\-]+)\\]\n'); - var lineRegex = new RegExp('^([\\dA-Z]{1,2}): (\\d)([A-I])[/]?([FGT])?([SD])? ([\\w\\- ]+)'); - var mountMap = { 'H': 4, 'L': 3, 'M': 2, 'S': 1, 'U': 0 }; - var standardMap = { 'RB': 0, 'TM': 1, 'FH': 2, 'EC': 3, 'PC': 4, 'SS': 5, 'FS': 6 }; - var bhMap = { 'lightweight alloy': 0, 'reinforced alloy': 1, 'military grade composite': 2, 'mirrored surface composite': 3, 'reactive surface composite': 4 }; - - function isEmptySlot(slot) { - return slot.maxClass == this && slot.c === null; - } - - function equalsIgnoreCase(str) { - return str.toLowerCase() == this.toLowerCase(); - } - - function validateBuild(shipId, code, name) { - var shipData = Ships[shipId]; - - if (!shipData) { - throw '"' + shipId + '" is not a valid Ship Id!'; - } - if (typeof name != 'string' || name.length == 0) { - throw shipData.properties.name + ' build "' + name + '" must be a string at least 1 character long!'; - } - if (typeof code != 'string' || code.length < 10) { - throw shipData.properties.name + ' build "' + name + '" is not valid!'; - } - try { - Serializer.toShip(new Ship(shipId, shipData.properties, shipData.slots), code); - } catch (e) { - throw shipData.properties.name + ' build "' + name + '" is not valid!'; - } - } - - function detailedJsonToBuild(detailedBuild) { - var ship; - if (!detailedBuild.name) { - throw 'Build Name missing!'; - } - - if (!detailedBuild.name.trim()) { - throw 'Build Name must be a string at least 1 character long!'; - } - - try { - ship = Serializer.fromDetailedBuild(detailedBuild); - } catch (e) { - throw detailedBuild.ship + ' Build "' + detailedBuild.name + '": Invalid data'; - } - - return { shipId: ship.id, name: detailedBuild.name, code: Serializer.fromShip(ship) }; - } - - function importBackup(importData) { - if (importData.builds && typeof importData.builds == 'object') { - for (var shipId in importData.builds) { - for (var buildName in importData.builds[shipId]) { - validateBuild(shipId, importData.builds[shipId][buildName], buildName); - } - } - $scope.builds = importData.builds; - } else { - throw 'builds must be an object!'; - } - if (importData.comparisons) { - for (var compName in importData.comparisons) { - var comparison = importData.comparisons[compName]; - for (var i = 0, l = comparison.builds.length; i < l; i++) { - var build = comparison.builds[i]; - if (!importData.builds[build.shipId] || !importData.builds[build.shipId][build.buildName]) { - throw build.shipId + ' build "' + build.buildName + '" data is missing!'; - } - } - } - $scope.comparisons = importData.comparisons; - } - if (importData.discounts instanceof Array && importData.discounts.length == 2) { - $scope.discounts = importData.discounts; - } - if (typeof importData.insurance == 'string' && importData.insurance.length > 3) { - $scope.insurance = importData.insurance; - } - } - - function importDetailedArray(importArr) { - var builds = {}; - for (var i = 0, l = importArr.length; i < l; i++) { - var build = detailedJsonToBuild(importArr[i]); - if (!builds[build.shipId]) { - builds[build.shipId] = {}; - } - builds[build.shipId][build.name] = build.code; - } - $scope.builds = builds; - } - - function importTextBuild(buildStr) { - var buildName = textBuildRegex.exec(buildStr)[1].trim(); - var shipName = buildName.toLowerCase(); - var shipId = null; - - for (var sId in Ships) { - if (Ships[sId].properties.name.toLowerCase() == shipName) { - shipId = sId; - break; - } - } - - if (!shipId) { throw 'No such ship found: "' + buildName + '"'; } - - var lines = buildStr.split('\n'); - var ship = new Ship(shipId, Ships[shipId].properties, Ships[shipId].slots); - ship.buildWith(null); - - for (var i = 1; i < lines.length; i++) { - var line = lines[i].trim(); - - if (!line) { continue; } - if (line.substring(0, 3) == '---') { break; } - - var parts = lineRegex.exec(line); - - if (!parts) { throw 'Error parsing: "' + line + '"'; } - - var typeSize = parts[1]; - var cl = parts[2]; - var rating = parts[3]; - var mount = parts[4]; - var missile = parts[5]; - var name = parts[6].trim(); - var slot, group; - - if (isNaN(typeSize)) { // Standard or Hardpoint - if (typeSize.length == 1) { // Hardpoint - var slotClass = mountMap[typeSize]; - - if (cl > slotClass) { throw cl + rating + ' ' + name + ' exceeds slot size: "' + line + '"'; } - - slot = _.find(ship.hardpoints, isEmptySlot, slotClass); - - if (!slot) { throw 'No hardpoint slot available for: "' + line + '"'; } - - group = _.find(GroupMap, equalsIgnoreCase, name); - - var hp = Components.findHardpoint(group, cl, rating, group ? null : name, mount, missile); - - if (!hp) { throw 'Unknown component: "' + line + '"'; } - - ship.use(slot, hp.id, hp, true); - - } else if (typeSize == 'BH') { - var bhId = bhMap[name.toLowerCase()]; - - if (bhId === undefined) { throw 'Unknown bulkhead: "' + line + '"'; } - - ship.useBulkhead(bhId, true); - - } else if (standardMap[typeSize] != undefined) { - var standardIndex = standardMap[typeSize]; - - if (ship.standard[standardIndex].maxClass < cl) { throw name + ' exceeds max class for the ' + ship.name; } - - ship.use(ship.standard[standardIndex], cl + rating, Components.standard(standardIndex, cl + rating), true); - - } else { - throw 'Unknown component: "' + line + '"'; - } - } else { - if (cl > typeSize) { throw cl + rating + ' ' + name + ' exceeds slot size: "' + line + '"'; } - - slot = _.find(ship.internal, isEmptySlot, typeSize); - - if (!slot) { throw 'No internal slot available for: "' + line + '"'; } - - group = _.find(GroupMap, equalsIgnoreCase, name); - - var intComp = Components.findInternal(group, cl, rating, group ? null : name); - - if (!intComp) { throw 'Unknown component: "' + line + '"'; } - - ship.use(slot, intComp.id, intComp); - } - } - - var builds = {}; - builds[shipId] = {}; - builds[shipId]['Imported ' + buildName] = Serializer.fromShip(ship); - $scope.builds = builds; - } - - $scope.validateImport = function() { - var importData = null; - var importString = $scope.importString.trim(); - $scope.importValid = false; - $scope.errorMsg = null; - $scope.builds = $scope.discounts = $scope.comparisons = $scope.insurance = null; - - if (!importString) { return; } - - - try { - if (textBuildRegex.test(importString)) { // E:D Shipyard build text - importTextBuild(importString); - } else { // JSON Build data - importData = angular.fromJson($scope.importString); - - if (!importData || typeof importData != 'object') { - throw 'Must be an object or array!'; - } - - if (importData instanceof Array) { // Must be detailed export json - importDetailedArray(importData); - } else if (importData.ship && typeof importData.name !== undefined) { // Using JSON from a single ship build export - importDetailedArray([importData]); // Convert to array with singleobject - } else { // Using Backup JSON - importBackup(importData); - } - } - } catch (e) { - $scope.errorMsg = (typeof e == 'string') ? e : 'Cannot Parse the data!'; - return; - } - - $scope.importValid = true; - }; - - $scope.hasBuild = function(shipId, name) { - return Persist.getBuild(shipId, name) !== null; - }; - - $scope.hasComparison = function(name) { - return Persist.getComparison(name) !== null; - }; - - $scope.process = function() { - if ($scope.builds) { - var builds = $scope.builds; - for (var shipId in builds) { - for (var buildName in builds[shipId]) { - var code = builds[shipId][buildName]; - // Update builds object such that orginal name retained, but can be renamed - builds[shipId][buildName] = { - code: code, - useName: buildName - }; - } - } - } - - if ($scope.comparisons) { - var comparisons = $scope.comparisons; - for (var name in comparisons) { - comparisons[name].useName = name; - } - } - - $scope.processed = true; - }; - - $scope.import = function() { - - if ($scope.builds) { - var builds = $scope.builds; - for (var shipId in builds) { - for (var buildName in builds[shipId]) { - var build = builds[shipId][buildName]; - var name = build.useName.trim(); - if (name) { - Persist.saveBuild(shipId, name, build.code); - } - } - } - } - - if ($scope.comparisons) { - var comparisons = $scope.comparisons; - for (var comp in comparisons) { - var comparison = comparisons[comp]; - var useName = comparison.useName.trim(); - if (useName) { - Persist.saveComparison(useName, comparison.builds, comparison.facets); - } - } - } - - if ($scope.discounts) { - $rootScope.discounts.ship = $scope.discounts[0]; - $rootScope.discounts.components = $scope.discounts[1]; - $rootScope.$broadcast('discountChange'); - Persist.setDiscount($scope.discounts); - } - - if ($scope.insurance) { - $rootScope.insurance.current = $scope.insurance; - Persist.setInsurance($scope.insurance); - } - - $scope.$parent.dismiss(); - }; - - /* Initialization */ - - if ($scope.builds) { // If import is passed an build object - $scope.canEdit = false; - $scope.process(); - } - - -}]); diff --git a/app/js/pages/controller-link.js b/app/js/pages/controller-link.js deleted file mode 100755 index 59c4690c..00000000 --- a/app/js/pages/controller-link.js +++ /dev/null @@ -1,16 +0,0 @@ -angular.module('app').controller('LinkController', ['$scope', 'Utils', '$stateParams', function($scope, Utils, $stateParams) { - $scope.url = $stateParams.url; - $scope.shortenedUrl = 'Shortening...'; - - $scope.onTextClick = function($event) { - $event.target.select(); - }; - - Utils.shortenUrl($scope.url) - .then(function(url) { - $scope.shortenedUrl = url; - }, function(e) { - $scope.shortenedUrl = 'Error - ' + e.statusText; - }); - -}]); diff --git a/app/js/pages/controller-modal.js b/app/js/pages/controller-modal.js deleted file mode 100755 index c73135ad..00000000 --- a/app/js/pages/controller-modal.js +++ /dev/null @@ -1,14 +0,0 @@ -angular.module('app').controller('ModalController', ['$rootScope', '$scope', '$state', function($rootScope, $scope, $state) { - - $scope.dismiss = function() { - if ($rootScope.prevState) { - var state = $rootScope.prevState; - $state.go(state.name, state.params, { location: 'replace', reload: false }); - } else { - $state.go('shipyard'); - } - }; - - $scope.$on('close', $scope.dismiss); - -}]); diff --git a/app/js/utils/ShortenUrl.js b/app/js/utils/ShortenUrl.js deleted file mode 100644 index 22cc498e..00000000 --- a/app/js/utils/ShortenUrl.js +++ /dev/null @@ -1,10 +0,0 @@ - -export default function shortenUrl(url) { - /*if (window.navigator.onLine) { - return $http.post(shortenAPI + GAPI_KEY, { longUrl: url }).then(function(response) { - return response.data.id; - }); - } else { - return $q.reject({ statusText: 'Not Online' }); - }*/ -} diff --git a/app/less/background-images.less b/app/less/background-images.less deleted file mode 100755 index 295dd50e..00000000 --- a/app/less/background-images.less +++ /dev/null @@ -1,8 +0,0 @@ - -.deep-space { - background-image: url(images/deep-space-1920x1080.jpg); -} - -.docking-bay { - background-image: url(images/bay-1920x1080.jpg); -} \ No newline at end of file diff --git a/app/less/fonts.less b/app/less/fonts.less deleted file mode 100755 index f8c0b0f4..00000000 --- a/app/less/fonts.less +++ /dev/null @@ -1,26 +0,0 @@ -@font-face { - font-family: 'Orbitron-Regular'; - src: url('fonts/orbitron-regular-webfont.eot'); - src: url('fonts/orbitron-regular-webfont.eot?#iefix') format('embedded-opentype'), - url('fonts/orbitron-regular-webfont.woff2') format('woff2'), - url('fonts/orbitron-regular-webfont.woff') format('woff'), - url('fonts/orbitron-regular-webfont.ttf') format('truetype'), - url('fonts/orbitron-regular-webfont.svg#orbitronregular') format('svg'); - font-weight: normal; - font-style: normal; -} - -@font-face { - font-family: 'Eurostile'; - src: url('fonts/eurostile.eot'); - src: url('fonts/eurostile.eot?#iefix') format('embedded-opentype'), - url('fonts/eurostile.woff2') format('woff2'), - url('fonts/eurostile.woff') format('woff'), - url('fonts/eurostile.ttf') format('truetype'), - url('fonts/eurostile.svg#euro_capsregular') format('svg'); - font-weight: normal; - font-style: normal; -} - -@fStandard: 'Eurostile', Helvetica, sans-serif; -@fTitle: 'Orbitron-Regular', Arial, sans-serif; diff --git a/app/views/_modal.html b/app/views/_modal.html deleted file mode 100755 index 946cf418..00000000 --- a/app/views/_modal.html +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/app/views/_slot-hardpoint.html b/app/views/_slot-hardpoint.html deleted file mode 100755 index 14d211fc..00000000 --- a/app/views/_slot-hardpoint.html +++ /dev/null @@ -1,17 +0,0 @@ -
    {{['U','S','M','L','H'][hp.maxClass] | translate}}
    -
    -
    - {{hp.c.class}}{{hp.c.rating}}/{{hp.c.mode}}{{hp.c.missile}} {{hp.c.name || hp.c.grp | translate}} -
    {{hp.c.mass}} T
    -
    -
    {{'damage' | translate}}: {{hp.c.damage}} ({{$r.fCrd(hp.c.ssdam)}} MJ)
    -
    {{'DPS' | translate}}: {{hp.c.dps}} ({{$r.fCrd(hp.c.mjdps)}} MJ)
    -
    {{'T_LOAD' | translate}}: {{hp.c.thermload}}
    -
    {{'type' | translate}}: {{hp.c.type}}
    -
    {{'ROF' | translate}}: {{hp.c.rof}}/s
    -
    {{'pen' | translate}}: {{hp.c.armourpen}}
    -
    +{{$r.fRPct(hp.c.shieldmul)}}
    -
    {{hp.c.range}} km
    -
    {{'ammo' | translate}}: {{$r.fCrd(hp.c.clip)}}+{{$r.fCrd(hp.c.ammo)}}
    -
    -
    diff --git a/app/views/_slot-internal.html b/app/views/_slot-internal.html deleted file mode 100755 index 4f9b7a60..00000000 --- a/app/views/_slot-internal.html +++ /dev/null @@ -1,22 +0,0 @@ -
    -
    -
    -
    {{c.c.class}}{{c.c.rating}} {{c.c.name || c.c.grp | translate}}
    -
    {{c.c.mass || c.c.capacity || '0'}}
    -
    -
    {{'optimal mass' | translate}}: {{c.c.optmass}}
    -
    {{'max mass' | translate}}: {{c.c.maxmass}}
    -
    {{c.c.bins}}
    -
    {{'rate' | translate}}: {{c.c.rate}} kg/s   {{'refuel time' | translate}}: {{$r.fTime(fuel * 1000 / c.c.rate)}}
    -
    {{'ammo' | translate}}: {{$r.fCrd(c.c.ammo)}}
    -
    {{'cells' | translate}}: {{c.c.cells}}
    -
    {{'recharge' | translate}}: {{c.c.recharge}} MJ   {{'total' | translate}}: {{c.c.cells * c.c.recharge}} MJ
    -
    {{'repair' | translate}}: {{c.c.repair}}
    -
    {{'range' | translate}} {{c.c.range}} km
    -
    {{'time' | translate}}: {{$r.fTime(c.c.time)}}
    -
    {{'max' | translate}}: {{(c.c.maximum)}}
    -
    {{c.c.rangeLS}}
    -
    -
    {{'range' | translate}}: {{c.c.rangeRating}}
    -
    +{{c.c.armouradd}}
    -
    diff --git a/app/views/modal-about.html b/app/views/modal-about.html deleted file mode 100755 index 5e03eb47..00000000 --- a/app/views/modal-about.html +++ /dev/null @@ -1,29 +0,0 @@ -

    Coriolis

    -

    The Coriolis project was inspired by E:D Shipyard and, of course, -Elite Dangerous. The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development.

    - -

    Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments.

    - -
    - - - -

    Github

    - github.com/cmmcleod/coriolis -
    -

    - Coriolis is an open source project. Checkout the list of upcoming features and to-do list on github. - Any and all contributions and feedback are welcome. If you encounter any bugs please report them and provide as much detail as possible. -

    - -
    - - - - -
    - -

    Help keep the lights on! Donations will be used to cover costs of running and maintaining Coriolis. Thanks for helping!

    - - \ No newline at end of file diff --git a/app/views/modal-delete.html b/app/views/modal-delete.html deleted file mode 100755 index f132277b..00000000 --- a/app/views/modal-delete.html +++ /dev/null @@ -1,4 +0,0 @@ -

    -

    - - \ No newline at end of file diff --git a/app/views/modal-export.html b/app/views/modal-export.html deleted file mode 100755 index 2828f7e1..00000000 --- a/app/views/modal-export.html +++ /dev/null @@ -1,6 +0,0 @@ -

    -
    -
    - -
    - \ No newline at end of file diff --git a/app/views/modal-import.html b/app/views/modal-import.html deleted file mode 100755 index fe92aace..00000000 --- a/app/views/modal-import.html +++ /dev/null @@ -1,46 +0,0 @@ -

    -
    - - -
    {{errorMsg}}
    -
    - -
    - - - - - - - - - - - - - - - -
    {{ships[shipId].properties.name}} - - -
    - - - - - - - - - -
    - - -
    - - - -
    - - \ No newline at end of file diff --git a/app/views/modal-link.html b/app/views/modal-link.html deleted file mode 100755 index 726033c2..00000000 --- a/app/views/modal-link.html +++ /dev/null @@ -1,9 +0,0 @@ -

    -
    -

    - -

    -

    - -

    - diff --git a/app/views/page-comparison.html b/app/views/page-comparison.html deleted file mode 100755 index d6ade87f..00000000 --- a/app/views/page-comparison.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - -
    - - - - - - -
    -

    - -
    -
      -
    • -
      -
    • -
    -
    - -
    -
    -
    - -
    -

    {{f.title | translate}}

    -
    - - \ No newline at end of file diff --git a/app/views/page-error.html b/app/views/page-error.html deleted file mode 100755 index e1c47d9b..00000000 --- a/app/views/page-error.html +++ /dev/null @@ -1,21 +0,0 @@ -
    -

    - {{msgPre}} - {{msgHighlight}} - {{msgPost}} -

    - -
    -
    - Create an issue on Github - if this keeps happening. Add these details -
    -
    -
    Browser:
    {{browser}}
    -
    Path:
    {{path}}
    -
    Error:
    {{type}}
    -
    Message:
    {{errorMessage}}
    -
    Details:
    {{details}}
    -
    -
    -
    diff --git a/devServer.js b/devServer.js new file mode 100644 index 00000000..4ef236a0 --- /dev/null +++ b/devServer.js @@ -0,0 +1,27 @@ +var path = require('path'); +var express = require('express'); +var webpack = require('webpack'); +var config = require('./webpack.config.dev'); + +var app = express(); +var compiler = webpack(config); + +app.use(require('webpack-dev-middleware')(compiler, { + noInfo: true, + publicPath: config.output.publicPath +})); + +app.use(require('webpack-hot-middleware')(compiler)); + +app.get('*', function(req, res) { + res.sendFile(path.join(__dirname, 'src/index.html')); +}); + +app.listen(3300, 'localhost', function(err) { + if (err) { + console.log(err); + return; + } + + console.log('Listening at http://localhost:3000'); +}); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100755 index 3a61d18a..00000000 --- a/gulpfile.js +++ /dev/null @@ -1,281 +0,0 @@ -// Build / Built-in dependencies -var gulp = require('gulp'), - exec = require('child_process').exec, - pkg = require('./package.json'); - -// Package.json / Gulp Dependencies -var appCache = require("gulp-manifest"), - concat = require('gulp-concat'), - del = require('del'), - eslint = require('gulp-eslint'); - gutil = require('gulp-util'), - htmlmin = require('gulp-htmlmin'), - jsonlint = require("gulp-jsonlint"), - karma = require('karma').server, - less = require('gulp-less'), - mainBowerFiles = require('main-bower-files'), - minifyCSS = require('gulp-minify-css'), - revAll = require('gulp-rev-all'), - runSequence = require('run-sequence'), - sourcemaps = require('gulp-sourcemaps'), - svgstore = require('gulp-svgstore'), - svgmin = require('gulp-svgmin'), - template = require('gulp-template'), - templateCache = require('gulp-angular-templatecache'), - uglify = require('gulp-uglify'); - -var cdnHostStr = ''; - -gulp.task('less', function() { - return gulp.src('app/less/app.less') - .pipe(less({paths: ['less/app.less']}).on('error',function(e){ - console.log('File:', e.fileName); - console.log('Line:', e.lineNumber); - console.log('Message:', e.message); - this.emit('end'); - })) - .pipe(minifyCSS()) - .pipe(gulp.dest('build')); -}); - -gulp.task('js-lint', function() { - return gulp.src(['app/js/**/*.js', '!app/js/template_cache.js', '!app/js/db.js']) - .pipe(eslint({ - globals: { angular:1, DB:1, d3:1, ga:1, GAPI_KEY:1, LZString: 1 }, - rules: { - quotes: [2, 'single'], - strict: 'global', - eqeqeq: 'smart', - 'space-after-keywords': [2, 'always'], - 'no-use-before-define': 'no-func', - 'space-before-function-paren': [2, 'never'], - 'space-before-blocks': [2, 'always'], - 'object-curly-spacing': [2, "always"], - 'brace-style': [2, '1tbs', { allowSingleLine: true }], - 'no-control-regex': false - }, - envs: ['browser'] - })) - .pipe(eslint.format()) - .pipe(eslint.failAfterError()); -}); - -gulp.task('json-lint', function() { - return gulp.src(['data/**/*.json' , 'app/schemas/**/*.json']) - .pipe(jsonlint()) - .pipe(jsonlint.reporter()) - .pipe(jsonlint.failAfterError()); -}); - -gulp.task('bower', function(){ - return gulp.src(mainBowerFiles()) - .pipe(uglify({mangle: false, compress: false}).on('error',function(e){ - console.log('Bower File:', e.fileName); - console.log('Line:', e.lineNumber); - console.log('Message:', e.message); - })) - .pipe(concat('lib.js')) - .pipe(gulp.dest('build')); -}); - -gulp.task('html2js', function() { - return gulp.src('app/views/**/*.html') - .pipe(htmlmin({ - 'collapseBooleanAttributes': true, - 'collapseWhitespace': true, - 'removeAttributeQuotes': true, - 'removeComments': true, - 'removeEmptyAttributes': true, - 'removeRedundantAttributes': true, - 'removeScriptTypeAttributes': true, - 'removeStyleLinkTypeAttributes': true - }).on('error',function(e){ - console.log('File:', e.fileName); - console.log('Message:',e.message); - })) - .pipe(templateCache({ - 'module': 'app.templates', - 'standalone': true, - 'root': 'views', - 'filename': 'template_cache.js' - })) - .pipe(gulp.dest('app/js')) -}); - -gulp.task('jsonToDB', function(cb) { - exec('node scripts/json-to-db.js', cb); -}); - -gulp.task('js', function() { - return gulp.src([ - 'app/js/db.js', - 'app/js/**/module-*.js', - 'app/js/template_cache.js', - 'app/js/app.js', - 'app/js/**/*.js' - ]) - .pipe(sourcemaps.init()) - .pipe(uglify({mangle: false}).on('error',function(e){ - console.log('File:', e.fileName); - console.log('Line:', e.lineNumber); - console.log('Message:', e.message); - this.emit('end'); - })) - .pipe(concat('app.js')) - .pipe(sourcemaps.write('.')) - .pipe(gulp.dest('build')); -}); - -gulp.task('copy', function() { - return gulp.src(['app/images/**','app/fonts/**','app/db.json', 'app/schemas/**'], {base: 'app/'}) - .pipe(gulp.dest('build')); -}); - -gulp.task('generateIndexHTML', function(done) { - // Generate minified inline svg of all icons for svg spriting - gulp.src('app/icons/*.svg') - .pipe(svgmin()) - .pipe(svgstore({ inlineSvg: true })) - .pipe(gutil.buffer(function(err, files) { - var svgIconsContent = files[0].contents.toString(); - gulp.src('app/index.html') - .pipe(template({ - version: pkg.version, - date : new Date().toISOString().slice(0, 10), - uaTracking: process.env.CORIOLIS_UA_TRACKING || false, - svgContent: svgIconsContent, - gapiKey: process.env.CORIOLIS_GAPI_KEY - })) - .pipe(htmlmin({ - 'collapseBooleanAttributes': true, - 'collapseWhitespace': true, - 'removeAttributeQuotes': true, - 'removeComments': true, - 'removeEmptyAttributes': true, - 'removeRedundantAttributes': true, - 'removeScriptTypeAttributes': true, - 'removeStyleLinkTypeAttributes': true - }).on('error',function(e){ - console.log('File:', e.fileName); - console.log('Message:',e.message); - })) - .pipe(gulp.dest('build')); - done(); - })); -}); - -gulp.task('serve', function(cb) { - exec('nginx -p $(pwd) -c nginx.conf', function (err, stdout, stderr) { - if (stderr) { - console.warn(stderr); - console.warn('Is NGINX already running?\n'); - } - cb(); - }); -}); - -// Windows command to launch nginx serv -gulp.task('serve-win', function(cb) { - exec('nginx -p %cd% -c nginx.conf', function (err, stdout, stderr) { - if (stderr) { - console.warn(stderr); - console.warn('Is NGINX already running?\n'); - } - cb(); - }); -}); - -gulp.task('serve-stop', function(cb) { - exec('kill -QUIT $(cat nginx.pid)', function (err, stdout, stderr) { - if (stderr) console.log(stderr); else cb(err); - }); -}); - -gulp.task('watch', function() { - gulp.watch(['app/index.html','app/icons/*.svg'], ['generateIndexHTML']); - gulp.watch(['app/images/**','app/fonts/**', 'app/db.json', 'app/schemas/**'], ['copy']); - gulp.watch('app/less/*.less', ['less']); - gulp.watch('app/views/**/*', ['html2js']); - gulp.watch('app/js/**/*.js', ['js']); - gulp.watch('data/**/*.json', ['jsonToDB']); - gulp.watch(['build/**', '!**/*.appcache'], ['appcache']); -}); - -gulp.task('cache-bust', function(done) { - var rev_all = new revAll({ prefix: cdnHostStr, dontRenameFile: ['.html','.json'] }); - var stream = gulp.src('build/**') - .pipe(rev_all.revision()) - .pipe(gulp.dest('build')) - .pipe(rev_all.manifestFile()) - .pipe(gulp.dest('build')); - - stream.on('end', function() { - var manifest = require('./build/rev-manifest.json'); - var arr = []; - for(var origFileName in manifest) { - if(origFileName != manifest[origFileName]) { // For all files busted/renamed - arr.push('./build/' + origFileName); // Add the original filename to the list - } - } - del(arr, done); // Delete all originals files the were not busted/renamed - }); - stream.on('error', done); -}); - -gulp.task('appcache', function(done) { - // Since using a CDN manually build file list rather than using appCache mechanisms - gulp.src(['build/**', '!build/index.html', '!**/*.json', '!**/logo/*', '!**/*.map','!**/*.appcache']) - .pipe(gutil.buffer(function(err, stream) { - var files = []; - for (var i = 0; i < stream.length; i++) { - if (!stream[i].isNull()) { - files.push(cdnHostStr + '/' + stream[i].relative); - } - } - - gulp.src([]) - .pipe(appCache({ - preferOnline: true, - cache: files, - filename: 'coriolis.appcache', - timestamp: true - })) - .pipe(gulp.dest('build')) - .on('end', done); - })); -}); - -gulp.task('upload', function(done) { - exec([ - "rsync -e 'ssh -i ", process.env.CORIOLIS_PEM, "' -a --delete build/ ", process.env.CORIOLIS_USER, "@", process.env.CORIOLIS_HOST, ":~/www" - ].join(''), - done - ); -}); - -gulp.task('test', function (done) { - karma.start({ - configFile: __dirname + '/test/karma.conf.js', - singleRun: true - }, function(exitStatus) { - done(exitStatus ? new gutil.PluginError('karma', { message: 'Unit tests failed!' }) : undefined); - }); -}); - -gulp.task('lint', ['js-lint', 'json-lint']); - -gulp.task('clean', function (done) { del(['build'], done); }); - -gulp.task('build', function (done) { runSequence('clean', ['html2js','jsonToDB'], ['generateIndexHTML','bower','js','less','copy'], done); }); -gulp.task('build-cache', function (done) { runSequence('build', 'appcache', done); }); -gulp.task('build-prod', function (done) { runSequence('build', 'cache-bust', 'appcache', done); }); - -gulp.task('dev', function (done) { runSequence('build-cache', 'serve','watch', done); }); - -gulp.task('deploy', function (done) { - cdnHostStr = '//cdn.' + process.env.CORIOLIS_HOST; - runSequence('build-prod', 'upload', done); -}); - -gulp.task('default', ['dev']); - diff --git a/nginx.conf b/nginx.conf deleted file mode 100755 index d9fa6a33..00000000 --- a/nginx.conf +++ /dev/null @@ -1,58 +0,0 @@ -worker_processes 2; -error_log ./nginx.error.log; -worker_rlimit_nofile 8192; -pid nginx.pid; - -events { - worker_connections 1024; - multi_accept on; -} - -http { - - access_log off; - charset UTF-8; - - types { - text/html html htm shtml; - text/css css; - text/xml xml rss; - image/gif gif; - image/jpeg jpeg jpg; - application/x-javascript js; - text/plain txt; - image/png png; - image/svg+xml svg; - image/x-icon ico; - application/pdf pdf; - text/cache-manifest appcache; - } - - gzip on; - gzip_vary on; - gzip_proxied any; - gzip_comp_level 6; - gzip_buffers 16 8k; - gzip_http_version 1.1; - gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; - - server { - listen 3300; - server_name localhost; - root ./build/; - index index.html; - - location ~* \.(?:manifest|appcache|html?|xml|json|css|js|map|jpg|jpeg|gif|png|ico|svg|eot|ttf|woff|woff2)$ { - expires -1; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Credentials true; - add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; - add_header Access-Control-Allow-Headers 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; - access_log off; - } - - location / { - try_files $uri $uri/ /index.html =404; - } - } -} diff --git a/package.json b/package.json index d9b6e733..9ac152b2 100644 --- a/package.json +++ b/package.json @@ -10,41 +10,45 @@ "private": true, "engine": "node >= 0.12.2", "license": "MIT", + "scripts": { + "clean": "rimraf build", + "build:prod": "NODE_ENV=production webpack --config webpack.config.prod.js", + "build": "npm run clean && npm run build:prod", + "start": "node devServer.js", + "lint": "eslint src" + }, "devDependencies": { - "async": "0.9.x", - "del": "1.2.x", - "gulp": "3.9.x", - "gulp-concat": "2.5.x", - "gulp-eslint": "0.13.x", - "gulp-jasmine": "2.0.x", - "gulp-jsonlint": "1.1.x", - "gulp-less": "3.0.x", - "gulp-manifest": "0.0.6", - "gulp-minify-css": "1.1.x", - "gulp-rev-all": "0.8.18", - "gulp-sourcemaps": "1.5.x", - "gulp-svgmin": "1.1.x", - "gulp-svgstore": "5.0.x", - "gulp-template": "3.0.x", - "gulp-uglify": "1.2.x", - "gulp-util": "3.0.x", - "jasmine-core": "2.3.x", - "jsen": "^0.6.0", - "json-concat": "0.0.x", - "karma": "0.12.x", - "karma-fixture": "^0.2.5", - "karma-jasmine": "0.3.x", - "karma-json-fixtures-preprocessor": "0.0.4", - "karma-mocha-reporter": "1.0.x", - "karma-phantomjs-launcher": "0.2.x", - "phantomjs": "1.9.x", - "run-sequence": "1.1.x", - "uglify-js": "2.4.x" + "babel-core": "^5.4.7", + "babel-eslint": "^3.1.9", + "babel-loader": "^5.1.2", + "babel-plugin-react-transform": "^1.1.1", + "css-loader": "^0.23.0", + "eslint": "^1.3.1", + "eslint-plugin-react": "^2.3.0", + "express": "^4.13.3", + "file-loader": "^0.8.4", + "install": "^0.3.0", + "json-loader": "^0.5.3", + "less": "^2.5.3", + "less-loader": "^2.2.1", + "npm": "^3.4.0", + "react-transform-catch-errors": "^1.0.0", + "react-transform-hmr": "^1.0.0", + "redbox-react": "^1.0.1", + "rimraf": "^2.4.3", + "style-loader": "^0.13.0", + "url-loader": "^0.5.6", + "webpack": "^1.9.6", + "webpack-dev-middleware": "^1.2.0", + "webpack-hot-middleware": "^2.0.0" }, "dependencies": { "classnames": "^2.2.0", + "d3": "^3.5.9", "fbemitter": "^2.0.0", + "lz-string": "^1.4.4", "react": "^0.14.2", - "react-dom": "^0.14.2" + "react-dom": "^0.14.2", + "superagent": "^1.4.0" } } diff --git a/scripts/json-to-db.js b/scripts/json-to-db.js deleted file mode 100755 index 67df0606..00000000 --- a/scripts/json-to-db.js +++ /dev/null @@ -1,90 +0,0 @@ -var fs = require('fs'); -var UglifyJS = require('uglify-js'); -var jsonConcat = require('json-concat'); -var async = require('async'); -var db_filename = './app/js/db.js'; - -async.parallel([ - function(cb) { jsonConcat({ dest: null, src: './data/ships' }, done.bind(cb)); }, - function(cb) { - var standard = [ - JSON.parse(fs.readFileSync('./data/components/standard/power_plant.json', 'utf8')), - JSON.parse(fs.readFileSync('./data/components/standard/thrusters.json', 'utf8')), - JSON.parse(fs.readFileSync('./data/components/standard/frame_shift_drive.json', 'utf8')), - JSON.parse(fs.readFileSync('./data/components/standard/life_support.json', 'utf8')), - JSON.parse(fs.readFileSync('./data/components/standard/power_distributor.json', 'utf8')), - JSON.parse(fs.readFileSync('./data/components/standard/sensors.json', 'utf8')), - JSON.parse(fs.readFileSync('./data/components/standard/fuel_tank.json', 'utf8')) - ]; - cb(null, standard); - }, - function(cb) { jsonConcat({ dest: null, src: './data/components/hardpoints' }, done.bind(cb)); }, - function(cb) { jsonConcat({ dest: null, src: './data/components/internal' }, done.bind(cb)); }, - function(cb) { jsonConcat({ dest: null, src: ['./data/components/bulkheads.json'] }, done.bind(cb)); } - ], writeDB); - -function done(err, json) { this(err,json); } - -function writeDB(err, arr) { - var ships = {}, internal = {}, hardpoints = {}; - var shipOrder = Object.keys(arr[0]).sort(function(a,b) { return arr[0][a].properties.name < arr[0][b].properties.name ? -1 : 1; }); - var internalOrder = Object.keys(arr[3]).sort(); - var hpOrder = [ - "pl", - "ul", - "bl", - "mc", - "c", - "fc", - "rg", - "pa", - "mr", - "tp", - "nl", - "ml", - "cs", - "cm", - "ws", - "kw", - "sb" - ]; - - for (var i = 0; i < internalOrder.length; i++) { - internal[internalOrder[i]] = arr[3][internalOrder[i]]; - } - - for (var j = 0; j < hpOrder.length; j++) { - hardpoints[hpOrder[j]] = arr[2][hpOrder[j]]; - } - - for (var s = 0; s < shipOrder.length; s++) { - ships[shipOrder[s]] = arr[0][shipOrder[s]]; - } - - try { - var db = { - ships: ships, - components: { - standard: arr[1], - hardpoints: hardpoints, - internal: internal, - bulkheads: arr[4] - } - }; - } - catch (e) { - console.error(arguments); - exit(0); - } - - var ast = UglifyJS.parse('var DB = ' + JSON.stringify(db)); - var code = ast.print_to_string({beautify: true, indent_level: 2}); - - fs.open(db_filename, 'w', function() { - fs.writeFile(db_filename, code, function(err) {}); - }); - - fs.open('./app/db.json', 'w', function() { - fs.writeFile('./app/db.json', JSON.stringify(db), function(err) {}); - }); -} diff --git a/src/app/Coriolis.jsx b/src/app/Coriolis.jsx new file mode 100644 index 00000000..466cd826 --- /dev/null +++ b/src/app/Coriolis.jsx @@ -0,0 +1,110 @@ +import React from 'react'; +import Router from './Router'; +import { getLanguage } from './i18n/Language'; +import Persist from './stores/Persist'; +import InterfaceEvents from './utils/InterfaceEvents'; + +import Header from './components/Header'; +import AboutPage from './pages/AboutPage'; +import NotFoundPage from './pages/NotFoundPage'; +import OutfittingPage from './pages/OutfittingPage'; +import ShipyardPage from './pages/ShipyardPage'; + +export default class Coriolis extends React.Component { + + static childContextTypes = { + language: React.PropTypes.object.isRequired, + route: React.PropTypes.object + }; + + constructor() { + super(); + this._setPage = this._setPage.bind(this); + + this.state = { + page: null, + language: getLanguage(Persist.getLangCode()), + route: null + }; + + Router('', (r) => this._setPage(ShipyardPage, r)); + // Router('/', (ctx) => this._setPage(ShipyardPage, ctx)); + Router('/outfitting/:ship', (r) => this._setPage(OutfittingPage, r)); + Router('/outfitting/:ship/:code', (r) => this._setPage(OutfittingPage, r)); + // Router('/compare/:name', compare); + // Router('/comparison/:code', comparison); + // Router('/settings', settings); + Router('/about', (r) => this._setPage(AboutPage, r)); + Router('*', (r) => this._setPage(null, r)); + } + + _setPage(page, route) { + this.setState({ page, route }); + } + + _onError(msg, scriptUrl, line, col, errObj) { + this._setPage(
    Some errors occured!!
    ); + } + + _onLanguageChange(lang) { + this.setState({ language: getLanguage(Persist.getLangCode()) }); + } + + _keyDown(e) { + switch (e.keyCode) { + case 27: + InterfaceEvents.closeAll(); + this._hideModal(); + break; + } + } + + _showModal(content) { + let modal =
    this._hideModal() }>{content}
    ; + this.setState({ modal }); + } + + _hideModal() { + if (this.state.modal) { + this.setState({ modal: null }); + } + } + + getChildContext() { + return { + language: this.state.language, + route: this.state.route + }; + } + + componentWillMount() { + // Listen for appcache updated event, present refresh to update view + if (window.applicationCache) { + window.applicationCache.addEventListener('updateready', () => { + if (window.applicationCache.status == window.applicationCache.UPDATEREADY) { + this.setState({appCacheUpdate: true}); // Browser downloaded a new app cache. + } + }, false); + } + + window.onerror = this._onError.bind(this); + document.addEventListener('keydown', this._keyDown.bind(this)); + Persist.addListener('language', this._onLanguageChange.bind(this)); + Persist.addListener('language', this._onLanguageChange.bind(this)); + InterfaceEvents.addListener('showModal', this._showModal.bind(this)); + InterfaceEvents.addListener('hideModal', this._hideModal.bind(this)); + + Router.start(); + } + + + render() { + return ( +
    +
    + {this.state.page? : } + {this.state.modal} +
    + ); + } +} diff --git a/app/js/Router.js b/src/app/Router.js similarity index 93% rename from app/js/Router.js rename to src/app/Router.js index f4132029..c5929c7d 100644 --- a/app/js/Router.js +++ b/src/app/Router.js @@ -1,4 +1,5 @@ -import Persist from 'stores/Persist'; +import Persist from './stores/Persist'; +import InterfaceEvents from './utils/InterfaceEvents'; function isStandAlone() { try { @@ -35,19 +36,6 @@ function Router(path, fn) { Router.callbacks = []; -/** - * Bind with the given `options`. - * - * Options: - * - * - `click` bind to click events [true] - * - `popstate` bind to popstate [true] - * - `dispatch` perform initial dispatch [true] - * - * @param {Object} options - * @api public - */ - Router.start = function(){ window.addEventListener('popstate', onpopstate, false); @@ -62,7 +50,7 @@ Router.start = function(){ } } else { var url = location.pathname + location.search + location.hash; - Router.replace(url, null, true, dispatch); + Router.replace(url, null, true, true); } }; @@ -76,8 +64,9 @@ Router.start = function(){ */ Router.go = function(path, state) { gaTrack(path); + InterfaceEvents.closeAll(); var ctx = new Context(path, state); - if (false !== dispatch) Router.dispatch(ctx); + Router.dispatch(ctx); if (!ctx.unhandled) ctx.pushState(); return ctx; }; @@ -95,8 +84,7 @@ Router.replace = function(path, state, init, dispatch) { gaTrack(path); var ctx = new Context(path, state); ctx.init = init; - if (null == dispatch) dispatch = true; - if (dispatch) Router.dispatch(ctx); + if (dispatch !== false) Router.dispatch(ctx); ctx.save(); return ctx; }; diff --git a/src/app/components/ActiveLink.jsx b/src/app/components/ActiveLink.jsx new file mode 100644 index 00000000..dfb5228c --- /dev/null +++ b/src/app/components/ActiveLink.jsx @@ -0,0 +1,20 @@ +import React from 'react'; +import Link from './Link'; +import cn from 'classnames'; + +export default class ActiveLink extends Link { + + isActive = () => { + return encodeURI(this.props.href) == (window.location.pathname + window.location.search); + } + + render() { + let className = this.props.className; + if (this.isActive()) { + className = cn(className, 'active'); + } + + return {this.props.children} + } + +} \ No newline at end of file diff --git a/src/app/components/AvailableModulesMenu.jsx b/src/app/components/AvailableModulesMenu.jsx new file mode 100644 index 00000000..95bb4bc5 --- /dev/null +++ b/src/app/components/AvailableModulesMenu.jsx @@ -0,0 +1,103 @@ +import React from 'react'; +import { findDOMNode } from 'react-dom'; +import TranslatedComponent from './TranslatedComponent'; +import cn from 'classnames'; +import { MountFixed, MountGimballed, MountTurret } from './SvgIcons'; + +export default class AvailableModulesMenu extends TranslatedComponent { + + static propTypes = { + modules: React.PropTypes.oneOfType([ React.PropTypes.object, React.PropTypes.array ]).isRequired, + onSelect: React.PropTypes.func.isRequired, + m: React.PropTypes.object, + shipMass: React.PropTypes.number, + warning: React.PropTypes.func + }; + + static defaultProps = { + shipMass: 0 + }; + + buildGroup(translate, mountedModule, warningFunc, mass, onSelect, grp, modules) { + let prevClass = null, prevRating = null; + let elems = []; + + for (let i = 0; i < modules.length; i++) { + let m = modules[i]; + let classRating = m.class + m.rating; + let mount = null; + let classes = cn(m.name ? 'lc' : 'c', { + active: mountedModule && mountedModule.id === m.id, + warning: warningFunc && warningFunc(m), + disabled: m.maxmass && (mass + (m.mass ? m.mass : 0)) > m.maxmass + }); + + switch(m.mode) { + case 'F': mount = ; break; + case 'G': mount = ; break; + case 'T': mount = ; break; + } + + if (i > 0 && modules.length > 3 && m.class != prevClass && (m.rating != prevRating || m.mode) && m.grp != 'pa') { + elems.push(
    ); + } + + elems.push( +
  • + {mount} + {(mount ? ' ' : '') + m.class + m.rating + (m.missile ? '/' + m.missile : '') + (m.name ? ' ' + translate(m.name) : '')} +
  • + ); + prevClass = m.class; + prevRating = m.rating; + } + + return
      {elems}
    ; + } + + componentDidMount() { + let m = this.props.m + + if (!(this.props.modules instanceof Array) && m && m.grp) { + findDOMNode(this).scrollTop = this.refs[m.grp].offsetTop; // Scroll to currently selected group + } + } + + render() { + let translate = this.context.language.translate; + let m = this.props.m; + let modules = this.props.modules; + let list; + let buildGroup = this.buildGroup.bind( + null, + translate, + m, + this.props.warning, + this.props.shipMass - (m && m.mass ? m.mass : 0), + this.props.onSelect + ); + + if (modules instanceof Array) { + console.log(modules[0].grp, modules); + list = buildGroup(modules[0].grp, modules); + } else { + console.log('menu object') + list = []; + // At present time slots with grouped options (Hardpoints and Internal) can be empty + list.push(
    {translate('empty')}
    ); + for (let g in modules) { + let grp = modules[g]; + let grpCode = grp[Object.keys(grp)[0]].grp; // Nasty operation to get the grp property of the first/any single component + list.push(
    {translate(g)}
    ); + list.push(buildGroup(g, modules[g])); + } + } + + return ( +
    e.stopPropagation() }> + {list} +
    + ); + } + +} diff --git a/src/app/components/HardpointSlot.jsx b/src/app/components/HardpointSlot.jsx new file mode 100644 index 00000000..6c4dfab6 --- /dev/null +++ b/src/app/components/HardpointSlot.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import Slot from './Slot'; + +export default class HardpointSlot extends Slot { + + getClassNames() { + return this.props.size > 0 ? 'hardpoint' : null; + } + + getSize(translate){ + return translate(['U','S','M','L','H'][this.props.size]); + } + + getSlotDetails(m, translate, formats, u) { + if (m) { + let classRating = `${m.class}${m.rating}${m.mode ? '/' + m.mode : ''}${m.missile ? m.missile : ''}`; + return ( +
    +
    {classRating + ' ' + translate(m.name || m.grp)}
    +
    {m.mass}{u.T}
    +
    + { m.damage ?
    {translate('damage')}: {m.damage} { m.ssdam ? ({formats.int(m.ssdam)} {u.MJ}) : null }
    : null } + { m.dps ?
    {translate('DPS')}: {m.dps} { m.mjdps ? ({formats.int(m.mjdps)} {u.MJ}) : null }
    : null } + { m.thermload ?
    {translate('T_LOAD')}: {m.thermload}
    : null } + { m.type ?
    {translate('type')}: {m.type}
    : null } + { m.rof ?
    {translate('ROF')}: {m.rof}{u.ps}
    : null } + { m.armourpen ?
    {translate('pen')}: {m.armourpen}
    : null } + { m.shieldmul ?
    +{formats.rPct(m.shieldmul)}
    : null } + { m.range ?
    {m.range} km
    : null } + { m.ammo >= 0 ?
    {translate('ammo')}: {formats.int(m.clip)}+{formats.int(m.ammo)}
    : null } +
    +
    + ); + } else { + return
    {translate('empty')}
    ; + } + } +} diff --git a/src/app/components/HardpointsSlotSection.jsx b/src/app/components/HardpointsSlotSection.jsx new file mode 100644 index 00000000..b4e3f386 --- /dev/null +++ b/src/app/components/HardpointsSlotSection.jsx @@ -0,0 +1,87 @@ +import React from 'react'; +import SlotSection from './SlotSection'; +import HardpointSlot from './HardpointSlot'; +import cn from 'classnames'; +import { MountFixed, MountGimballed, MountTurret } from '../components/SvgIcons'; + +export default class HardpointsSlotSection extends SlotSection { + + constructor(props, context) { + super(props, context, 'hardpoints', 'hardpoints'); + + this._empty = this._empty.bind(this); + } + + _empty() { + + } + + _fill(grp, mount) { + + } + + _getSlots() { + let slots = []; + let hardpoints = this.props.ship.hardpoints; + let availableModules = this.props.ship.getAvailableModules(); + let currentMenu = this.state.currentMenu; + + for (let i = 0, l = hardpoints.length; i < l; i++) { + let h = hardpoints[i]; + if (h.maxClass) { + slots.push(); + } + } + + return slots; + } + + _getSectionMenu(translate) { + let _fill = this._fill; + + return
    e.stopPropagation()}> +
      +
    • {translate('empty all')}
    • +
    +
    {translate('pl')}
    +
      +
    • +
    • +
    • +
    +
    {translate('ul')}
    +
      +
    • +
    • +
    • +
    +
    {translate('bl')}
    +
      +
    • +
    • +
    • +
    +
    {translate('mc')}
    +
      +
    • +
    • +
    • +
    +
    {translate('c')}
    +
      +
    • +
    • +
    • +
    +
    ; + } + +} diff --git a/src/app/components/Header.jsx b/src/app/components/Header.jsx new file mode 100644 index 00000000..875bbb99 --- /dev/null +++ b/src/app/components/Header.jsx @@ -0,0 +1,251 @@ +import React from 'react'; +import TranslatedComponent from './TranslatedComponent'; +import Link from './Link'; +import ActiveLink from './ActiveLink'; +import cn from 'classnames'; +import { Cogs, CoriolisLogo, Hammer, Rocket, StatsBars } from './SvgIcons'; +import Ships from '../shipyard/Ships'; +import InterfaceEvents from '../utils/InterfaceEvents'; +import Persist from '../stores/Persist'; +import ModalDeleteAll from './ModalDeleteAll'; + +export default class Header extends TranslatedComponent { + + constructor(props) { + super(props); + this.state = { + openedMenu: null + }; + + this._close = this._close.bind(this); + this.shipOrder = Object.keys(Ships).sort(); + } + + _close() { + this.setState({ openedMenu: null }); + } + + _setInsurance(e) { + e.stopPropagation(); + Persist.setInsurance('Beta'); // TODO: get insurance name + } + + _setModuleDiscount(e) { + e.stopPropagation(); + Persist.setModuleDiscount(0); // TODO: get module discount + } + + _setShipDiscount(e) { + e.stopPropagation(); + Persist.setShipDiscount(0); // TODO: get ship discount + } + + _showDeleteAll(e) { + e.preventDefault(); + InterfaceEvents.showModal(); + this._close(); + }; + + _showBackup(e) { + e.preventDefault(); + /*$state.go('modal.export', { + title: 'backup', + data: Persist.getAll(), + description: 'PHRASE_BACKUP_DESC' + });*/ + // TODO: implement modal + }; + + _showDetailedExport(e){ + e.preventDefault(); + e.stopPropagation(); + + /*$state.go('modal.export', { + title: 'detailed export', + data: Serializer.toDetailedExport(Persist.getBuilds()), + description: 'PHRASE_EXPORT_DESC' + });*/ + // TODO: implement modal + } + + _setTextSize(size) { + Persist.setSizeRatio(size); // TODO: implement properly + } + + _resetTextSize() { + Persist.setSizeRatio(1); + } + + _openMenu(event, openedMenu) { + event.stopPropagation(); + + if (this.state.openedMenu == openedMenu) { + openedMenu = null; + } + + this.setState({ openedMenu }); + } + + _getShipsMenu() { + let shipList = []; + + for (let s in Ships) { + shipList.push({Ships[s].properties.name}); + } + + return ( +
    e.stopPropagation() }> + {shipList} +
    + ); + } + + _getBuildsMenu() { + let builds = Persist.getBuilds(); + let buildList = []; + for (let shipId of this.shipOrder) { + if (builds[shipId]) { + let shipBuilds = []; + let buildNameOrder = Object.keys(builds[shipId]).sort(); + for (let buildName of buildNameOrder) { + let href = ['/outfitting/', shipId, '/', builds[shipId][buildName], '?bn=', buildName].join(''); + shipBuilds.push(
  • {buildName}
  • ); + } + buildList.push(
      {Ships[shipId].properties.name}{shipBuilds}
    ); + } + } + + return ( +
    e.stopPropagation() }> +
    {buildList}
    +
    + ); + } + + _getComparisonsMenu() { + let comparisons; + let translate = this.context.language.translate; + + if (Persist.hasComparisons()) { + let comparisons = []; + let comps = Object.keys(Persist.getComparisons()).sort(); + console.log(comps); + + for (let name of comps) { + comparisons.push({name}); + } + } else { + comparisons = {translate('none created')}; + } + + return ( +
    e.stopPropagation() } style={{ whiteSpace: 'nowrap' }}> + {comparisons} +
    + {translate('compare all')} + {translate('create new')} +
    + ); + } + + _getSettingsMenu() { + let translate = this.context.language.translate; + + return ( +
    e.stopPropagation() }> +
      + {translate('language')} +
    • +

    +
      + {translate('insurance')} +
    • +

    +
      + {translate('ship')} {translate('discount')} +
    • +

    +
      + {translate('component')} {translate('discount')} +
    • +
    +
    + +
    + + + + + + + + + + + +
    AA
    +
    + {translate('about')} +
    + ); + } + + componentWillMount() { + this.closeAllListener = InterfaceEvents.addListener('closeAll', this._close); + } + + componentWillUnmount() { + this.closeAllListener.remove(); + } + + render() { + let translate = this.context.language.translate; + let openedMenu = this.state.openedMenu; + let hasBuilds = Persist.hasBuilds(); + + if (this.props.appCacheUpdate) { + return
    { 'PHRASE_UPDATE_RDY' | translate }
    ; + } + + return ( +
    + + +
    +
    this._openMenu(e,'s') } > + {' ' + translate('ships')} +
    + {openedMenu == 's' ? this._getShipsMenu() : null} +
    + +
    +
    this._openMenu(e,'b') : null }> + {' ' + translate('builds')} +
    + {openedMenu == 'b' ? this._getBuildsMenu() : null} +
    + +
    +
    this._openMenu(e,'comp') : null }> + {' ' + translate('compare')} +
    + {openedMenu == 'comp' ? this._getComparisonsMenu() : null} +
    + +
    +
    this._openMenu(e,'settings') }> + {translate('settings')} +
    + {openedMenu == 'settings' ? this._getSettingsMenu() : null} +
    +
    + ); + } + +} \ No newline at end of file diff --git a/src/app/components/InternalSlot.jsx b/src/app/components/InternalSlot.jsx new file mode 100644 index 00000000..dcf30582 --- /dev/null +++ b/src/app/components/InternalSlot.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import Slot from './Slot'; +import { Infinite } from './SvgIcons'; + +export default class InternalSlot extends Slot { + + getSlotDetails(m, translate, formats, u) { + if (m) { + let classRating = m.class + m.rating; + + return ( +
    +
    {classRating + ' ' + translate(m.name || m.grp)}
    +
    {m.mass || m.capacity || 0}{u.T}
    +
    + { m.optmass ?
    {translate('optimal mass') + ': '}{m.optmass}{u.T}
    : null } + { m.maxmass ?
    {translate('max mass') + ': '}{m.maxmass}{u.T}
    : null } + { m.bins ?
    {m.bins + ' '}{translate('bins')}
    : null } + { m.rate ?
    {translate('rate')}: {m.rate}{u.kgs}   {translate('refuel time')}: {formats.time(this.props.fuel * 1000 / m.rate)}
    : null } + { m.ammo ?
    {translate('ammo')}: {formats.gen(m.ammo)}
    : null } + { m.cells ?
    {translate('cells')}: {m.cells}
    : null } + { m.recharge ?
    {translate('recharge')}: {m.recharge} MJ   {translate('total')}: {m.cells * m.recharge}{u.MJ}
    : null } + { m.repair ?
    {translate('repair')}: {m.repair}
    : null } + { m.range ?
    {translate('range')} {m.range}{u.km}
    : null } + { m.time ?
    {translate('time')}: {formats.time(m.time)}
    : null } + { m.maximum ?
    {translate('max')}: {(m.maximum)}
    : null } + { m.rangeLS ?
    {m.rangeLS}{u.Ls}
    : null } + { m.rangeLS === null ?
    {u.Ls}
    : null } + { m.rangeRating ?
    {translate('range')}: {m.rangeRating}
    : null } + { m.armouradd ?
    +{m.armouradd} {translate('armour')}
    : null } +
    +
    + ); + } else { + return
    {translate('empty')}
    ; + } + } +} diff --git a/src/app/components/InternalSlotSection.jsx b/src/app/components/InternalSlotSection.jsx new file mode 100644 index 00000000..28b8c793 --- /dev/null +++ b/src/app/components/InternalSlotSection.jsx @@ -0,0 +1,69 @@ +import React from 'react'; +import SlotSection from './SlotSection'; +import InternalSlot from './InternalSlot'; +import cn from 'classnames'; + + +export default class InternalSlotSection extends SlotSection { + + constructor(props, context) { + super(props, context, 'internal', 'internal compartments'); + + this._empty = this._empty.bind(this); + this._fillWithCargo = this._fillWithCargo.bind(this); + this._fillWithCells = this._fillWithCells.bind(this); + this._fillWithArmor = this._fillWithArmor.bind(this); + } + + _empty() { + + } + + _fillWithCargo() { + + } + + _fillWithCells() { + + } + + _fillWithArmor() { + + } + + _getSlots() { + let slots = []; + let {internal, fuelCapacity, ladenMass } = this.props.ship; + let availableModules = this.props.ship.getAvailableModules(); + let currentMenu = this.state.currentMenu; + + for (let i = 0, l = internal.length; i < l; i++) { + let s = internal[i]; + slots.push(); + } + + return slots; + } + + _getSectionMenu(translate) { + return
    e.stopPropagation()}> +
      +
    • {translate('empty all')}
    • +
    • {translate('cargo')}
    • +
    • {translate('scb')}
    • +
    • {translate('hr')}
    • +
    +
    ; + } + +} diff --git a/src/app/components/Link.jsx b/src/app/components/Link.jsx new file mode 100644 index 00000000..fdf73cb9 --- /dev/null +++ b/src/app/components/Link.jsx @@ -0,0 +1,31 @@ +import React from 'react'; +import Router from '../Router'; +import shallowEqual from '../utils/shallowEqual'; + +export default class Link extends React.Component { + + shouldComponentUpdate(nextProps) { + return !shallowEqual(this.props, nextProps); + } + + handler = (event) => { + if (event.getModifierState + && ( event.getModifierState('Shift') + || event.getModifierState('Alt') + || event.getModifierState('Control') + || event.getModifierState('Meta') + || event.button > 1)) { + return; + } + event.nativeEvent && event.preventDefault && event.preventDefault(); + + if (this.props.href) { + Router.go(encodeURI(this.props.href)); + } + } + + render() { + return {this.props.children} + } + +} \ No newline at end of file diff --git a/src/app/components/ModalDeleteAll.jsx b/src/app/components/ModalDeleteAll.jsx new file mode 100644 index 00000000..1bfda0d6 --- /dev/null +++ b/src/app/components/ModalDeleteAll.jsx @@ -0,0 +1,22 @@ +import React from 'react'; +import TranslatedComponent from './TranslatedComponent'; +import InterfaceEvents from '../utils/InterfaceEvents'; + +export default class ModalDeleteAll extends TranslatedComponent { + + _deleteAll() { + Persist.deleteAll(); + InterfaceEvents.hideModal(); + } + + render() { + let translate = this.context.language.translate; + + return
    e.stopPropagation()}> +

    {translate('delete all')}

    +

    {translate('PHRASE_CONFIRMATION')}

    + + +
    ; + } +} diff --git a/src/app/components/ModalExport.jsx b/src/app/components/ModalExport.jsx new file mode 100644 index 00000000..db966748 --- /dev/null +++ b/src/app/components/ModalExport.jsx @@ -0,0 +1,49 @@ +import React from 'react'; +import TranslatedComponent from './TranslatedComponent'; +import InterfaceEvents from '../utils/InterfaceEvents'; + +export default class DeleteAllModal extends TranslatedComponent { + + static propTypes = { + title: React.propTypes.string, + promise: : React.propTypes.func, + data: React.propTypes.oneOfType[React.propTypes.string, React.propTypes.object] + }; + + constructor(props) { + super(props); + let exportJson; + + if (props.promise) { + exportJson = 'Generating...'; + } else if(typeof props.data == 'string') { + exportJson = props.data; + } else { + exportJson = JSON.stringify(this.props.data); + } + + this.state = { exportJson }; + } + + componentWillMount(){ + // When promise is done update exportJson accordingly + } + + render() { + let translate = this.context.language.translate; + let description; + + if (this.props.description) { + description =
    {translate(this.props.description)}
    + } + + return
    e.stopPropagation() }> +

    {translate(this.props.title || 'Export')}

    + {description} +
    + +
    + +
    ; + } +} diff --git a/src/app/components/ModalImport.jsx b/src/app/components/ModalImport.jsx new file mode 100644 index 00000000..0b974acb --- /dev/null +++ b/src/app/components/ModalImport.jsx @@ -0,0 +1,439 @@ +import React from 'react'; +import cn from 'classnames'; +import TranslatedComponent from './TranslatedComponent'; +import InterfaceEvents from '../utils/InterfaceEvents'; +import Persist from '../stores/Persist'; +import Ships from '../shipyard/Ships'; +import Ship from '../shipyard/Ship'; +import * as ModuleUtils from '../shipyard/ModuleUtils'; +import { Download } from './SvgIcons'; + + +const textBuildRegex = new RegExp('^\\[([\\w \\-]+)\\]\n'); +const lineRegex = new RegExp('^([\\dA-Z]{1,2}): (\\d)([A-I])[/]?([FGT])?([SD])? ([\\w\\- ]+)'); +const mountMap = { 'H': 4, 'L': 3, 'M': 2, 'S': 1, 'U': 0 }; +const standardMap = { 'RB': 0, 'TM': 1, 'FH': 2, 'EC': 3, 'PC': 4, 'SS': 5, 'FS': 6 }; +const bhMap = { 'lightweight alloy': 0, 'reinforced alloy': 1, 'military grade composite': 2, 'mirrored surface composite': 3, 'reactive surface composite': 4 }; + +function isEmptySlot(slot) { + return slot.maxClass == this && slot.m === null; +} + +function equalsIgnoreCase(str) { + return str.toLowerCase() == this.toLowerCase(); +} + +function validateBuild(shipId, code, name) { + let shipData = Ships[shipId]; + + if (!shipData) { + throw '"' + shipId + '" is not a valid Ship Id!'; + } + if (typeof name != 'string' || name.length == 0) { + throw shipData.properties.name + ' build "' + name + '" must be a string at least 1 character long!'; + } + if (typeof code != 'string' || code.length < 10) { + throw shipData.properties.name + ' build "' + name + '" is not valid!'; + } + try { + Serializer.toShip(new Ship(shipId, shipData.properties, shipData.slots), code); + } catch (e) { + throw shipData.properties.name + ' build "' + name + '" is not valid!'; + } +} + +function detailedJsonToBuild(detailedBuild) { + let ship; + if (!detailedBuild.name) { + throw 'Build Name missing!'; + } + + if (!detailedBuild.name.trim()) { + throw 'Build Name must be a string at least 1 character long!'; + } + + try { + ship = Serializer.fromDetailedBuild(detailedBuild); + } catch (e) { + throw detailedBuild.ship + ' Build "' + detailedBuild.name + '": Invalid data'; + } + + return { shipId: ship.id, name: detailedBuild.name, code: Serializer.fromShip(ship) }; +} + +export default class ModalImport extends TranslatedComponent { + + static propTypes = { + title: React.propTypes.string, + promise: : React.propTypes.func, + data: React.propTypes.oneOfType[React.propTypes.string, React.propTypes.object] + }; + + constructor(props) { + super(props); + + this.state = { + builds: null, + canEdit: true, + comparisons: null, + discounts: null, + errorMsg: null, + importString: null, + importValid: false, + insurance: null + }; + + this._process = this._process.bind(this); + this._importBackup = this._importBackup.bind(this); + } + + _importBackup(importData) { + if (importData.builds && typeof importData.builds == 'object') { + for (let shipId in importData.builds) { + for (let buildName in importData.builds[shipId]) { + validateBuild(shipId, importData.builds[shipId][buildName], buildName); + } + } + this.setState({ builds: importData.builds }); + } else { + throw 'builds must be an object!'; + } + if (importData.comparisons) { + for (let compName in importData.comparisons) { + let comparison = importData.comparisons[compName]; + for (let i = 0, l = comparison.builds.length; i < l; i++) { + let build = comparison.builds[i]; + if (!importData.builds[build.shipId] || !importData.builds[build.shipId][build.buildName]) { + throw build.shipId + ' build "' + build.buildName + '" data is missing!'; + } + } + } + this.setState({ comparisons: importData.comparisons }); + } + if (importData.discounts instanceof Array && importData.discounts.length == 2) { + this.setState({ discounts: importData.discounts }); + } + if (typeof importData.insurance == 'string' && importData.insurance.length > 3) { + this.setState({ insurance: importData.insurance }); + } + } + + _importDetailedArray(importArr) { + let builds = {}; + for (let i = 0, l = importArr.length; i < l; i++) { + let build = this._detailedJsonToBuild(importArr[i]); + if (!builds[build.shipId]) { + builds[build.shipId] = {}; + } + builds[build.shipId][build.name] = build.code; + } + this.setState({ builds }); + } + + _importTextBuild(buildStr) { + let buildName = textBuildRegex.exec(buildStr)[1].trim(); + let shipName = buildName.toLowerCase(); + let shipId = null; + + for (let sId in Ships) { + if (Ships[sId].properties.name.toLowerCase() == shipName) { + shipId = sId; + break; + } + } + + if (!shipId) { + throw 'No such ship found: "' + buildName + '"'; + } + + let lines = buildStr.split('\n'); + let ship = new Ship(shipId, Ships[shipId].properties, Ships[shipId].slots); + ship.buildWith(null); + + for (let i = 1; i < lines.length; i++) { + let line = lines[i].trim(); + + if (!line) { continue; } + if (line.substring(0, 3) == '---') { break; } + + let parts = lineRegex.exec(line); + + if (!parts) { throw 'Error parsing: "' + line + '"'; } + + let typeSize = parts[1]; + let cl = parts[2]; + let rating = parts[3]; + let mount = parts[4]; + let missile = parts[5]; + let name = parts[6].trim(); + let slot, group; + + if (isNaN(typeSize)) { // Standard or Hardpoint + if (typeSize.length == 1) { // Hardpoint + let slotClass = mountMap[typeSize]; + + if (cl > slotClass) { throw cl + rating + ' ' + name + ' exceeds slot size: "' + line + '"'; } + + slot = _.find(ship.hardpoints, isEmptySlot, slotClass); + + if (!slot) { throw 'No hardpoint slot available for: "' + line + '"'; } + + group = _.find(GroupMap, equalsIgnoreCase, name); + + let hp = ModuleUtils.findHardpoint(group, cl, rating, group ? null : name, mount, missile); + + if (!hp) { throw 'Unknown component: "' + line + '"'; } + + ship.use(slot, hp, true); + + } else if (typeSize == 'BH') { + let bhId = bhMap[name.toLowerCase()]; + + if (bhId === undefined) { throw 'Unknown bulkhead: "' + line + '"'; } + + ship.useBulkhead(bhId, true); + + } else if (standardMap[typeSize] != undefined) { + let standardIndex = standardMap[typeSize]; + + if (ship.standard[standardIndex].maxClass < cl) { throw name + ' exceeds max class for the ' + ship.name; } + + ship.use(ship.standard[standardIndex], cl + rating, ModuleUtils.standard(standardIndex, cl + rating), true); + + } else { + throw 'Unknown component: "' + line + '"'; + } + } else { + if (cl > typeSize) { throw cl + rating + ' ' + name + ' exceeds slot size: "' + line + '"'; } + + slot = _.find(ship.internal, isEmptySlot, typeSize); + + if (!slot) { throw 'No internal slot available for: "' + line + '"'; } + + group = _.find(GroupMap, equalsIgnoreCase, name); + + let intComp = ModuleUtils.findInternal(group, cl, rating, group ? null : name); + + if (!intComp) { throw 'Unknown component: "' + line + '"'; } + + ship.use(slot, intComp.id, intComp); + } + } + + let builds = {}; + builds[shipId] = {}; + builds[shipId]['Imported ' + buildName] = Serializer.fromShip(ship); + this.setState({ builds }); + } + + _validateImport() { + let importData = null; + let importString = $scope.importString.trim(); + this.setState({ + builds: null, + comparisons: null, + discounts: null, + errorMsg: null, + importValid: false, + insurance: null + }); + + if (!importString) { + return; + } + + try { + if (textBuildRegex.test(importString)) { // E:D Shipyard build text + importTextBuild(importString); + } else { // JSON Build data + importData = angular.fromJson($scope.importString); + + if (!importData || typeof importData != 'object') { + throw 'Must be an object or array!'; + } + + if (importData instanceof Array) { // Must be detailed export json + this._importDetailedArray(importData); + } else if (importData.ship && typeof importData.name !== undefined) { // Using JSON from a single ship build export + this._importDetailedArray([importData]); // Convert to array with singleobject + } else { // Using Backup JSON + this._importBackup(importData); + } + } + } catch (e) { + this.setState({ errorMsg: (typeof e == 'string') ? e : 'Cannot Parse the data!' }); + return; + } + + this.setState({ importValid: true }); + }; + + _process() { + let builds = null, comparisons = null; + + if (this.state.builds) { + builds = $scope.builds; + for (let shipId in builds) { + for (let buildName in builds[shipId]) { + let code = builds[shipId][buildName]; + // Update builds object such that orginal name retained, but can be renamed + builds[shipId][buildName] = { + code: code, + useName: buildName + }; + } + } + } + + if (this.state.comparisons) { + let comparisons = $scope.comparisons; + for (let name in comparisons) { + comparisons[name].useName = name; + } + } + + this.setState({ processed: true, builds, comparisons }); + }; + + _import() { + + if (this.state.builds) { + let builds = this.state.builds; + for (let shipId in builds) { + for (let buildName in builds[shipId]) { + let build = builds[shipId][buildName]; + let name = build.useName.trim(); + if (name) { + Persist.saveBuild(shipId, name, build.code); + } + } + } + } + + if (this.state.comparisons) { + let comparisons = this.state.comparisons; + for (let comp in comparisons) { + let comparison = comparisons[comp]; + let useName = comparison.useName.trim(); + if (useName) { + Persist.saveComparison(useName, comparison.builds, comparison.facets); + } + } + } + + if (this.state.discounts) { + Persist.setDiscount((this.state.discounts); + } + + if (this.state.insurance) { + Persist.setInsurance(this.state.insurance); + } + + InterfaceEvents.hideModal(); + }; + + componentWillMount() { + if (this.props.importingBuilds) { + this.setState({ builds: this.props.importingBuilds, canEdit : false}); + this._process(); + } + } + + render() { + let translate = this.context.language.translate; + let importStage; + + if (this.state.processed) { + importStage = ( +
    +