mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-08 22:33:24 +00:00
Continued porting to react
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
"ClassDeclaration": true
|
||||
}
|
||||
}],
|
||||
"no-console": 2,
|
||||
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
|
||||
"comma-style": [2, "last"],
|
||||
"indent": [2, 2, { "SwitchCase": 1, "VariableDeclarator": 2 }],
|
||||
|
||||
@@ -6,10 +6,9 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import TU from 'react-testutils-additions';
|
||||
import Utils from './testUtils';
|
||||
import Persist from '../src/app/stores/Persist';
|
||||
import { getLanguage } from '../src/app/i18n/Language';
|
||||
|
||||
describe('Import Controller', function() {
|
||||
describe('Import Modal', function() {
|
||||
|
||||
const Persist = require('../src/app/stores/Persist').default;
|
||||
const ModalImport = require('../src/app/components/ModalImport').default;
|
||||
@@ -90,8 +89,8 @@ describe('Import Controller', function() {
|
||||
});
|
||||
|
||||
it('imports an old valid backup', function() {
|
||||
let importData = require('./fixtures/old-valid-export');
|
||||
let importStr = JSON.stringify(importData);
|
||||
const importData = require('./fixtures/old-valid-export');
|
||||
const importStr = JSON.stringify(importData);
|
||||
|
||||
pasteText(importStr);
|
||||
expect(modal.state.builds).toEqual(importData.builds);
|
||||
@@ -104,7 +103,7 @@ describe('Import Controller', function() {
|
||||
});
|
||||
|
||||
it('catches an invalid backup', function() {
|
||||
let importData = require('./fixtures/valid-backup');
|
||||
const importData = require('./fixtures/valid-backup');
|
||||
let invalidImportData = Object.assign({}, importData);
|
||||
invalidImportData.builds.asp = null; // Remove Asp Miner build used in comparison
|
||||
|
||||
@@ -131,7 +130,7 @@ describe('Import Controller', function() {
|
||||
beforeEach(reset);
|
||||
|
||||
it('imports a valid v3 build', function() {
|
||||
let importData = require('./fixtures/anaconda-test-detailed-export-v3');
|
||||
const importData = require('./fixtures/anaconda-test-detailed-export-v3');
|
||||
pasteText(JSON.stringify(importData));
|
||||
|
||||
expect(modal.state.importValid).toBeTruthy();
|
||||
@@ -149,7 +148,7 @@ describe('Import Controller', function() {
|
||||
});
|
||||
|
||||
it('catches an invalid build', function() {
|
||||
let importData = require('./fixtures/anaconda-test-detailed-export-v3');
|
||||
const importData = require('./fixtures/anaconda-test-detailed-export-v3');
|
||||
pasteText(JSON.stringify(importData).replace('components', 'comps'));
|
||||
|
||||
expect(modal.state.importValid).toBeFalsy();
|
||||
@@ -162,8 +161,8 @@ describe('Import Controller', function() {
|
||||
beforeEach(reset);
|
||||
|
||||
it('imports all builds', function() {
|
||||
let importData = require('./fixtures/valid-detailed-export');
|
||||
let expectedBuilds = require('./fixtures/expected-builds');
|
||||
const importData = require('./fixtures/valid-detailed-export');
|
||||
const expectedBuilds = require('./fixtures/expected-builds');
|
||||
|
||||
pasteText(JSON.stringify(importData));
|
||||
expect(modal.state.importValid).toBeTruthy();
|
||||
@@ -185,7 +184,7 @@ describe('Import Controller', function() {
|
||||
describe('Import E:D Shipyard Builds', function() {
|
||||
|
||||
it('imports a valid builds', function() {
|
||||
let imports = require('./fixtures/ed-shipyard-import-valid');
|
||||
const imports = require('./fixtures/ed-shipyard-import-valid');
|
||||
|
||||
for (let i = 0; i < imports.length; i++ ) {
|
||||
reset();
|
||||
@@ -203,7 +202,7 @@ describe('Import Controller', function() {
|
||||
});
|
||||
|
||||
it('catches invalid builds', function() {
|
||||
let imports = require('./fixtures/ed-shipyard-import-invalid');
|
||||
const imports = require('./fixtures/ed-shipyard-import-invalid');
|
||||
|
||||
for (let i = 0; i < imports.length; i++ ) {
|
||||
reset();
|
||||
@@ -212,7 +211,21 @@ describe('Import Controller', function() {
|
||||
expect(modal.state.errorMsg).toEqual(imports[i].errorMsg);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Imports from a Comparison', function() {
|
||||
|
||||
it('imports a valid comparison', function() {
|
||||
const importBuilds = require('./fixtures/valid-backup').builds;
|
||||
Persist.deleteAll();
|
||||
render = TU.renderIntoDocument(<ContextProvider><ModalImport builds={importBuilds} /></ContextProvider>);
|
||||
modal = TU.findRenderedComponentWithType(render, ModalImport);
|
||||
|
||||
expect(modal.state.processed).toBe(true);
|
||||
expect(modal.state.errorMsg).toEqual(null);
|
||||
clickImport();
|
||||
expect(Persist.getBuilds()).toEqual(importBuilds);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
37
__tests__/test-persist.js
Normal file
37
__tests__/test-persist.js
Normal file
@@ -0,0 +1,37 @@
|
||||
jest.dontMock('../src/app/stores/Persist');
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import TU from 'react-testutils-additions';
|
||||
|
||||
xdescribe('Persist', function() {
|
||||
|
||||
const Persist = require('../src/app/stores/Persist').default;
|
||||
|
||||
describe('Builds', function() {
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('Comparisons', function() {
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('Settings', function() {
|
||||
|
||||
it("has defaults", function() {
|
||||
expect(false).toBeTruthy('Implement');
|
||||
});
|
||||
|
||||
it("loads from localStorage correctly", function() {
|
||||
expect(false).toBeTruthy('Implement');
|
||||
});
|
||||
|
||||
it("generates the backup", function() {
|
||||
expect(false).toBeTruthy('Implement');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,27 +1,20 @@
|
||||
import Ship from '../src/app/shipyard/Ship';
|
||||
import { Ships } from 'coriolis-data';
|
||||
import * as Serializer from '../src/app/shipyard/Serializer';
|
||||
import jsen from 'jsen';
|
||||
|
||||
describe("Serializer Service", function() {
|
||||
|
||||
describe("Serializer", function() {
|
||||
const anacondaTestExport = require.requireActual('./fixtures/anaconda-test-detailed-export-v3');
|
||||
const code = anacondaTestExport.references[0].code;
|
||||
const anaconda = Ships.anaconda;
|
||||
const validate = jsen(require('../src/schemas/ship-loadout/3'));
|
||||
|
||||
describe("To Detailed Build", function() {
|
||||
let testBuild = new Ship('anaconda', anaconda.properties, anaconda.slots).buildFrom(code);
|
||||
let exportData = Serializer.toDetailedBuild('Test', testBuild);
|
||||
|
||||
let testBuild, exportData;
|
||||
|
||||
beforeEach(function() {
|
||||
testBuild = new Ship('anaconda', anaconda.properties, anaconda.slots);
|
||||
testBuild.buildFrom(code);
|
||||
exportData = Serializer.toDetailedBuild('Test', testBuild);
|
||||
});
|
||||
|
||||
xit("conforms to the v2 ship-loadout schema", function() {
|
||||
// var validate = jsen(require('../schemas/ship-loadout/3'));
|
||||
// var valid = validate(exportData);
|
||||
expect(valid).toBeTruthy();
|
||||
it("conforms to the v3 ship-loadout schema", function() {
|
||||
expect(validate(exportData)).toBe(true);
|
||||
});
|
||||
|
||||
it("contains the correct components and stats", function() {
|
||||
@@ -33,6 +26,21 @@ describe("Serializer Service", function() {
|
||||
|
||||
});
|
||||
|
||||
describe("Export Detailed Builds", function() {
|
||||
const expectedExport = require('./fixtures/valid-detailed-export');
|
||||
const builds = require('./fixtures/expected-builds');
|
||||
const exportData = Serializer.toDetailedExport(builds);
|
||||
|
||||
it("conforms to the v3 ship-loadout schema", function() {
|
||||
expect(exportData instanceof Array).toBe(true);
|
||||
|
||||
for (let detailedBuild of exportData) {
|
||||
expect(validate(detailedBuild)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("From Detailed Build", function() {
|
||||
|
||||
it("builds the ship correctly", function() {
|
||||
@@ -51,4 +59,5 @@ describe("Serializer Service", function() {
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -42,10 +42,12 @@
|
||||
"<rootDir>/node_modules/classnames",
|
||||
"<rootDir>/node_modules/d3",
|
||||
"<rootDir>/node_modules/lz-string",
|
||||
"<rootDir>/node_modules/jsen",
|
||||
"<rootDir>/node_modules/coriolis-data",
|
||||
"<rootDir>/src/app/shipyard",
|
||||
"<rootDir>/src/app/i18n",
|
||||
"<rootDir>/src/app/utils",
|
||||
"<rootDir>/src/schemas",
|
||||
"<rootDir>/__tests__"
|
||||
]
|
||||
},
|
||||
@@ -67,6 +69,7 @@
|
||||
"file-loader": "^0.8.4",
|
||||
"html-webpack-plugin": "^1.7.0",
|
||||
"jest-cli": "*",
|
||||
"jsen": "^0.6.0",
|
||||
"json-loader": "^0.5.3",
|
||||
"less": "^2.5.3",
|
||||
"less-loader": "^2.2.1",
|
||||
@@ -79,6 +82,7 @@
|
||||
"webpack-dev-server": "^1.14.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-polyfill": "^6.3.14",
|
||||
"classnames": "^2.2.0",
|
||||
"d3": "^3.5.9",
|
||||
"fbemitter": "^2.0.0",
|
||||
|
||||
@@ -121,7 +121,7 @@ export default class Coriolis extends React.Component {
|
||||
* @param {React.Component} content Modal Content
|
||||
*/
|
||||
_showModal(content) {
|
||||
let modal = <div className='modal-bg' onClick={(e) => this._hideModal() }>{content}</div>;
|
||||
let modal = <div className='modal-bg' onTouchTap={(e) => this._hideModal() }>{content}</div>;
|
||||
this.setState({ modal });
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ export default class Coriolis extends React.Component {
|
||||
* @return {React.Component} The main app
|
||||
*/
|
||||
render() {
|
||||
return <div onClick={this._closeMenu}>
|
||||
return <div onTouchTap={this._closeMenu}>
|
||||
<Header appCacheUpdate={this.state.appCacheUpdate} currentMenu={this.state.currentMenu} />
|
||||
{ this.state.page ? <this.state.page currentMenu={this.state.currentMenu} /> : <NotFoundPage/> }
|
||||
{ this.state.modal }
|
||||
|
||||
@@ -22,12 +22,13 @@ export default class ActiveLink extends Link {
|
||||
* @return {React.Component} The active link
|
||||
*/
|
||||
render() {
|
||||
let action = this.handler.bind(this);
|
||||
let className = this.props.className;
|
||||
if (isActive(this.props.href)) {
|
||||
className = cn(className, 'active');
|
||||
}
|
||||
|
||||
return <a {...this.props} className={className} onClick={this.handler.bind(this)}>{this.props.children}</a>;
|
||||
return <a {...this.props} className={className} onTouchTap={action}>{this.props.children}</a>;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import TranslatedComponent from './TranslatedComponent';
|
||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||
import cn from 'classnames';
|
||||
import { MountFixed, MountGimballed, MountTurret } from './SvgIcons';
|
||||
|
||||
@@ -30,6 +31,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
constructor(props, context) {
|
||||
super(props);
|
||||
this._hideDiff = this._hideDiff.bind(this);
|
||||
this._diffMove = this._diffMove.bind(this);
|
||||
this.state = { list: this._initList(props, context) };
|
||||
}
|
||||
|
||||
@@ -49,8 +51,8 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
m,
|
||||
warning,
|
||||
shipMass - (m && m.mass ? m.mass : 0),
|
||||
(m) => {
|
||||
this._hideDiff();
|
||||
(m, event) => {
|
||||
this._hideDiff(event);
|
||||
onSelect(m);
|
||||
}
|
||||
);
|
||||
@@ -89,9 +91,10 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
let m = modules[i];
|
||||
let mount = null;
|
||||
let disabled = m.maxmass && (mass + (m.mass ? m.mass : 0)) > m.maxmass;
|
||||
let active = mountedModule && mountedModule === m;
|
||||
let classes = cn(m.name ? 'lc' : 'c', {
|
||||
active: mountedModule && mountedModule.id === m.id,
|
||||
warning: !disabled && warningFunc && warningFunc(m),
|
||||
active,
|
||||
disabled
|
||||
});
|
||||
|
||||
@@ -105,11 +108,14 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
elems.push(<br key={m.grp + i} />);
|
||||
}
|
||||
|
||||
let showDiff = disabled || active ? null : this._showDiff.bind(this, mountedModule, m);
|
||||
|
||||
elems.push(
|
||||
<li
|
||||
key={m.id}
|
||||
className={classes}
|
||||
onMouseOver={disabled ? null : this._showDiff.bind(this, mountedModule, m)}
|
||||
onMouseEnter={showDiff}
|
||||
onTouchStart={showDiff}
|
||||
onMouseLeave={this._hideDiff}
|
||||
onClick={disabled ? null : onSelect.bind(null, m)}
|
||||
>
|
||||
@@ -132,15 +138,27 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_showDiff(mm, m, event) {
|
||||
event.preventDefault();
|
||||
if (this.props.diffDetails) {
|
||||
this.context.tooltip(this.props.diffDetails(m, mm), event.currentTarget.getBoundingClientRect());
|
||||
}
|
||||
}
|
||||
|
||||
_touchStart(event) {
|
||||
event.preventDefault();
|
||||
console.log(Object.assign({}, event));
|
||||
}
|
||||
|
||||
_diffMove(event) {
|
||||
console.log(Object.assign({}, event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide diff tooltip
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_hideDiff() {
|
||||
_hideDiff(event) {
|
||||
event.preventDefault();
|
||||
this.context.tooltip();
|
||||
}
|
||||
|
||||
@@ -170,7 +188,15 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<div className={cn('select', this.props.className)} onScroll={this._hideDiff} onClick={(e) => e.stopPropagation() }>
|
||||
<div
|
||||
className={cn('select', this.props.className)}
|
||||
onScroll={this._hideDiff}
|
||||
onClick={(e) => e.stopPropagation() }
|
||||
onTouchStart={this._touchStart}
|
||||
onTouchEnd={this._hideDiff}
|
||||
onTouchCancel={this._hideDiff}
|
||||
onContextMenu={stopCtxPropagation}
|
||||
>
|
||||
{this.state.list}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import d3 from 'd3';
|
||||
import TranslatedComponent from './TranslatedComponent';
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ export default class ComparisonTable extends TranslatedComponent {
|
||||
*/
|
||||
_buildHeaders(facets, onSort, translate) {
|
||||
let header = [
|
||||
<th key='ship' rowSpan='2' className='sortable' onClick={onSort.bind(null, 'name')}>{translate('ship')}</th>,
|
||||
<th key='build' rowSpan='2' className='sortable' onClick={onSort.bind(null, 'buildName')}>{translate('build')}</th>
|
||||
<th key='ship' rowSpan='2' className='sortable' onTouchTap={onSort.bind(null, 'name')}>{translate('ship')}</th>,
|
||||
<th key='build' rowSpan='2' className='sortable' onTouchTap={onSort.bind(null, 'buildName')}>{translate('build')}</th>
|
||||
];
|
||||
let subHeader = [];
|
||||
|
||||
@@ -47,13 +47,13 @@ export default class ComparisonTable extends TranslatedComponent {
|
||||
if (f.active) {
|
||||
let p = f.props;
|
||||
let pl = p.length;
|
||||
header.push(<th key={f.title} rowSpan={pl === 1 ? 2 : 1} colSpan={pl} className={cn({ sortable: pl === 1 })} onClick={pl === 1 ? onSort.bind(null, p[0]) : null }>
|
||||
header.push(<th key={f.title} rowSpan={pl === 1 ? 2 : 1} colSpan={pl} className={cn({ sortable: pl === 1 })} onTouchTap={pl === 1 ? onSort.bind(null, p[0]) : null }>
|
||||
{translate(f.title)}
|
||||
</th>);
|
||||
|
||||
if (pl > 1) {
|
||||
for (let i = 0; i < pl; i++) {
|
||||
subHeader.push(<th key={p[i]} className={cn('sortable', { lft: i === 0 })} onClick={onSort.bind(null, p[i])} >{translate(f.lbls[i])}</th>);
|
||||
subHeader.push(<th key={p[i]} className={cn('sortable', { lft: i === 0 })} onTouchTap={onSort.bind(null, p[i])} >{translate(f.lbls[i])}</th>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,9 +295,9 @@ export default class CostSection extends TranslatedComponent {
|
||||
if (item.m && item.m.cost) {
|
||||
let toggle = this._toggleCost.bind(this, item);
|
||||
rows.push(<tr key={i} className={cn('highlight', { disabled: !item.incCost })}>
|
||||
<td className='ptr' style={{ width: '1em' }} onClick={toggle}>{item.m.class + item.m.rating}</td>
|
||||
<td className='le ptr shorten cap' onClick={toggle}>{slotName(translate, item)}</td>
|
||||
<td className='ri ptr' onClick={toggle}>{formats.int(item.discountedCost)}{units.CR}</td>
|
||||
<td className='ptr' style={{ width: '1em' }} onTouchTap={toggle}>{item.m.class + item.m.rating}</td>
|
||||
<td className='le ptr shorten cap' onTouchTap={toggle}>{slotName(translate, item)}</td>
|
||||
<td className='ri ptr' onTouchTap={toggle}>{formats.int(item.discountedCost)}{units.CR}</td>
|
||||
</tr>);
|
||||
}
|
||||
}
|
||||
@@ -306,12 +306,12 @@ export default class CostSection extends TranslatedComponent {
|
||||
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
||||
<thead>
|
||||
<tr className='main'>
|
||||
<th colSpan='2' className='sortable le' onClick={this._sortCostBy.bind(this,'m')}>
|
||||
<th colSpan='2' className='sortable le' onTouchTap={this._sortCostBy.bind(this,'m')}>
|
||||
{translate('component')}
|
||||
{shipDiscount < 1 && <u className='cap optional-hide' style={{ marginLeft: '0.5em' }}>{`[${translate('ship')} -${formats.pct1(1 - shipDiscount)}]`}</u>}
|
||||
{moduleDiscount < 1 && <u className='cap optional-hide' style={{ marginLeft: '0.5em' }}>{`[${translate('modules')} -${formats.pct1(1 - moduleDiscount)}]`}</u>}
|
||||
</th>
|
||||
<th className='sortable le' onClick={this._sortCostBy.bind(this, 'cr')} >{translate('credits')}</th>
|
||||
<th className='sortable le' onTouchTap={this._sortCostBy.bind(this, 'cr')} >{translate('credits')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -346,7 +346,7 @@ export default class CostSection extends TranslatedComponent {
|
||||
if (retrofitCosts.length) {
|
||||
for (let i = 0, l = retrofitCosts.length; i < l; i++) {
|
||||
let item = retrofitCosts[i];
|
||||
rows.push(<tr key={i} className={cn('highlight', { disabled: !item.retroItem.incCost })} onClick={this._toggleRetrofitCost.bind(this, item)}>
|
||||
rows.push(<tr key={i} className={cn('highlight', { disabled: !item.retroItem.incCost })} onTouchTap={this._toggleRetrofitCost.bind(this, item)}>
|
||||
<td style={{ width: '1em' }}>{item.sellClassRating}</td>
|
||||
<td className='le shorten cap'>{translate(item.sellName)}</td>
|
||||
<td style={{ width: '1em' }}>{item.buyClassRating}</td>
|
||||
@@ -363,9 +363,9 @@ export default class CostSection extends TranslatedComponent {
|
||||
<table style={{ width: '100%' }}>
|
||||
<thead>
|
||||
<tr className='main'>
|
||||
<th colSpan='2' className='sortable le' onClick={this._sortRetrofitBy.bind(this, 'sellName')}>{translate('sell')}</th>
|
||||
<th colSpan='2' className='sortable le' onClick={this._sortRetrofitBy.bind(this, 'buyName')}>{translate('buy')}</th>
|
||||
<th colSpan='2' className='sortable le' onClick={this._sortRetrofitBy.bind(this, 'cr')}>
|
||||
<th colSpan='2' className='sortable le' onTouchTap={this._sortRetrofitBy.bind(this, 'sellName')}>{translate('sell')}</th>
|
||||
<th colSpan='2' className='sortable le' onTouchTap={this._sortRetrofitBy.bind(this, 'buyName')}>{translate('buy')}</th>
|
||||
<th colSpan='2' className='sortable le' onTouchTap={this._sortRetrofitBy.bind(this, 'cr')}>
|
||||
{translate('net cost')}
|
||||
{moduleDiscount < 1 && <u className='cap optional-hide' style={{ marginLeft: '0.5em' }}>{`[${translate('modules')} -${formats.rPct(1 - moduleDiscount)}]`}</u>}
|
||||
</th>
|
||||
@@ -473,10 +473,10 @@ export default class CostSection extends TranslatedComponent {
|
||||
<table style={{ width: '100%' }}>
|
||||
<thead>
|
||||
<tr className='main'>
|
||||
<th colSpan='2' className='sortable le' onClick={this._sortAmmoBy.bind(this, 'm')} >{translate('module')}</th>
|
||||
<th colSpan='1' className='sortable le' onClick={this._sortAmmoBy.bind(this, 'max')} >{translate('qty')}</th>
|
||||
<th colSpan='1' className='sortable le' onClick={this._sortAmmoBy.bind(this, 'cost')} >{translate('unit cost')}</th>
|
||||
<th className='sortable le' onClick={this._sortAmmoBy.bind(this, 'total')}>{translate('total cost')}</th>
|
||||
<th colSpan='2' className='sortable le' onTouchTap={this._sortAmmoBy.bind(this, 'm')} >{translate('module')}</th>
|
||||
<th colSpan='1' className='sortable le' onTouchTap={this._sortAmmoBy.bind(this, 'max')} >{translate('qty')}</th>
|
||||
<th colSpan='1' className='sortable le' onTouchTap={this._sortAmmoBy.bind(this, 'cost')} >{translate('unit cost')}</th>
|
||||
<th className='sortable le' onTouchTap={this._sortAmmoBy.bind(this, 'total')}>{translate('total cost')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -673,9 +673,9 @@ export default class CostSection extends TranslatedComponent {
|
||||
<table className='tabs'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{ width:'33%' }} className={cn({ active: tab == 'costs' })} onClick={this._showTab.bind(this, 'costs')} >{translate('costs')}</th>
|
||||
<th style={{ width:'33%' }} className={cn({ active: tab == 'retrofit' })} onClick={this._showTab.bind(this, 'retrofit')} >{translate('retrofit costs')}</th>
|
||||
<th style={{ width:'34%' }} className={cn({ active: tab == 'ammo' })} onClick={this._showTab.bind(this, 'ammo')} >{translate('reload costs')}</th>
|
||||
<th style={{ width:'33%' }} className={cn({ active: tab == 'costs' })} onTouchTap={this._showTab.bind(this, 'costs')} >{translate('costs')}</th>
|
||||
<th style={{ width:'33%' }} className={cn({ active: tab == 'retrofit' })} onTouchTap={this._showTab.bind(this, 'retrofit')} >{translate('retrofit costs')}</th>
|
||||
<th style={{ width:'34%' }} className={cn({ active: tab == 'ammo' })} onTouchTap={this._showTab.bind(this, 'ammo')} >{translate('reload costs')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
@@ -3,6 +3,7 @@ import SlotSection from './SlotSection';
|
||||
import HardpointSlot from './HardpointSlot';
|
||||
import cn from 'classnames';
|
||||
import { MountFixed, MountGimballed, MountTurret } from '../components/SvgIcons';
|
||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||
|
||||
/**
|
||||
* Hardpoint slot section
|
||||
@@ -90,39 +91,39 @@ export default class HardpointsSlotSection extends SlotSection {
|
||||
_getSectionMenu(translate) {
|
||||
let _fill = this._fill;
|
||||
|
||||
return <div className='select hardpoint' onClick={(e) => e.stopPropagation()}>
|
||||
return <div className='select hardpoint' onTouchTap={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||
<ul>
|
||||
<li className='lc' onClick={this._empty}>{translate('empty all')}</li>
|
||||
<li className='lc' onTouchTap={this._empty}>{translate('empty all')}</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('pl')}</div>
|
||||
<ul>
|
||||
<li className='c' onClick={_fill.bind(this, 'pl', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className='c' onClick={_fill.bind(this, 'pl', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className='c' onClick={_fill.bind(this, 'pl', 'T')}><MountTurret className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'pl', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'pl', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'pl', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('ul')}</div>
|
||||
<ul>
|
||||
<li className='c' onClick={_fill.bind(this, 'ul', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className='c' onClick={_fill.bind(this, 'ul', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className='c' onClick={_fill.bind(this, 'ul', 'T')}><MountTurret className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'ul', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'ul', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'ul', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('bl')}</div>
|
||||
<ul>
|
||||
<li className='c' onClick={_fill.bind(this, 'bl', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className='c' onClick={_fill.bind(this, 'bl', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className='c' onClick={_fill.bind(this, 'bl', 'T')}><MountTurret className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'bl', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'bl', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'bl', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('mc')}</div>
|
||||
<ul>
|
||||
<li className='c' onClick={_fill.bind(this, 'mc', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className='c' onClick={_fill.bind(this, 'mc', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className='c' onClick={_fill.bind(this, 'mc', 'T')}><MountTurret className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'mc', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'mc', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'mc', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('c')}</div>
|
||||
<ul>
|
||||
<li className='c' onClick={_fill.bind(this, 'c', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className='c' onClick={_fill.bind(this, 'c', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className='c' onClick={_fill.bind(this, 'c', 'T')}><MountTurret className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'c', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'c', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'c', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,11 @@ export default class Header extends TranslatedComponent {
|
||||
this._setLanguage = this._setLanguage.bind(this);
|
||||
this._setInsurance = this._setInsurance.bind(this);
|
||||
|
||||
this._openShips = this._openMenu.bind(this, 's');
|
||||
this._openBuilds = this._openMenu.bind(this, 'b');
|
||||
this._openComp = this._openMenu.bind(this, 'comp');
|
||||
this._openSettings = this._openMenu.bind(this, 'settings');
|
||||
|
||||
this.languageOptions = [];
|
||||
this.insuranceOptions = [];
|
||||
this.discountOptions = [];
|
||||
@@ -156,12 +161,11 @@ export default class Header extends TranslatedComponent {
|
||||
|
||||
/**
|
||||
* Open a menu
|
||||
* @param {SyntheticEvent} event Event
|
||||
* @param {string} menu Menu name
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_openMenu(event, menu) {
|
||||
_openMenu(menu, event) {
|
||||
event.stopPropagation();
|
||||
|
||||
if (this.props.currentMenu == menu) {
|
||||
menu = null;
|
||||
}
|
||||
@@ -181,7 +185,7 @@ export default class Header extends TranslatedComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='menu-list dbl no-wrap' onClick={ (e) => e.stopPropagation() }>
|
||||
<div className='menu-list dbl no-wrap' onTouchTap={ (e) => e.stopPropagation() }>
|
||||
{shipList}
|
||||
</div>
|
||||
);
|
||||
@@ -207,7 +211,7 @@ export default class Header extends TranslatedComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='menu-list' onClick={ (e) => e.stopPropagation() }>
|
||||
<div className='menu-list' onTouchTap={ (e) => e.stopPropagation() }>
|
||||
<div className='dbl'>{buildList}</div>
|
||||
</div>
|
||||
);
|
||||
@@ -233,7 +237,7 @@ export default class Header extends TranslatedComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='menu-list' onClick={ (e) => e.stopPropagation() } style={{ whiteSpace: 'nowrap' }}>
|
||||
<div className='menu-list' onTouchTap={ (e) => e.stopPropagation() } style={{ whiteSpace: 'nowrap' }}>
|
||||
{comparisons}
|
||||
<hr />
|
||||
<Link href='/compare/all' ui-sref="compare({name: 'all'})" className='block cap'>{translate('compare all')}</Link>
|
||||
@@ -251,14 +255,14 @@ export default class Header extends TranslatedComponent {
|
||||
let tips = Persist.showTooltips();
|
||||
|
||||
return (
|
||||
<div className='menu-list no-wrap cap' onClick={ (e) => e.stopPropagation() }>
|
||||
<div className='menu-list no-wrap cap' onTouchTap={ (e) => e.stopPropagation() }>
|
||||
<div style={{ lineHeight: '2em' }}>
|
||||
{translate('language')}
|
||||
<select className='cap' value={Persist.getLangCode()} onChange={this._setLanguage}>
|
||||
{this.languageOptions}
|
||||
</select>
|
||||
<br/>
|
||||
<span className='cap ptr' onClick={this._toggleTooltips} >
|
||||
<span className='cap ptr' onTouchTap={this._toggleTooltips} >
|
||||
{translate('tooltips')}
|
||||
<div className={cn({ disabled: !tips, 'primary-disabled': tips })} style={{ marginLeft: '0.5em', display: 'inline-block' }}>{(tips ? '✓' : '✗')}</div>
|
||||
</span>
|
||||
@@ -281,10 +285,10 @@ export default class Header extends TranslatedComponent {
|
||||
<hr />
|
||||
<ul>
|
||||
{translate('builds')} & {translate('comparisons')}
|
||||
<li><a href="#" className='block' onClick={this._showBackup.bind(this)}>{translate('backup')}</a></li>
|
||||
<li><a href="#" className='block' onClick={this._showDetailedExport.bind(this)}>{translate('detailed export')}</a></li>
|
||||
<li><a href="#" className='block' onClick={this._showImport.bind(this)}>{translate('import')}</a></li>
|
||||
<li><a href="#" onClick={this._showDeleteAll.bind(this)}>{translate('delete all')}</a></li>
|
||||
<li><a href="#" className='block' onTouchTap={this._showBackup.bind(this)}>{translate('backup')}</a></li>
|
||||
<li><a href="#" className='block' onTouchTap={this._showDetailedExport.bind(this)}>{translate('detailed export')}</a></li>
|
||||
<li><a href="#" className='block' onTouchTap={this._showImport.bind(this)}>{translate('import')}</a></li>
|
||||
<li><a href="#" onTouchTap={this._showDeleteAll.bind(this)}>{translate('delete all')}</a></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<table style={{ width: 300, backgroundColor: 'transparent' }}>
|
||||
@@ -295,7 +299,7 @@ export default class Header extends TranslatedComponent {
|
||||
<td style={{ width: 20 }}><span style={{ fontSize: 30 }}>A</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colSpan='3' style={{ textAlign: 'center', cursor: 'pointer' }} className='primary-disabled cap' onClick={this._resetTextSize.bind(this)}>{translate('reset')}</td>
|
||||
<td colSpan='3' style={{ textAlign: 'center', cursor: 'pointer' }} className='primary-disabled cap' onTouchTap={this._resetTextSize.bind(this)}>{translate('reset')}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -343,7 +347,7 @@ export default class Header extends TranslatedComponent {
|
||||
let hasBuilds = Persist.hasBuilds();
|
||||
|
||||
if (this.props.appCacheUpdate) {
|
||||
return <div id="app-update" onClick={() => window.location.reload() }>{translate('PHRASE_UPDATE_RDY')}</div>;
|
||||
return <div id="app-update" onTouchTap={() => window.location.reload() }>{translate('PHRASE_UPDATE_RDY')}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -351,28 +355,28 @@ export default class Header extends TranslatedComponent {
|
||||
<Link className='l' href="/" style={{ marginRight: '1em' }} title="Home"><CoriolisLogo className='icon xl' /></Link>
|
||||
|
||||
<div className='l menu'>
|
||||
<div className={cn('menu-header', { selected: openedMenu == 's' })} onClick={ (e) => this._openMenu(e,'s') } >
|
||||
<div className={cn('menu-header', { selected: openedMenu == 's' })} onTouchTap={this._openShips}>
|
||||
<Rocket className='warning' /><span className='menu-item-label'>{' ' + translate('ships')}</span>
|
||||
</div>
|
||||
{openedMenu == 's' ? this._getShipsMenu() : null}
|
||||
</div>
|
||||
|
||||
<div className='l menu'>
|
||||
<div className={cn('menu-header', { selected: openedMenu == 'b', disabled: !hasBuilds })} onClick={ hasBuilds ? (e) => this._openMenu(e,'b') : null }>
|
||||
<div className={cn('menu-header', { selected: openedMenu == 'b', disabled: !hasBuilds })} onTouchTap={hasBuilds && this._openBuilds}>
|
||||
<Hammer className={cn('warning', { 'warning-disabled': !hasBuilds })} /><span className='menu-item-label'>{' ' + translate('builds')}</span>
|
||||
</div>
|
||||
{openedMenu == 'b' ? this._getBuildsMenu() : null}
|
||||
</div>
|
||||
|
||||
<div className='l menu'>
|
||||
<div className={cn('menu-header', { selected: openedMenu == 'comp', disabled: !hasBuilds })} onClick={ hasBuilds ? (e) => this._openMenu(e,'comp') : null }>
|
||||
<div className={cn('menu-header', { selected: openedMenu == 'comp', disabled: !hasBuilds })} onTouchTap={hasBuilds && this._openComp}>
|
||||
<StatsBars className={cn('warning', { 'warning-disabled': !hasBuilds })} /><span className='menu-item-label'>{' ' + translate('compare')}</span>
|
||||
</div>
|
||||
{openedMenu == 'comp' ? this._getComparisonsMenu() : null}
|
||||
</div>
|
||||
|
||||
<div className='r menu'>
|
||||
<div className={cn('menu-header', { selected: openedMenu == 'settings' })}onClick={ (e) => this._openMenu(e,'settings') }>
|
||||
<div className={cn('menu-header', { selected: openedMenu == 'settings' })} onTouchTap={this._openSettings}>
|
||||
<Cogs className='xl warning'/><span className='menu-item-label'>{translate('settings')}</span>
|
||||
</div>
|
||||
{openedMenu == 'settings' ? this._getSettingsMenu() : null}
|
||||
|
||||
@@ -3,6 +3,7 @@ import cn from 'classnames';
|
||||
import SlotSection from './SlotSection';
|
||||
import InternalSlot from './InternalSlot';
|
||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||
|
||||
/**
|
||||
* Internal slot section
|
||||
@@ -131,12 +132,12 @@ export default class InternalSlotSection extends SlotSection {
|
||||
* @return {React.Component} Section menu
|
||||
*/
|
||||
_getSectionMenu(translate) {
|
||||
return <div className='select' onClick={e => e.stopPropagation()}>
|
||||
return <div className='select' onTouchTap={e => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||
<ul>
|
||||
<li className='lc' onClick={this._empty}>{translate('empty all')}</li>
|
||||
<li className='lc' onClick={this._fillWithCargo}>{translate('cargo')}</li>
|
||||
<li className='lc' onClick={this._fillWithCells}>{translate('scb')}</li>
|
||||
<li className='lc' onClick={this._fillWithArmor}>{translate('hr')}</li>
|
||||
<li className='lc' onTouchTap={this._empty}>{translate('empty all')}</li>
|
||||
<li className='lc' onTouchTap={this._fillWithCargo}>{translate('cargo')}</li>
|
||||
<li className='lc' onTouchTap={this._fillWithCells}>{translate('scb')}</li>
|
||||
<li className='lc' onTouchTap={this._fillWithArmor}>{translate('hr')}</li>
|
||||
</ul>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import d3 from 'd3';
|
||||
import TranslatedComponent from './TranslatedComponent';
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@ export default class Link extends React.Component {
|
||||
* @return {React.Component} A href element
|
||||
*/
|
||||
render() {
|
||||
return <a {...this.props} onClick={this.handler.bind(this)}>{this.props.children}</a>;
|
||||
let action = this.handler.bind(this);
|
||||
return <a {...this.props} onTouchTap={action}>{this.props.children}</a>;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -96,20 +96,20 @@ export default class ModalCompare extends TranslatedComponent {
|
||||
let translate = this.context.language.translate;
|
||||
|
||||
let availableBuilds = unusedBuilds.map((build, i) =>
|
||||
<tr key={i} onClick={this._addBuild.bind(this, i)}>
|
||||
<tr key={i} onTouchTap={this._addBuild.bind(this, i)}>
|
||||
<td className='tl'>{build.name}</td>
|
||||
<td className='tl'>{build.buildName}</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
let selectedBuilds = usedBuilds.map((build, i) =>
|
||||
<tr key={i} onClick={this._removeBuild.bind(this, i)}>
|
||||
<tr key={i} onTouchTap={this._removeBuild.bind(this, i)}>
|
||||
<td className='tl'>{build.name}</td><
|
||||
td className='tl'>{build.buildName}</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
||||
return <div className='modal' onTouchTap={ (e) => e.stopPropagation() }>
|
||||
<h3>{translate('PHRASE_SELECT_BUILDS')}</h3>
|
||||
<div id='build-select'>
|
||||
<table>
|
||||
@@ -127,8 +127,8 @@ export default class ModalCompare extends TranslatedComponent {
|
||||
</table>
|
||||
</div>
|
||||
<br/>
|
||||
<button className='cap' onClick={this._selectBuilds.bind(this)}>{translate('Ok')}</button>
|
||||
<button className='r cap' onClick={() => this.context.hideModal()}>{translate('Cancel')}</button>
|
||||
<button className='cap' onTouchTap={this._selectBuilds.bind(this)}>{translate('Ok')}</button>
|
||||
<button className='r cap' onTouchTap={() => this.context.hideModal()}>{translate('Cancel')}</button>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,11 @@ export default class ModalDeleteAll extends TranslatedComponent {
|
||||
render() {
|
||||
let translate = this.context.language.translate;
|
||||
|
||||
return <div className='modal' onClick={(e) => e.stopPropagation()}>
|
||||
return <div className='modal' onTouchTap={(e) => e.stopPropagation()}>
|
||||
<h2>{translate('delete all')}</h2>
|
||||
<p className='cen'>{translate('PHRASE_CONFIRMATION')}</p>
|
||||
<button className='l cap' onClick={this._deleteAll.bind(this)}>{translate('yes')}</button>
|
||||
<button className='r cap' onClick={this.context.hideModal}>{translate('no')}</button>
|
||||
<button className='l cap' onTouchTap={this._deleteAll.bind(this)}>{translate('yes')}</button>
|
||||
<button className='r cap' onTouchTap={this.context.hideModal}>{translate('no')}</button>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,13 +52,13 @@ export default class ModalExport extends TranslatedComponent {
|
||||
description = <div>{translate(this.props.description)}</div>;
|
||||
}
|
||||
|
||||
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
||||
return <div className='modal' onTouchTap={ (e) => e.stopPropagation() }>
|
||||
<h2>{translate(this.props.title || 'Export')}</h2>
|
||||
{description}
|
||||
<div>
|
||||
<textarea className='cb json' onFocus={ (e) => e.target.select() } readOnly value={this.state.exportJson} />
|
||||
</div>
|
||||
<button className='r dismiss cap' onClick={this.context.hideModal}>{translate('close')}</button>
|
||||
<button className='r dismiss cap' onTouchTap={this.context.hideModal}>{translate('close')}</button>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,11 @@ function detailedJsonToBuild(detailedBuild) {
|
||||
*/
|
||||
export default class ModalImport extends TranslatedComponent {
|
||||
|
||||
|
||||
static propTypes = {
|
||||
builds: React.PropTypes.object, // Optional: Import object
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param {Object} props React Component properties
|
||||
@@ -97,8 +102,8 @@ export default class ModalImport extends TranslatedComponent {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
builds: null,
|
||||
canEdit: true,
|
||||
builds: props.builds,
|
||||
canEdit: !props.builds,
|
||||
comparisons: null,
|
||||
discounts: null,
|
||||
errorMsg: null,
|
||||
@@ -326,13 +331,13 @@ export default class ModalImport extends TranslatedComponent {
|
||||
let builds = null, comparisons = null;
|
||||
|
||||
if (this.state.builds) {
|
||||
builds = this.state.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 = {}; // Create new builds object such that orginal name retained, but can be renamed
|
||||
for (let shipId in this.state.builds) {
|
||||
let shipbuilds = this.state.builds[shipId];
|
||||
builds[shipId] = {};
|
||||
for (let buildName in shipbuilds) {
|
||||
builds[shipId][buildName] = {
|
||||
code,
|
||||
code: shipbuilds[buildName],
|
||||
useName: buildName
|
||||
};
|
||||
}
|
||||
@@ -340,9 +345,9 @@ export default class ModalImport extends TranslatedComponent {
|
||||
}
|
||||
|
||||
if (this.state.comparisons) {
|
||||
comparisons = this.state.comparisons;
|
||||
for (let name in comparisons) {
|
||||
comparisons[name].useName = name;
|
||||
comparisons = {};
|
||||
for (let name in this.state.comparisons) {
|
||||
comparisons[name] = Object.assign({ useName: name }, this.state.comparisons[name]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,8 +408,7 @@ export default class ModalImport extends TranslatedComponent {
|
||||
* If imported data is already provided process immediately on mount
|
||||
*/
|
||||
componentWillMount() {
|
||||
if (this.props.importingBuilds) {
|
||||
this.setState({ builds: this.props.importingBuilds, canEdit : false });
|
||||
if (this.props.builds) {
|
||||
this._process();
|
||||
}
|
||||
}
|
||||
@@ -504,7 +508,7 @@ export default class ModalImport extends TranslatedComponent {
|
||||
);
|
||||
}
|
||||
|
||||
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
||||
return <div className='modal' onTouchTap={ (e) => e.stopPropagation() } onClick={ (e) => e.stopPropagation() }>
|
||||
<h2 >{translate('import')}</h2>
|
||||
{importStage}
|
||||
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
||||
|
||||
@@ -40,7 +40,7 @@ export default class ModalPermalink extends TranslatedComponent {
|
||||
render() {
|
||||
let translate = this.context.language.translate;
|
||||
|
||||
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
||||
return <div className='modal' onTouchTap={ (e) => e.stopPropagation() }>
|
||||
<h2>{translate('permalink')}</h2>
|
||||
<br/>
|
||||
<h3>{translate('URL')}</h3>
|
||||
@@ -49,7 +49,7 @@ export default class ModalPermalink extends TranslatedComponent {
|
||||
<h3 >{translate('shortened')}</h3>
|
||||
<input value={this.state.shortenedUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/>
|
||||
<br/><br/>
|
||||
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
||||
<button className={'r dismiss cap'} onTouchTap={this.context.hideModal}>{translate('close')}</button>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ export default class PowerBands extends TranslatedComponent {
|
||||
height={state.barHeight}
|
||||
x={Math.floor(Math.max(wattScale(b.retractedSum) - wattScale(b.retracted), 0))}
|
||||
y={1}
|
||||
onClick={this._selectRet.bind(this, i)}
|
||||
onTouchTap={this._selectRet.bind(this, i)}
|
||||
className={getClass(ret[i], b.retractedSum, available)}
|
||||
/>);
|
||||
|
||||
@@ -223,7 +223,7 @@ export default class PowerBands extends TranslatedComponent {
|
||||
height={state.barHeight}
|
||||
x={wattScale(b.retractedSum) - (wattScale(b.retracted) / 2)}
|
||||
y={state.retY}
|
||||
onClick={this._selectRet.bind(this, i)}
|
||||
onTouchTap={this._selectRet.bind(this, i)}
|
||||
className='primary-bg'>{retLbl}</text>
|
||||
);
|
||||
}
|
||||
@@ -238,7 +238,7 @@ export default class PowerBands extends TranslatedComponent {
|
||||
height={state.barHeight}
|
||||
x={Math.floor(Math.max(wattScale(b.deployedSum) - wattScale(b.retracted) - wattScale(b.deployed), 0))}
|
||||
y={state.barHeight + 1}
|
||||
onClick={this._selectDep.bind(this, i)}
|
||||
onTouchTap={this._selectDep.bind(this, i)}
|
||||
className={getClass(dep[i], b.deployedSum, available)}
|
||||
/>);
|
||||
|
||||
@@ -250,7 +250,7 @@ export default class PowerBands extends TranslatedComponent {
|
||||
height={state.barHeight}
|
||||
x={wattScale(b.deployedSum) - ((wattScale(b.retracted) + wattScale(b.deployed)) / 2)}
|
||||
y={state.depY}
|
||||
onClick={this._selectDep.bind(this, i)}
|
||||
onTouchTap={this._selectDep.bind(this, i)}
|
||||
className='primary-bg'>{depLbl}</text>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -119,23 +119,23 @@ export default class PowerManagement extends TranslatedComponent {
|
||||
let retractedElem = null, deployedElem = null;
|
||||
|
||||
if (slot.enabled) {
|
||||
retractedElem = <td className='ptr upp' onClick={toggleEnabled}>{POWER[ship.getSlotStatus(slot, false)]}</td>;
|
||||
deployedElem = <td className='ptr upp' onClick={toggleEnabled}>{POWER[ship.getSlotStatus(slot, true)]}</td>;
|
||||
retractedElem = <td className='ptr upp' onTouchTap={toggleEnabled}>{POWER[ship.getSlotStatus(slot, false)]}</td>;
|
||||
deployedElem = <td className='ptr upp' onTouchTap={toggleEnabled}>{POWER[ship.getSlotStatus(slot, true)]}</td>;
|
||||
} else {
|
||||
retractedElem = <td className='ptr disabled upp' colSpan='2' onClick={toggleEnabled}>{translate('disabled')}</td>;
|
||||
retractedElem = <td className='ptr disabled upp' colSpan='2' onTouchTap={toggleEnabled}>{translate('disabled')}</td>;
|
||||
}
|
||||
|
||||
powerRows.push(<tr key={i} className={cn('highlight', { disabled: !slot.enabled })}>
|
||||
<td className='ptr' style={{ width: '1em' }} onClick={toggleEnabled}>{m.class + m.rating}</td>
|
||||
<td className='ptr le shorten cap' onClick={toggleEnabled}>{slotName(translate, slot)}</td>
|
||||
<td className='ptr' onClick={toggleEnabled}><u>{translate(slot.type)}</u></td>
|
||||
<td className='ptr' style={{ width: '1em' }} onTouchTap={toggleEnabled}>{m.class + m.rating}</td>
|
||||
<td className='ptr le shorten cap' onTouchTap={toggleEnabled}>{slotName(translate, slot)}</td>
|
||||
<td className='ptr' onTouchTap={toggleEnabled}><u>{translate(slot.type)}</u></td>
|
||||
<td>
|
||||
<span className='flip ptr btn' onClick={this._priority.bind(this, slot, -1)}>►</span>
|
||||
<span className='flip ptr btn' onTouchTap={this._priority.bind(this, slot, -1)}>►</span>
|
||||
{' ' + (slot.priority + 1) + ' '}
|
||||
<span className='ptr btn' onClick={this._priority.bind(this, slot, 1)}>►</span>
|
||||
<span className='ptr btn' onTouchTap={this._priority.bind(this, slot, 1)}>►</span>
|
||||
</td>
|
||||
<td className='ri ptr' style={{ width: '3.25em' }} onClick={toggleEnabled}>{pwr(m.power)}</td>
|
||||
<td className='ri ptr' style={{ width: '3em' }} onClick={toggleEnabled}><u>{pct(m.power / ship.powerAvailable)}</u></td>
|
||||
<td className='ri ptr' style={{ width: '3.25em' }} onTouchTap={toggleEnabled}>{pwr(m.power)}</td>
|
||||
<td className='ri ptr' style={{ width: '3em' }} onTouchTap={toggleEnabled}><u>{pct(m.power / ship.powerAvailable)}</u></td>
|
||||
{retractedElem}
|
||||
{deployedElem}
|
||||
</tr>);
|
||||
@@ -200,12 +200,12 @@ export default class PowerManagement extends TranslatedComponent {
|
||||
<table style={{ width: '100%' }}>
|
||||
<thead>
|
||||
<tr className='main'>
|
||||
<th colSpan='2' className='sortable le' onClick={sortOrder.bind(this, 'n')} >{translate('module')}</th>
|
||||
<th style={{ width: '3em' }} className='sortable' onClick={sortOrder.bind(this, 't')} >{translate('type')}</th>
|
||||
<th style={{ width: '4em' }} className='sortable' onClick={sortOrder.bind(this, 'pri')} >{translate('pri')}</th>
|
||||
<th colSpan='2' className='sortable' onClick={sortOrder.bind(this, 'pwr')} >{translate('PWR')}</th>
|
||||
<th style={{ width: '3em' }} className='sortable' onClick={sortOrder.bind(this, 'r')} >{translate('ret')}</th>
|
||||
<th style={{ width: '3em' }} className='sortable' onClick={sortOrder.bind(this, 'd')} >{translate('dep')}</th>
|
||||
<th colSpan='2' className='sortable le' onTouchTap={sortOrder.bind(this, 'n')} >{translate('module')}</th>
|
||||
<th style={{ width: '3em' }} className='sortable' onTouchTap={sortOrder.bind(this, 't')} >{translate('type')}</th>
|
||||
<th style={{ width: '4em' }} className='sortable' onTouchTap={sortOrder.bind(this, 'pri')} >{translate('pri')}</th>
|
||||
<th colSpan='2' className='sortable' onTouchTap={sortOrder.bind(this, 'pwr')} >{translate('PWR')}</th>
|
||||
<th style={{ width: '3em' }} className='sortable' onTouchTap={sortOrder.bind(this, 'r')} >{translate('ret')}</th>
|
||||
<th style={{ width: '3em' }} className='sortable' onTouchTap={sortOrder.bind(this, 'd')} >{translate('dep')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import React from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
|
||||
const MARGIN_LR = 8; // Left/ Right margin
|
||||
|
||||
/**
|
||||
* Horizontal Slider
|
||||
@@ -8,7 +11,8 @@ export default class Slider extends React.Component {
|
||||
static defaultProps = {
|
||||
axis: false,
|
||||
min: 0,
|
||||
max: 1
|
||||
max: 1,
|
||||
scale: 1 // SVG render scale
|
||||
};
|
||||
|
||||
static PropTypes = {
|
||||
@@ -16,6 +20,7 @@ export default class Slider extends React.Component {
|
||||
axisUnit: React.PropTypes.string,
|
||||
min: React.PropTypes.number,
|
||||
max: React.PropTypes.number,
|
||||
scale: React.PropTypes.number,
|
||||
onChange: React.PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
@@ -25,52 +30,101 @@ export default class Slider extends React.Component {
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this._down = this._down.bind(this);
|
||||
this._move = this._move.bind(this);
|
||||
this._up = this._up.bind(this);
|
||||
this._updatePercent = this._updatePercent.bind(this);
|
||||
this._updateDimensions = this._updateDimensions.bind(this);
|
||||
|
||||
this.down = this.down.bind(this);
|
||||
this.up = this.up.bind(this);
|
||||
this.state = { width: 0 };
|
||||
}
|
||||
|
||||
/**
|
||||
* On Mouse down handler
|
||||
* On Mouse/Touch down handler
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
down(event) {
|
||||
if (this.move) {
|
||||
this.up(event);
|
||||
} else {
|
||||
let rect = event.currentTarget.getBoundingClientRect();
|
||||
this.move = this._updatePercent.bind(this, rect.left, rect.width);
|
||||
this.move(event);
|
||||
document.addEventListener('mousemove', this.move, true);
|
||||
document.addEventListener('mouseup', this.up, true);
|
||||
_down(event) {
|
||||
let rect = event.currentTarget.getBoundingClientRect();
|
||||
this.left = rect.left;
|
||||
this.width = rect.width;
|
||||
this._move(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the slider percentage on move
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_move(event) {
|
||||
if(this.width !== null && this.left != null) {
|
||||
let clientX = event.touches ? event.touches[0].clientX : event.clientX;
|
||||
event.preventDefault();
|
||||
this._updatePercent(clientX - this.left, this.width);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On Mouse up handler
|
||||
* On Mouse/Touch up handler
|
||||
* @param {Event} event DOM Event
|
||||
*/
|
||||
up(event) {
|
||||
document.removeEventListener('mousemove', this.move, true);
|
||||
document.removeEventListener('mouseup', this.up, true);
|
||||
this.move = null;
|
||||
_up(event) {
|
||||
event.preventDefault();
|
||||
this.left = null;
|
||||
this.width = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user is still dragging
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_enter(event) {
|
||||
if(event.buttons !== 1) {
|
||||
this.left = null;
|
||||
this.width = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the slider percentage
|
||||
* @param {number} left Slider left position
|
||||
* @param {number} pos Slider drag position
|
||||
* @param {number} width Slider width
|
||||
* @param {Event} event DOM Event
|
||||
*/
|
||||
_updatePercent(left, width, event) {
|
||||
this.props.onChange(Math.min(Math.max((event.clientX - left) / width, 0), 1));
|
||||
_updatePercent(pos, width) {
|
||||
this.props.onChange(Math.min(Math.max(pos / width, 0), 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update dimenions from rendered DOM
|
||||
*/
|
||||
_updateDimensions() {
|
||||
this.setState({
|
||||
outerWidth: findDOMNode(this).offsetWidth
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add listeners when about to mount
|
||||
*/
|
||||
componentWillMount() {
|
||||
if (this.props.onResize) {
|
||||
this.resizeListener = this.props.onResize(this._updateDimensions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger DOM updates on mount
|
||||
*/
|
||||
componentDidMount() {
|
||||
this._updateDimensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove listeners on unmount
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this.up();
|
||||
if (this.resizeListener) {
|
||||
this.resizeListener.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,24 +132,33 @@ export default class Slider extends React.Component {
|
||||
* @return {React.Component} The slider
|
||||
*/
|
||||
render() {
|
||||
let pctStr = (this.props.percent * 100) + '%';
|
||||
let { axis, axisUnit, min, max } = this.props;
|
||||
let axisGroup;
|
||||
let outerWidth = this.state.outerWidth;
|
||||
let { axis, axisUnit, min, max, scale } = this.props;
|
||||
|
||||
if (axis) {
|
||||
axisGroup = <g style={{ fontSize: '.7em' }}>
|
||||
<text className='primary-disabled' y='3em' x='0' style={{ textAnchor: 'middle' }}>{min + axisUnit}</text>
|
||||
<text className='primary-disabled' y='3em' x='50%' style={{ textAnchor: 'middle' }}>{(min + max / 2) + axisUnit}</text>
|
||||
<text className='primary-disabled' y='3em' x='99%' style={{ textAnchor: 'middle' }}>{max + axisUnit}</text>
|
||||
</g>;
|
||||
let style = {
|
||||
width: '100%',
|
||||
height: axis ? '2.5em' : '1.5em',
|
||||
boxSizing: 'border-box'
|
||||
};
|
||||
|
||||
if (!outerWidth) {
|
||||
return <svg style={style} />;
|
||||
}
|
||||
|
||||
return <svg style={{ width: '100%', height: axis ? '2.5em' : '1.5em', padding: '0 0.6em', cursor: 'col-resize', boxSizing: 'border-box' }}>
|
||||
<rect className='primary' style={{ opacity: 0.3 }} y='0.25em' rx='0.3em' ry='0.3em' width='100%' height='0.7em' />
|
||||
<rect className='primary-disabled'y='0.45em' rx='0.15em' ry='0.15em' width={pctStr} height='0.3em' />
|
||||
<circle className='primary' r='0.6em' cy='0.6em' cx={pctStr} />
|
||||
<rect width='100%' height='100%' fillOpacity='0' onMouseDown={this.down} onClick={this.click} />
|
||||
{axisGroup}
|
||||
let margin = MARGIN_LR * scale;
|
||||
let width = outerWidth - (margin * 2);
|
||||
let pctPos = width * this.props.percent;
|
||||
|
||||
return <svg onMouseUp={this._up} onMouseEnter={this._enter.bind(this)} onMouseMove={this._move} onTouchEnd={this._up} style={style}>
|
||||
<rect className='primary' style={{ opacity: 0.3 }} x={margin} y='0.25em' rx='0.3em' ry='0.3em' width={width} height='0.7em' />
|
||||
<rect className='primary-disabled' x={margin} y='0.45em' rx='0.15em' ry='0.15em' width={pctPos} height='0.3em' />
|
||||
<circle className='primary' r={margin} cy='0.6em' cx={pctPos + margin} />
|
||||
<rect x={margin} width={width} height='100%' fillOpacity='0' style={{ cursor: 'col-resize' }} onMouseDown={this._down} onTouchMove={this._move} onTouchStart={this._down} />
|
||||
{axis && <g style={{ fontSize: '.7em' }}>
|
||||
<text className='primary-disabled' y='3em' x={margin} style={{ textAnchor: 'middle' }}>{min + axisUnit}</text>
|
||||
<text className='primary-disabled' y='3em' x='50%' style={{ textAnchor: 'middle' }}>{(min + max / 2) + axisUnit}</text>
|
||||
<text className='primary-disabled' y='3em' x='100%' style={{ textAnchor: 'end' }}>{max + axisUnit}</text>
|
||||
</g>}
|
||||
</svg>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,8 +92,10 @@ export default class Slot extends TranslatedComponent {
|
||||
/>;
|
||||
}
|
||||
|
||||
// TODO: implement touch dragging
|
||||
|
||||
return (
|
||||
<div className={cn('slot', dropClass, { selected })} onClick={onOpen} onContextMenu={this._contextMenu} onDragOver={dragOver}>
|
||||
<div className={cn('slot', dropClass, { selected })} onTouchTap={onOpen} onContextMenu={this._contextMenu} onDragOver={dragOver}>
|
||||
<div className='details-container'>
|
||||
<div className='sz'>{this._getMaxClassLabel(translate)}</div>
|
||||
{slotDetails}
|
||||
|
||||
@@ -49,11 +49,11 @@ export default class SlotSection extends TranslatedComponent {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_openMenu(menu, event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (this.props.currentMenu === menu) {
|
||||
menu = null;
|
||||
}
|
||||
|
||||
this.context.openMenu(menu);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,6 @@ export default class SlotSection extends TranslatedComponent {
|
||||
e.stopPropagation();
|
||||
let os = this.state.originSlot;
|
||||
if (os) {
|
||||
console.log('has origin');
|
||||
e.dataTransfer.dropEffect = os != targetSlot && targetSlot.maxClass >= os.m.class ? 'copyMove' : 'none';
|
||||
this.setState({ targetSlot });
|
||||
} else {
|
||||
@@ -157,16 +156,6 @@ export default class SlotSection extends TranslatedComponent {
|
||||
return 'ineligible'; // Cannot be dropped / invalid drop slot
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle slot Active/Inactive
|
||||
* @param {Object} slot Slot
|
||||
*/
|
||||
_togglePwr(slot) {
|
||||
this.props.ship.setSlotEnabled(slot, !slot.enabled);
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close current menu
|
||||
*/
|
||||
@@ -188,7 +177,7 @@ export default class SlotSection extends TranslatedComponent {
|
||||
|
||||
return (
|
||||
<div id={this.sectionId} className={'group'} onDragLeave={this._dragOverNone}>
|
||||
<div className={cn('section-menu', { selected: sectionMenuOpened })} onClick={open} onContextMenu={ctx}>
|
||||
<div className={cn('section-menu', { selected: sectionMenuOpened })} onTouchTap={open} onContextMenu={ctx}>
|
||||
<h1>{translate(this.sectionName)} <Equalizer/></h1>
|
||||
{sectionMenuOpened ? this._getSectionMenu(translate) : null }
|
||||
</div>
|
||||
|
||||
@@ -43,7 +43,7 @@ export default class StandardSlot extends TranslatedComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn('slot', { selected: this.props.selected })} onClick={this.props.onOpen}>
|
||||
<div className={cn('slot', { selected: this.props.selected })} onTouchTap={this.props.onOpen}>
|
||||
<div className={cn('details-container', { warning: warning && warning(slot.m) })}>
|
||||
<div className={'sz'}>{slot.maxClass}</div>
|
||||
<div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import SlotSection from './SlotSection';
|
||||
import StandardSlot from './StandardSlot';
|
||||
import { diffDetails } from '../utils/SlotFunctions';
|
||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||
|
||||
/**
|
||||
* Standard Slot section
|
||||
@@ -171,7 +172,7 @@ export default class StandardSlotSection extends SlotSection {
|
||||
let bh = ship.bulkheads;
|
||||
|
||||
slots[0] = (
|
||||
<div key='bh' className={cn('slot', { selected: currentMenu === bh })} onClick={open.bind(this, bh)}>
|
||||
<div key='bh' className={cn('slot', { selected: currentMenu === bh })} onTouchTap={open.bind(this, bh)}>
|
||||
<div className={'details-container'}>
|
||||
<div className={'details'}>
|
||||
<div className={'sz'}>8</div>
|
||||
@@ -183,21 +184,21 @@ export default class StandardSlotSection extends SlotSection {
|
||||
</div>
|
||||
</div>
|
||||
{currentMenu === bh &&
|
||||
<div className='select' onClick={ e => e.stopPropagation() }>
|
||||
<div className='select' onTouchTap={ e => e.stopPropagation() }>
|
||||
<ul>
|
||||
<li onClick={selBulkhead.bind(this, 0)} onMouseOver={this._bhDiff.bind(this, 0)} onMouseLeave={this._hideDiff} className={cn('lc', { active: bh.index == 0 })}>
|
||||
<li onTouchTap={selBulkhead.bind(this, 0)} onMouseOver={this._bhDiff.bind(this, 0)} onMouseLeave={this._hideDiff} className={cn('lc', { active: bh.index == 0 })}>
|
||||
{translate('Lightweight Alloy')}
|
||||
</li>
|
||||
<li onClick={selBulkhead.bind(this, 1)} onMouseOver={this._bhDiff.bind(this, 1)} onMouseLeave={this._hideDiff} className={cn('lc', { active: bh.index == 1 })}>
|
||||
<li onTouchTap={selBulkhead.bind(this, 1)} onMouseOver={this._bhDiff.bind(this, 1)} onMouseLeave={this._hideDiff} className={cn('lc', { active: bh.index == 1 })}>
|
||||
{translate('Reinforced Alloy')}
|
||||
</li>
|
||||
<li onClick={selBulkhead.bind(this, 2)} onMouseOver={this._bhDiff.bind(this, 2)} onMouseLeave={this._hideDiff} className={cn('lc', { active: bh.index == 2 })}>
|
||||
<li onTouchTap={selBulkhead.bind(this, 2)} onMouseOver={this._bhDiff.bind(this, 2)} onMouseLeave={this._hideDiff} className={cn('lc', { active: bh.index == 2 })}>
|
||||
{translate('Military Grade Composite')}
|
||||
</li>
|
||||
<li onClick={selBulkhead.bind(this, 3)} onMouseOver={this._bhDiff.bind(this, 3)} onMouseLeave={this._hideDiff} className={cn('lc', { active: bh.index == 3 })}>
|
||||
<li onTouchTap={selBulkhead.bind(this, 3)} onMouseOver={this._bhDiff.bind(this, 3)} onMouseLeave={this._hideDiff} className={cn('lc', { active: bh.index == 3 })}>
|
||||
{translate('Mirrored Surface Composite')}
|
||||
</li>
|
||||
<li onClick={selBulkhead.bind(this, 4)} onMouseOver={this._bhDiff.bind(this, 4)} onMouseLeave={this._hideDiff} className={cn('lc', { active: bh.index == 4 })}>
|
||||
<li onTouchTap={selBulkhead.bind(this, 4)} onMouseOver={this._bhDiff.bind(this, 4)} onMouseLeave={this._hideDiff} className={cn('lc', { active: bh.index == 4 })}>
|
||||
{translate('Reactive Surface Composite')}
|
||||
</li>
|
||||
</ul>
|
||||
@@ -293,19 +294,19 @@ export default class StandardSlotSection extends SlotSection {
|
||||
_getSectionMenu(translate) {
|
||||
let _fill = this._fill;
|
||||
|
||||
return <div className='select' onClick={(e) => e.stopPropagation()}>
|
||||
return <div className='select' onTouchTap={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||
<ul>
|
||||
<li className='lc' onClick={this._optimizeStandard}>{translate('Optimize')}</li>
|
||||
<li className='c' onClick={_fill.bind(this, 'E')}>E</li>
|
||||
<li className='c' onClick={_fill.bind(this, 'D')}>D</li>
|
||||
<li className='c' onClick={_fill.bind(this, 'C')}>C</li>
|
||||
<li className='c' onClick={_fill.bind(this, 'B')}>B</li>
|
||||
<li className='c' onClick={_fill.bind(this, 'A')}>A</li>
|
||||
<li className='lc' onTouchTap={this._optimizeStandard}>{translate('Optimize')}</li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'E')}>E</li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'D')}>D</li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'C')}>C</li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'B')}>B</li>
|
||||
<li className='c' onTouchTap={_fill.bind(this, 'A')}>A</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('builds / roles')}</div>
|
||||
<ul>
|
||||
<li className='lc' onClick={this._optimizeCargo}>{translate('Trader')}</li>
|
||||
<li className='lc' onClick={this._optimizeExplorer}>{translate('Explorer')}</li>
|
||||
<li className='lc' onTouchTap={this._optimizeCargo}>{translate('Trader')}</li>
|
||||
<li className='lc' onTouchTap={this._optimizeExplorer}>{translate('Explorer')}</li>
|
||||
</ul>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
import { shallowEqual } from '../utils/UtilityFunctions';
|
||||
import TranslatedComponent from './TranslatedComponent';
|
||||
|
||||
/**
|
||||
* Document Root Tooltip
|
||||
*/
|
||||
export default class Tooltip extends React.Component {
|
||||
export default class Tooltip extends TranslatedComponent {
|
||||
|
||||
static propTypes = {
|
||||
rect: React.PropTypes.object.isRequired,
|
||||
@@ -16,36 +16,98 @@ export default class Tooltip extends React.Component {
|
||||
};
|
||||
|
||||
/**
|
||||
* Adjusts the position of the tooltip if its content
|
||||
* Constructor
|
||||
* @param {Object} props React Component properties
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this._adjustDimensions = this._adjustDimensions.bind(this);
|
||||
this.state = this._initialDimensions(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get position and reset width/height
|
||||
* @param {Object} props React Component properties
|
||||
* @return {Object} Dimenions / state
|
||||
*/
|
||||
_initialDimensions(props) {
|
||||
let { options, rect } = props;
|
||||
let orientation = options.orientation || 'n';
|
||||
let top, left;
|
||||
|
||||
switch (orientation) {
|
||||
case 's':
|
||||
top = Math.round(rect.top + rect.height);
|
||||
left = Math.round(rect.left + (rect.width / 2));
|
||||
break;
|
||||
case 'n':
|
||||
top = Math.round(rect.top);
|
||||
left = Math.round(rect.left + (rect.width / 2));
|
||||
break;
|
||||
case 'e':
|
||||
top = Math.round(rect.top + (rect.height / 2));
|
||||
left = Math.round(rect.left + rect.width);
|
||||
break;
|
||||
case 'w':
|
||||
top = Math.round(rect.top + (rect.height / 2));
|
||||
left = Math.round(rect.left);
|
||||
}
|
||||
|
||||
return { top, left, arrLeft: left, width: null, height: null, orientation };
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the position and size of the tooltip if its content
|
||||
* appear outside of the windows left or right border
|
||||
* @param {DomElement} elem Tooltip contents container
|
||||
*/
|
||||
_adjustPosition(elem) {
|
||||
if (elem) {
|
||||
let o = this.props.options.orientation || 'n';
|
||||
let rect = elem.getBoundingClientRect();
|
||||
_adjustDimensions() {
|
||||
if (this.elem) {
|
||||
let o = this.state.orientation;
|
||||
let rect = this.elem.getBoundingClientRect();
|
||||
|
||||
// Round widthand height to nearest even number to avoid translate3d text blur
|
||||
// caused by fractional pixels
|
||||
let width = Math.ceil(rect.width / 2) * 2;
|
||||
|
||||
this.setState({
|
||||
width,
|
||||
height: Math.round(rect.height / 2) * 2
|
||||
});
|
||||
|
||||
if (o == 'n' || o == 's') {
|
||||
let docWidth = document.documentElement.clientWidth;
|
||||
|
||||
if (rect.left < 0) {
|
||||
elem.style.left = rect.width / 2 + 'px';
|
||||
} else if ((rect.left + rect.width) > docWidth) {
|
||||
elem.style.left = docWidth - (rect.width / 2) + 'px';
|
||||
this.setState({ left: Math.round(width / 4) * 2 });
|
||||
} else if ((rect.left + width) > docWidth) {
|
||||
this.setState({ left: docWidth - Math.round(width / 4) * 2 });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a component should be rerendered
|
||||
* @param {object} nextProps Next properties
|
||||
* @return {boolean} true if update is needed
|
||||
*Potentially adjust component dimensions after mount
|
||||
*/
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !shallowEqual(this.props, nextProps);
|
||||
componentDidMount() {
|
||||
this._adjustDimensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset width and height on propChange
|
||||
* @param {Object} nextProps Incoming/Next properties
|
||||
*/
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState(this._initialDimensions(nextProps));
|
||||
}
|
||||
|
||||
/**
|
||||
* Potentially adjust component dimensions on re-render
|
||||
*/
|
||||
componentDidUpdate() {
|
||||
this._adjustDimensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component
|
||||
@@ -55,33 +117,12 @@ export default class Tooltip extends React.Component {
|
||||
if (!this.props.children) { // If no content is provided
|
||||
return null;
|
||||
}
|
||||
let { top, left, arrLeft, width, height, orientation } = this.state;
|
||||
|
||||
let { children, options, rect } = this.props;
|
||||
let o = options.orientation || 'n';
|
||||
let style = options.style || {};
|
||||
|
||||
switch (o) {
|
||||
case 's':
|
||||
style.top = rect.top + rect.height;
|
||||
style.left = rect.left + (rect.width / 2);
|
||||
break;
|
||||
case 'n':
|
||||
style.top = rect.top;
|
||||
style.left = rect.left + (rect.width / 2);
|
||||
break;
|
||||
case 'e':
|
||||
style.left = rect.left + rect.width;
|
||||
style.top = rect.top + (rect.height / 2);
|
||||
break;
|
||||
case 'w':
|
||||
style.left = rect.left;
|
||||
style.top = rect.top + (rect.height / 2);
|
||||
}
|
||||
|
||||
return <div>
|
||||
<div className={ 'arr ' + o} style={style} />
|
||||
<div className={ 'tip ' + o} style={style} ref={this._adjustPosition.bind(this)}>
|
||||
{children}
|
||||
return <div style={{ fontSize: this.context.sizeRatio + 'em' }}>
|
||||
<div className={ 'arr ' + orientation} style={{ top, left: arrLeft }} />
|
||||
<div className={ 'tip ' + orientation} style={{ top, left, width, height }} ref={(elem) => this.elem = elem}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import SlotSection from './SlotSection';
|
||||
import HardpointSlot from './HardpointSlot';
|
||||
import cn from 'classnames';
|
||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||
|
||||
/**
|
||||
* Utility Slot Section
|
||||
@@ -90,21 +91,21 @@ export default class UtilitySlotSection extends SlotSection {
|
||||
_getSectionMenu(translate) {
|
||||
let _use = this._use;
|
||||
|
||||
return <div className='select' onClick={(e) => e.stopPropagation()}>
|
||||
return <div className='select' onTouchTap={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||
<ul>
|
||||
<li className='lc' onClick={this._empty}>{translate('empty all')}</li>
|
||||
<li className='lc' onTouchTap={this._empty}>{translate('empty all')}</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('sb')}</div>
|
||||
<ul>
|
||||
<li className='c' onClick={_use.bind(this, 'sb', 'E', null)}>E</li>
|
||||
<li className='c' onClick={_use.bind(this, 'sb', 'D', null)}>D</li>
|
||||
<li className='c' onClick={_use.bind(this, 'sb', 'C', null)}>C</li>
|
||||
<li className='c' onClick={_use.bind(this, 'sb', 'B', null)}>B</li>
|
||||
<li className='c' onClick={_use.bind(this, 'sb', 'A', null)}>A</li>
|
||||
<li className='c' onTouchTap={_use.bind(this, 'sb', 'E', null)}>E</li>
|
||||
<li className='c' onTouchTap={_use.bind(this, 'sb', 'D', null)}>D</li>
|
||||
<li className='c' onTouchTap={_use.bind(this, 'sb', 'C', null)}>C</li>
|
||||
<li className='c' onTouchTap={_use.bind(this, 'sb', 'B', null)}>B</li>
|
||||
<li className='c' onTouchTap={_use.bind(this, 'sb', 'A', null)}>A</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('cm')}</div>
|
||||
<ul>
|
||||
<li className='lc' onClick={_use.bind(this, 'cm', null, 'Heat Sink Launcher')}>{translate('Heat Sink Launcher')}</li>
|
||||
<li className='lc' onTouchTap={_use.bind(this, 'cm', null, 'Heat Sink Launcher')}>{translate('Heat Sink Launcher')}</li>
|
||||
</ul>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import 'babel-polyfill';
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import '../less/app.less';
|
||||
import Coriolis from './Coriolis';
|
||||
import TapEventPlugin from 'react/lib/TapEventPlugin';
|
||||
import EventPluginHub from 'react/lib/EventPluginHub';
|
||||
|
||||
EventPluginHub.injection.injectEventPluginsByName({ TapEventPlugin });
|
||||
|
||||
render(<Coriolis />, document.getElementById('coriolis'));
|
||||
|
||||
@@ -13,6 +13,7 @@ import BarChart from '../components/BarChart';
|
||||
import ModalCompare from '../components/ModalCompare';
|
||||
import ModalExport from '../components/ModalExport';
|
||||
import ModalPermalink from '../components/ModalPermalink';
|
||||
import ModalImport from '../components/ModalImport';
|
||||
import { FloppyDisk, Bin, Download, Embed, Rocket, LinkIcon } from '../components/SvgIcons';
|
||||
import ShortenUrl from '../utils/ShortenUrl';
|
||||
import { comparisonBBCode } from '../utils/BBCode';
|
||||
@@ -295,7 +296,16 @@ export default class ComparisonPage extends Page {
|
||||
* Import the comparison builds
|
||||
*/
|
||||
_import() {
|
||||
// TODO: Implement
|
||||
let builds = {};
|
||||
|
||||
for (let ship of this.state.builds) {
|
||||
if (!builds[ship.id]) {
|
||||
builds[ship.id] = {};
|
||||
}
|
||||
builds[ship.id][ship.buildName] = ship.toString();
|
||||
}
|
||||
|
||||
this.context.showModal(<ModalImport builds={builds} />);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,7 +342,7 @@ export default class ComparisonPage extends Page {
|
||||
|
||||
let code = fromComparison(name, builds, selectedFacets, predicate, desc);
|
||||
let loc = window.location;
|
||||
return `${loc.protocol}://${loc.host}/comparison/${code}`;
|
||||
return `${loc.protocol}//${loc.host}/comparison/${code}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -418,17 +428,17 @@ export default class ComparisonPage extends Page {
|
||||
<td className='head'>{translate('comparison')}</td>
|
||||
<td>
|
||||
<input value={newName} onChange={this._onNameChange} placeholder={translate('Enter Name')} maxLength='50' />
|
||||
<button onClick={this._save} disabled={!newName || newName == 'all' || saved}>
|
||||
<button onTouchTap={this._save} disabled={!newName || newName == 'all' || saved}>
|
||||
<FloppyDisk className='lg'/><span className='button-lbl'>{translate('save')}</span>
|
||||
</button>
|
||||
<button onClick={this._delete} disabled={name == 'all' || !saved}><Bin className='lg warning'/></button>
|
||||
<button onClick={this._selectBuilds}>
|
||||
<button onTouchTap={this._delete} disabled={name == 'all' || !saved}><Bin className='lg warning'/></button>
|
||||
<button onTouchTap={this._selectBuilds}>
|
||||
<Rocket className='lg'/><span className='button-lbl'>{translate('builds')}</span>
|
||||
</button>
|
||||
<button className='r' onClick={this._genPermalink} disabled={builds.length == 0}>
|
||||
<button className='r' onTouchTap={this._genPermalink} disabled={builds.length == 0}>
|
||||
<LinkIcon className='lg'/><span className='button-lbl'>{translate('permalink')}</span>
|
||||
</button>
|
||||
<button className='r' onClick={this._genBBcode} disabled={builds.length == 0}>
|
||||
<button className='r' onTouchTap={this._genBBcode} disabled={builds.length == 0}>
|
||||
<Embed className='lg'/><span className='button-lbl'>{translate('forum')}</span>
|
||||
</button>
|
||||
</td>
|
||||
@@ -438,7 +448,7 @@ export default class ComparisonPage extends Page {
|
||||
<td className='head'>{translate('comparison')}</td>
|
||||
<td>
|
||||
<h3>{name}</h3>
|
||||
<button className='r' onClick={this._import}><Download className='lg'/>{translate('import')}</button>
|
||||
<button className='r' onTouchTap={this._import}><Download className='lg'/>{translate('import')}</button>
|
||||
</td>
|
||||
</tr>;
|
||||
}
|
||||
@@ -453,7 +463,7 @@ export default class ComparisonPage extends Page {
|
||||
<td>
|
||||
<ul id='facet-container' onDragOver={this._facetDragOver}>
|
||||
{facets.map((f, i) =>
|
||||
<li key={f.title} data-i={i} draggable='true' onDragStart={this._facetDrag} onDragEnd={this._facetDrop} className={cn('facet', { active: f.active })} onClick={this._toggleFacet.bind(this, f)}>
|
||||
<li key={f.title} data-i={i} draggable='true' onDragStart={this._facetDrag} onDragEnd={this._facetDrop} className={cn('facet', { active: f.active })} onTouchTap={this._toggleFacet.bind(this, f)}>
|
||||
{'↔ ' + translate(f.title)}
|
||||
</li>
|
||||
)}
|
||||
@@ -469,7 +479,7 @@ export default class ComparisonPage extends Page {
|
||||
<div className='chart' ref={'chartRef'}>{translate('PHRASE_NO_BUILDS')}</div> :
|
||||
facets.filter((f) => f.active).map((f, i) =>
|
||||
<div key={f.title} className='chart' ref={ i == 0 ? 'chartRef' : null}>
|
||||
<h3 className='ptr' onClick={this._sortShips.bind(this, f.props[0])}>{translate(f.title)}</h3>
|
||||
<h3 className='ptr' onTouchTap={this._sortShips.bind(this, f.props[0])}>{translate(f.title)}</h3>
|
||||
<BarChart
|
||||
width={chartWidth}
|
||||
data={builds}
|
||||
|
||||
@@ -76,9 +76,9 @@ export default class OutfittingPage extends Page {
|
||||
savedCode,
|
||||
fuelCapacity,
|
||||
fuelLevel: 1,
|
||||
jumpRangeChartFunc: ship.getJumpRangeWith.bind(ship, fuelCapacity),
|
||||
totalRangeChartFunc: ship.getFastestRangeWith.bind(ship, fuelCapacity),
|
||||
speedChartFunc: ship.getSpeedsWith.bind(ship, fuelCapacity)
|
||||
jumpRangeChartFunc: ship.calcJumpRangeWith.bind(ship, fuelCapacity),
|
||||
totalRangeChartFunc: ship.calcFastestRangeWith.bind(ship, fuelCapacity),
|
||||
speedChartFunc: ship.calcSpeedsWith.bind(ship, fuelCapacity)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -188,9 +188,9 @@ export default class OutfittingPage extends Page {
|
||||
this.setState({
|
||||
fuelLevel,
|
||||
fuelCapacity,
|
||||
jumpRangeChartFunc: ship.getJumpRangeWith.bind(ship, fuel),
|
||||
totalRangeChartFunc: ship.getFastestRangeWith.bind(ship, fuel),
|
||||
speedChartFunc: ship.getSpeedsWith.bind(ship, fuel)
|
||||
jumpRangeChartFunc: ship.calcJumpRangeWith.bind(ship, fuel),
|
||||
totalRangeChartFunc: ship.calcFastestRangeWith.bind(ship, fuel),
|
||||
speedChartFunc: ship.calcSpeedsWith.bind(ship, fuel)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -240,11 +240,11 @@ export default class OutfittingPage extends Page {
|
||||
* @return {React.Component} The page contents
|
||||
*/
|
||||
render() {
|
||||
let { translate, units, formats, termtip } = this.context.language;
|
||||
let tip = this.context.termtip;
|
||||
let hide = this.context.tooltip.bind(null, null);
|
||||
let state = this.state;
|
||||
let { language, termtip, tooltip, sizeRatio, onWindowResize } = this.context;
|
||||
let { translate, units, formats } = language;
|
||||
let { ship, code, savedCode, buildName, chartWidth, fuelCapacity, fuelLevel } = state;
|
||||
let hide = tooltip.bind(null, null);
|
||||
let menu = this.props.currentMenu;
|
||||
let shipUpdated = this._shipUpdated;
|
||||
let hStr = ship.getHardpointsString();
|
||||
@@ -252,24 +252,24 @@ export default class OutfittingPage extends Page {
|
||||
let iStr = ship.getInternalString();
|
||||
|
||||
return (
|
||||
<div id='outfit' className={'page'} style={{ fontSize: (this.context.sizeRatio * 0.9) + 'em' }}>
|
||||
<div id='outfit' className={'page'} style={{ fontSize: (sizeRatio * 0.9) + 'em' }}>
|
||||
<div id='overview'>
|
||||
<h1>{ship.name}</h1>
|
||||
<div id='build'>
|
||||
<input value={buildName} onChange={this._buildNameChange} placeholder={translate('Enter Name')} maxsize={50} />
|
||||
<button onClick={this._saveBuild} disabled={!buildName || savedCode && code == savedCode} onMouseOver={tip.bind(null, 'save')} onMouseOut={hide}>
|
||||
<button onTouchTap={this._saveBuild} disabled={!buildName || savedCode && code == savedCode} onMouseOver={termtip.bind(null, 'save')} onMouseOut={hide}>
|
||||
<FloppyDisk className='lg' />
|
||||
</button>
|
||||
<button onClick={this._reloadBuild} disabled={!savedCode || code == savedCode} onMouseOver={tip.bind(null, 'reload')} onMouseOut={hide}>
|
||||
<button onTouchTap={this._reloadBuild} disabled={!savedCode || code == savedCode} onMouseOver={termtip.bind(null, 'reload')} onMouseOut={hide}>
|
||||
<Reload className='lg'/>
|
||||
</button>
|
||||
<button className={'danger'} onClick={this._deleteBuild} disabled={!savedCode} onMouseOver={tip.bind(null, 'delete')} onMouseOut={hide}>
|
||||
<button className={'danger'} onTouchTap={this._deleteBuild} disabled={!savedCode} onMouseOver={termtip.bind(null, 'delete')} onMouseOut={hide}>
|
||||
<Bin className='lg'/>
|
||||
</button>
|
||||
<button onClick={this._resetBuild} disabled={!code} onMouseOver={tip.bind(null, 'reset')} onMouseOut={hide}>
|
||||
<button onTouchTap={this._resetBuild} disabled={!code} onMouseOver={termtip.bind(null, 'reset')} onMouseOut={hide}>
|
||||
<Switch className='lg'/>
|
||||
</button>
|
||||
<button onClick={this._exportBuild} disabled={!buildName} onMouseOver={tip.bind(null, 'export')} onMouseOut={hide}>
|
||||
<button onTouchTap={this._exportBuild} disabled={!buildName} onMouseOver={termtip.bind(null, 'export')} onMouseOut={hide}>
|
||||
<Download className='lg'/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -331,9 +331,21 @@ export default class OutfittingPage extends Page {
|
||||
<table style={{ width: '100%', lineHeight: '1em', backgroundColor: 'transparent' }}>
|
||||
<tbody >
|
||||
<tr>
|
||||
<td style={{ verticalAlign: 'top', padding: 0, width: '2.5em' }}><Fuel className='xl primary-disabled' /></td>
|
||||
<td><Slider axis={true} onChange={this._fuelChange} axisUnit={translate('T')} percent={fuelLevel} max={fuelCapacity} /></td>
|
||||
<td className='primary' style={{ width: '10em', verticalAlign: 'top', fontSize: '0.9em' }}>{formats.f2(fuelLevel * fuelCapacity)}{units.T} {formats.pct1(fuelLevel)}</td>
|
||||
<td style={{ verticalAlign: 'top', padding: 0, width: '2.5em' }} onMouseEnter={termtip.bind(null, 'fuel level')} onMouseLeave={hide}>
|
||||
<Fuel className='xl primary-disabled' />
|
||||
</td>
|
||||
<td>
|
||||
<Slider
|
||||
axis={true}
|
||||
onChange={this._fuelChange}
|
||||
axisUnit={translate('T')}
|
||||
percent={fuelLevel}
|
||||
max={fuelCapacity}
|
||||
scale={sizeRatio}
|
||||
onResize={onWindowResize}
|
||||
/>
|
||||
</td>
|
||||
<td className='primary' style={{ width: '10em', verticalAlign: 'top', fontSize: '0.9em', textAlign: 'left' }}>{formats.f2(fuelLevel * fuelCapacity)}{units.T} {formats.pct1(fuelLevel)}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -205,44 +205,44 @@ export default class ShipyardPage extends Page {
|
||||
<table style={{ fontSize:'0.85em', whiteSpace:'nowrap', margin: '0 auto' }} align='center'>
|
||||
<thead>
|
||||
<tr className='main'>
|
||||
<th rowSpan={2} className='sortable le' onClick={sortShips('name')}>{translate('ship')}</th>
|
||||
<th rowSpan={2} className='sortable' onClick={sortShips('manufacturer')}>{translate('manufacturer')}</th>
|
||||
<th rowSpan={2} className='sortable' onClick={sortShips('class')}>{translate('size')}</th>
|
||||
<th rowSpan={2} className='sortable' onMouseEnter={tip.bind(null, 'maneuverability')} onMouseLeave={hide} onClick={sortShips('agility')}>{translate('mnv')}</th>
|
||||
<th rowSpan={2} className='sortable le' onTouchTap={sortShips('name')}>{translate('ship')}</th>
|
||||
<th rowSpan={2} className='sortable' onTouchTap={sortShips('manufacturer')}>{translate('manufacturer')}</th>
|
||||
<th rowSpan={2} className='sortable' onTouchTap={sortShips('class')}>{translate('size')}</th>
|
||||
<th rowSpan={2} className='sortable' onMouseEnter={tip.bind(null, 'maneuverability')} onMouseLeave={hide} onTouchTap={sortShips('agility')}>{translate('mnv')}</th>
|
||||
<th colSpan={4}>{translate('base')}</th>
|
||||
<th colSpan={4}>{translate('max')}</th>
|
||||
<th colSpan={5} className='sortable' onClick={sortShips('hpCount')}>{translate('hardpoints')}</th>
|
||||
<th colSpan={8} className='sortable' onClick={sortShips('intCount')}>{translate('internal compartments')}</th>
|
||||
<th rowSpan={2} className='sortable' onClick={sortShips('hullMass')}>{translate('hull')}</th>
|
||||
<th rowSpan={2} className='sortable' onMouseEnter={tip.bind(null, 'mass lock factor')} onMouseLeave={hide} onClick={sortShips('masslock')} >{translate('MLF')}</th>
|
||||
<th rowSpan={2} className='sortable' onClick={sortShips('retailCost')}>{translate('cost')}</th>
|
||||
<th colSpan={5} className='sortable' onTouchTap={sortShips('hpCount')}>{translate('hardpoints')}</th>
|
||||
<th colSpan={8} className='sortable' onTouchTap={sortShips('intCount')}>{translate('internal compartments')}</th>
|
||||
<th rowSpan={2} className='sortable' onTouchTap={sortShips('hullMass')}>{translate('hull')}</th>
|
||||
<th rowSpan={2} className='sortable' onMouseEnter={tip.bind(null, 'mass lock factor')} onMouseLeave={hide} onTouchTap={sortShips('masslock')} >{translate('MLF')}</th>
|
||||
<th rowSpan={2} className='sortable' onTouchTap={sortShips('retailCost')}>{translate('cost')}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
{/* Base */}
|
||||
<th className='sortable lft' onClick={sortShips('speed')}>{translate('speed')}</th>
|
||||
<th className='sortable' onClick={sortShips('boost')}>{translate('boost')}</th>
|
||||
<th className='sortable' onClick={sortShips('baseArmour')}>{translate('armour')}</th>
|
||||
<th className='sortable' onClick={sortShips('baseShieldStrength')}>{translate('shields')}</th>
|
||||
<th className='sortable lft' onTouchTap={sortShips('speed')}>{translate('speed')}</th>
|
||||
<th className='sortable' onTouchTap={sortShips('boost')}>{translate('boost')}</th>
|
||||
<th className='sortable' onTouchTap={sortShips('baseArmour')}>{translate('armour')}</th>
|
||||
<th className='sortable' onTouchTap={sortShips('baseShieldStrength')}>{translate('shields')}</th>
|
||||
{/* Max */}
|
||||
<th className='sortable lft' onClick={sortShips('topSpeed')}>{translate('speed')}</th>
|
||||
<th className='sortable' onClick={sortShips('topBoost')}>{translate('boost')}</th>
|
||||
<th className='sortable' onClick={sortShips('maxJumpRange')}>{translate('jump')}</th>
|
||||
<th className='sortable' onClick={sortShips('maxCargo')}>{translate('cargo')}</th>
|
||||
<th className='sortable lft' onTouchTap={sortShips('topSpeed')}>{translate('speed')}</th>
|
||||
<th className='sortable' onTouchTap={sortShips('topBoost')}>{translate('boost')}</th>
|
||||
<th className='sortable' onTouchTap={sortShips('maxJumpRange')}>{translate('jump')}</th>
|
||||
<th className='sortable' onTouchTap={sortShips('maxCargo')}>{translate('cargo')}</th>
|
||||
{/* Hardpoints */}
|
||||
<th className='sortable lft' onClick={sortShips('hp',1)}>{translate('S')}</th>
|
||||
<th className='sortable' onClick={sortShips('hp', 2)}>{translate('M')}</th>
|
||||
<th className='sortable' onClick={sortShips('hp', 3)}>{translate('L')}</th>
|
||||
<th className='sortable' onClick={sortShips('hp', 4)}>{translate('H')}</th>
|
||||
<th className='sortable' onClick={sortShips('hp', 0)}>{translate('U')}</th>
|
||||
<th className='sortable lft' onTouchTap={sortShips('hp',1)}>{translate('S')}</th>
|
||||
<th className='sortable' onTouchTap={sortShips('hp', 2)}>{translate('M')}</th>
|
||||
<th className='sortable' onTouchTap={sortShips('hp', 3)}>{translate('L')}</th>
|
||||
<th className='sortable' onTouchTap={sortShips('hp', 4)}>{translate('H')}</th>
|
||||
<th className='sortable' onTouchTap={sortShips('hp', 0)}>{translate('U')}</th>
|
||||
{/* Internal */}
|
||||
<th className='sortable lft' onClick={sortShips('int', 0)} >1</th>
|
||||
<th className='sortable' onClick={sortShips('int', 1)} >2</th>
|
||||
<th className='sortable' onClick={sortShips('int', 2)} >3</th>
|
||||
<th className='sortable' onClick={sortShips('int', 3)} >4</th>
|
||||
<th className='sortable' onClick={sortShips('int', 4)} >5</th>
|
||||
<th className='sortable' onClick={sortShips('int', 5)} >6</th>
|
||||
<th className='sortable' onClick={sortShips('int', 6)} >7</th>
|
||||
<th className='sortable' onClick={sortShips('int', 7)} >8</th>
|
||||
<th className='sortable lft' onTouchTap={sortShips('int', 0)} >1</th>
|
||||
<th className='sortable' onTouchTap={sortShips('int', 1)} >2</th>
|
||||
<th className='sortable' onTouchTap={sortShips('int', 2)} >3</th>
|
||||
<th className='sortable' onTouchTap={sortShips('int', 3)} >4</th>
|
||||
<th className='sortable' onTouchTap={sortShips('int', 4)} >5</th>
|
||||
<th className='sortable' onTouchTap={sortShips('int', 5)} >6</th>
|
||||
<th className='sortable' onTouchTap={sortShips('int', 6)} >7</th>
|
||||
<th className='sortable' onTouchTap={sortShips('int', 7)} >8</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -109,14 +109,6 @@ export default class Ship {
|
||||
|
||||
/* GETTERS */
|
||||
|
||||
/**
|
||||
* [getAvailableModules description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getAvailableModules() {
|
||||
return this.availCS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the ship thrust/move
|
||||
* @return {[type]} True if thrusters operational
|
||||
@@ -136,6 +128,86 @@ export default class Ship {
|
||||
this.boostEnergy <= this.standard[4].m.enginecapacity; // PD capacitor is sufficient for boost
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate hypothetical jump range using the installed FSD and the
|
||||
* specified mass which can be more or less than ships actual mass
|
||||
* @param {number} fuel Fuel available in tons
|
||||
* @param {number} cargo Cargo in tons
|
||||
* @return {number} Jump range in Light Years
|
||||
*/
|
||||
calcJumpRangeWith(fuel, cargo) {
|
||||
return Calc.jumpRange(this.unladenMass + fuel + cargo, this.standard[2].m, fuel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hypothetical laden jump range based on a potential change in mass, fuel, or FSD
|
||||
* @param {number} massDelta Optional - Change in laden mass (mass + cargo + fuel)
|
||||
* @param {number} fuel Optional - Available fuel (defaults to max fuel based on FSD)
|
||||
* @param {Object} fsd Optional - Frame Shift Drive (or use mounted FSD)
|
||||
* @return {number} Jump range in Light Years
|
||||
*/
|
||||
calcLadenRange(massDelta, fuel, fsd) {
|
||||
return Calc.jumpRange(this.ladenMass + (massDelta || 0), fsd || this.standard[2].m, fuel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hypothetical unladen jump range based on a potential change in mass, fuel, or FSD
|
||||
* @param {number} massDelta Optional - Change in ship mass
|
||||
* @param {number} fuel Optional - Available fuel (defaults to lesser of fuel capacity or max fuel based on FSD)
|
||||
* @param {Object} fsd Optional - Frame Shift Drive (or use mounted FSD)
|
||||
* @return {number} Jump range in Light Years
|
||||
*/
|
||||
calcUnladenRange(massDelta, fuel, fsd) {
|
||||
fsd = fsd || this.standard[2].m;
|
||||
return Calc.jumpRange(this.unladenMass + (massDelta || 0) + Math.min(fsd.maxfuel, fuel || this.fuelCapacity), fsd || this.standard[2].m, fuel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate cumulative (total) jump range when making longest jumps using the installed FSD and the
|
||||
* specified mass which can be more or less than ships actual mass
|
||||
* @param {number} fuel Fuel available in tons
|
||||
* @param {number} cargo Cargo in tons
|
||||
* @return {number} Total/Cumulative Jump range in Light Years
|
||||
*/
|
||||
calcFastestRangeWith(fuel, cargo) {
|
||||
return Calc.totalRange(this.unladenMass + fuel + cargo, this.standard[2].m, fuel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hypothetical top speeds at cargo and fuel tonnage
|
||||
* @param {number} fuel Fuel available in tons
|
||||
* @param {number} cargo Cargo in tons
|
||||
* @return {Object} Speed at pip settings and boost
|
||||
*/
|
||||
calcSpeedsWith(fuel, cargo) {
|
||||
return Calc.speed(this.unladenMass + fuel + cargo, this.speed, this.boost, this.standard[1].m, this.pipSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hypothetical shield strength for the ship using the specified parameters
|
||||
* @param {Object} sg [optional] Shield Generator to use
|
||||
* @param {number} multiplierDelta [optional] Change to shield multiplier (+0.2, - 0.12, etc)
|
||||
* @return {number} Shield strength in MH
|
||||
*/
|
||||
calcShieldStrengthWith(sg, multiplierDelta) {
|
||||
if (!sg) {
|
||||
let sgSlot = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any
|
||||
if (!sgSlot) {
|
||||
return 0;
|
||||
}
|
||||
sg = sgSlot.m;
|
||||
}
|
||||
return Calc.shieldStrength(this.hullMass, this.baseShieldStrength, sg, this.shieldMultiplier + (multiplierDelta || 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* [getAvailableModules description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getAvailableModules() {
|
||||
return this.availCS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the a slots power status:
|
||||
* 0 - No status [Blank]
|
||||
@@ -160,61 +232,6 @@ export default class Ship {
|
||||
return this.priorityBands[slot.priority].retractedSum >= this.powerAvailable ? 2 : 3; // Offline : Online
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate jump range using the installed FSD and the
|
||||
* specified mass which can be more or less than ships actual mass
|
||||
* @param {number} fuel Fuel available in tons
|
||||
* @param {number} cargo Cargo in tons
|
||||
* @return {number} Jump range in Light Years
|
||||
*/
|
||||
getJumpRangeWith(fuel, cargo) {
|
||||
return Calc.jumpRange(this.unladenMass + fuel + cargo, this.standard[2].m, fuel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the laden jump range based on a potential change in mass, fuel, or FSD
|
||||
* @param {number} massDelta Optional - Change in laden mass (mass + cargo + fuel)
|
||||
* @param {number} fuel Optional - Available fuel (defaults to max fuel based on FSD)
|
||||
* @param {Object} fsd Optional - Frame Shift Drive (or use mounted FSD)
|
||||
* @return {number} Jump range in Light Years
|
||||
*/
|
||||
getLadenRange(massDelta, fuel, fsd) {
|
||||
return Calc.jumpRange(this.ladenMass + (massDelta || 0), fsd || this.standard[2].m, fuel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unladen jump range based on a potential change in mass, fuel, or FSD
|
||||
* @param {number} massDelta Optional - Change in ship mass
|
||||
* @param {number} fuel Optional - Available fuel (defaults to lesser of fuel capacity or max fuel based on FSD)
|
||||
* @param {Object} fsd Optional - Frame Shift Drive (or use mounted FSD)
|
||||
* @return {number} Jump range in Light Years
|
||||
*/
|
||||
getUnladenRange(massDelta, fuel, fsd) {
|
||||
fsd = fsd || this.standard[2].m;
|
||||
return Calc.jumpRange(this.unladenMass + (massDelta || 0) + Math.min(fsd.maxfuel, fuel || this.fuelCapacity), fsd || this.standard[2].m, fuel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate cumulative (total) jump range when making longest jumps using the installed FSD and the
|
||||
* specified mass which can be more or less than ships actual mass
|
||||
* @param {number} fuel Fuel available in tons
|
||||
* @param {number} cargo Cargo in tons
|
||||
* @return {number} Total/Cumulative Jump range in Light Years
|
||||
*/
|
||||
getFastestRangeWith(fuel, cargo) {
|
||||
return Calc.totalRange(this.unladenMass + fuel + cargo, this.standard[2].m, fuel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the top speeds at cargo and fuel tonnage
|
||||
* @param {number} fuel Fuel available in tons
|
||||
* @param {number} cargo Cargo in tons
|
||||
* @return {Object} Speed at pip settings and boost
|
||||
*/
|
||||
getSpeedsWith(fuel, cargo) {
|
||||
return Calc.speed(this.unladenMass + fuel + cargo, this.speed, this.boost, this.standard[1].m, this.pipSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an internal slot that has an installed modul of the specific group.
|
||||
*
|
||||
@@ -426,6 +443,7 @@ export default class Ship {
|
||||
* code.
|
||||
*
|
||||
* @param {string} serializedString The string to deserialize
|
||||
* @return {this} The current ship instance for chaining
|
||||
*/
|
||||
buildFrom(serializedString) {
|
||||
let standard = new Array(this.standard.length),
|
||||
@@ -446,7 +464,7 @@ export default class Ship {
|
||||
|
||||
decodeToArray(code, internal, decodeToArray(code, hardpoints, decodeToArray(code, standard, 1)));
|
||||
|
||||
this.buildWith(
|
||||
return this.buildWith(
|
||||
{
|
||||
bulkheads: code.charAt(0) * 1,
|
||||
standard,
|
||||
@@ -716,9 +734,9 @@ export default class Ship {
|
||||
updateJumpStats() {
|
||||
let fsd = this.standard[2].m; // Frame Shift Drive;
|
||||
let { unladenMass, ladenMass, fuelCapacity } = this;
|
||||
this.unladenRange = this.getUnladenRange(); // Includes fuel weight for jump
|
||||
this.unladenRange = this.calcUnladenRange(); // Includes fuel weight for jump
|
||||
this.fullTankRange = Calc.jumpRange(unladenMass + fuelCapacity, fsd); // Full Tank
|
||||
this.ladenRange = this.getLadenRange(); // Includes full tank and caro
|
||||
this.ladenRange = this.calcLadenRange(); // Includes full tank and caro
|
||||
this.unladenTotalRange = Calc.totalRange(unladenMass, fsd, fuelCapacity);
|
||||
this.ladenTotalRange = Calc.totalRange(unladenMass + this.cargoCapacity, fsd, fuelCapacity);
|
||||
this.maxJumpCount = Math.ceil(fuelCapacity / fsd.maxfuel);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import { isShieldGenerator } from '../shipyard/ModuleUtils';
|
||||
import { Infinite } from '../components/SvgIcons';
|
||||
|
||||
/**
|
||||
@@ -80,12 +81,16 @@ const PROP_BLACKLIST = {
|
||||
fuelpower: 1,
|
||||
optmass: 1,
|
||||
maxmass: 1,
|
||||
minmass: 1,
|
||||
passive: 1,
|
||||
thermload: 1,
|
||||
ammocost: 1,
|
||||
activepower: 1,
|
||||
cooldown: 1,
|
||||
chargeup: 1,
|
||||
optmul: 1,
|
||||
minmul: 1,
|
||||
maxmul: 1,
|
||||
ssdam: 1,
|
||||
mjdps: 1,
|
||||
mjeps: 1,
|
||||
@@ -98,7 +103,7 @@ const PROP_BLACKLIST = {
|
||||
const TERM_LOOKUP = {
|
||||
pGen: 'power',
|
||||
armouradd: 'armour',
|
||||
shieldmul: 'shield',
|
||||
shieldmul: 'multiplier',
|
||||
rof: 'ROF',
|
||||
dps: 'DPS'
|
||||
};
|
||||
@@ -148,7 +153,7 @@ function diff(format, mVal, mmVal) {
|
||||
return <Infinite/>;
|
||||
} else {
|
||||
let diff = mVal - mmVal;
|
||||
if (!diff || diff == mVal || Math.abs(diff) == Infinity) {
|
||||
if (!diff || !mVal || diff == mVal || Math.abs(diff) == Infinity) {
|
||||
return format(mVal);
|
||||
}
|
||||
return `${format(mVal)} (${diff > 0 ? '+' : ''}${format(diff)})`;
|
||||
@@ -157,10 +162,13 @@ function diff(format, mVal, mmVal) {
|
||||
|
||||
/**
|
||||
* Returns a a summary and diff of the potential module
|
||||
* versus the currently mounted module if there is one
|
||||
* versus the currently mounted module if there is one. Must be bound
|
||||
* to a ship instance
|
||||
*
|
||||
* @this {Ship}
|
||||
* @param {Object} language Current language
|
||||
* @param {Object} m Potential Module (cannot be null)
|
||||
* @param {Object} mm Currently mounted module (optional - null)
|
||||
* @param {Object} mm Currently mounted module (optional - null if empty)
|
||||
* @return {React.Component} Component to be rendered
|
||||
*/
|
||||
export function diffDetails(language, m, mm) {
|
||||
@@ -171,6 +179,8 @@ export function diffDetails(language, m, mm) {
|
||||
let mmMass = mm.mass || 0;
|
||||
let massDiff = mMass - mmMass;
|
||||
let capDiff = (m.fuel || m.cargo || 0) - (mm.fuel || mm.cargo || 0);
|
||||
let mAffectsShield = isShieldGenerator(m.grp) || m.grp == 'sb';
|
||||
let mmAffectsShield = isShieldGenerator(mm.grp) || mm.grp == 'sb';
|
||||
|
||||
propDiffs.push(<div key='cost'>{translate('cost')}: <span className={diffClass(m.cost, mm.cost, true) }>{formats.int(m.cost || 0)}{units.CR}</span></div>);
|
||||
propDiffs.push(<div key='mass'>{translate('mass')}: <span className={diffClass(mMass, mm.mass, true)}>{diff(formats.round, mMass, mmMass)}{units.T}</span></div>);
|
||||
@@ -187,10 +197,24 @@ export function diffDetails(language, m, mm) {
|
||||
}
|
||||
}
|
||||
|
||||
if (mAffectsShield || mmAffectsShield) {
|
||||
let shield = this.calcShieldStrengthWith(); // Get shield strength regardless of slot active / inactive
|
||||
let newShield = 0;
|
||||
|
||||
if (mAffectsShield) {
|
||||
if (m.grp == 'sb') { // Both m and mm must be utility modules if this is true
|
||||
newShield = this.calcShieldStrengthWith(null, m.shieldmul - (mm.shieldmul || 0));
|
||||
} else {
|
||||
newShield = this.calcShieldStrengthWith(m);
|
||||
}
|
||||
}
|
||||
propDiffs.push(<div key='shields'>{`${translate('shields')}: `}<span className={newShield > shield ? 'secondary' : 'warning'}>{diff(formats.int, newShield, shield)}{units.MJ}</span></div>);
|
||||
}
|
||||
|
||||
if (m.grp == 'fd' || massDiff || capDiff) {
|
||||
let fsd = m.grp == 'fd' ? m : null;
|
||||
let maxRange = this.getUnladenRange(massDiff, m.fuel, fsd);
|
||||
let ladenRange = this.getLadenRange(massDiff + capDiff, m.fuel, fsd);
|
||||
let maxRange = this.calcUnladenRange(massDiff, m.fuel, fsd);
|
||||
let ladenRange = this.calcLadenRange(massDiff + capDiff, m.fuel, fsd);
|
||||
|
||||
if (maxRange != this.unladenRange) {
|
||||
propDiffs.push(<div key='maxRange'>{`${translate('max')} ${translate('jump range')}: `}<span className={maxRange > this.unladenRange ? 'secondary' : 'warning'}>{formats.round(maxRange)}{units.LY}</span></div>);
|
||||
|
||||
@@ -14,6 +14,17 @@ export function wrapCtxMenu(cb) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop context menu / right-click propagation unless shift is held.
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
export function stopCtxPropagation(event) {
|
||||
if (!event.getModifierState('Shift')) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares A and B and return true using strict comparison (===)
|
||||
* @param {any} objA A
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
// Background colors
|
||||
@bg: rgba(30,30,30,1);
|
||||
@bgBlack: rgba(0,0,0,0.9);
|
||||
@bgBlack: #000;
|
||||
@primary-bg: fadeout(darken(@primary, 47%), 15%);
|
||||
@secondary-bg: fadeout(darken(@secondary, @bgDarken), @bgTransparency); // Brown background
|
||||
@warning-bg: fadeout(darken(@warning, @bgDarken), @bgTransparency); // Dark Red
|
||||
|
||||
@@ -41,16 +41,6 @@ tbody tr {
|
||||
&.tr {
|
||||
color: @fg;
|
||||
text-align: right;
|
||||
|
||||
&:hover {
|
||||
background-color: @warning-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&.highlight {
|
||||
&:hover {
|
||||
background-color: @warning-bg;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
|
||||
@@ -14,20 +14,20 @@
|
||||
&.n {
|
||||
margin-top: -6px;
|
||||
left: 50%;
|
||||
.transform(translate(-50%, -100%));
|
||||
.transform(translate3d(-50%, -100%, 0));
|
||||
}
|
||||
&.s {
|
||||
margin-top: 6px;
|
||||
left: 50%;
|
||||
.transform(translate(-50%, 0));
|
||||
.transform(translate3d(-50%, 0, 0));
|
||||
}
|
||||
&.e {
|
||||
margin-left: 6px;
|
||||
.transform(translate(0, -50%));
|
||||
.transform(translate3d(0, -50%, 0));
|
||||
}
|
||||
&.w {
|
||||
margin-left: -6px;
|
||||
.transform(translate(-100%, -50%));
|
||||
.transform(translate3d(-100%, -50%, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
height: 0;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
.transform(translate3d(0, 0, 0)); // Fix iOS Safari 8 Scroll bug
|
||||
|
||||
&.n {
|
||||
border-top: 6px solid @primary;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"id": "http://cdn.coriolis.io/schemas/ship-loadout/1-draft.json#",
|
||||
"id": "http://cdn.coriolis.io/schemas/ship-loadout/1.json#",
|
||||
"title": "Ship Loadout",
|
||||
"type": "object",
|
||||
"description": "The details for a specific ship build/loadout",
|
||||
"description": "The details for a specific ship build/loadout. DEPRECATED in favor of Version 3",
|
||||
"required": ["name", "ship", "components"],
|
||||
"properties": {
|
||||
"name": {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"id": "http://cdn.coriolis.io/schemas/ship-loadout/2.json#",
|
||||
"title": "Ship Loadout",
|
||||
"type": "object",
|
||||
"description": "The details for a specific ship build/loadout",
|
||||
"description": "The details for a specific ship build/loadout. DEPRECATED in favor of Version 3",
|
||||
"required": ["name", "ship", "components"],
|
||||
"properties": {
|
||||
"name": {
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
"armourAdded":{
|
||||
"description": "Armour added through Hull reinforcement",
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
"minimum": 0
|
||||
},
|
||||
"baseShieldStrength": {
|
||||
"type": "integer",
|
||||
@@ -225,7 +225,7 @@
|
||||
"boost": {
|
||||
"description": "Maximum boost speed of the ships (4 pips, straight-line)",
|
||||
"type": "number",
|
||||
"minimum": 1
|
||||
"minimum": 0
|
||||
},
|
||||
"cargoCapacity": {
|
||||
"type": "integer",
|
||||
|
||||
Reference in New Issue
Block a user