diff --git a/README.md b/README.md index 98802787..dc9bb4bb 100755 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## About -The Coriolis project was inspired by [E:D Shipyard](http://www.edshipyard.com/) and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development. +The Coriolis project was inspired by E:D Shipyard and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development. Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it. diff --git a/src/app/Coriolis.jsx b/src/app/Coriolis.jsx index 2e46fb6e..4292d0ea 100644 --- a/src/app/Coriolis.jsx +++ b/src/app/Coriolis.jsx @@ -68,7 +68,8 @@ export default class Coriolis extends React.Component { this.state = { noTouch: !('ontouchstart' in window || navigator.msMaxTouchPoints || navigator.maxTouchPoints), page: null, - announcements: [], + // Announcements must have an expiry date in format "YYYY-MM-DDTHH:MM:SSZ" + announcements: [{expiry: "2024-11-30T00:00:00Z", text: "Mandalay added"}, {expiry: "2024-12-06T00:00:00Z", text: "Concord Cannon added"}, {expiry: "2024-12-08T00:00:00Z", text: "Boost Interval Feature added"}], language: getLanguage(Persist.getLangCode()), route: {}, sizeRatio: Persist.getSizeRatio() diff --git a/src/app/components/AvailableModulesMenu.jsx b/src/app/components/AvailableModulesMenu.jsx index de4a6e17..87f188b6 100644 --- a/src/app/components/AvailableModulesMenu.jsx +++ b/src/app/components/AvailableModulesMenu.jsx @@ -39,13 +39,18 @@ const GRPCAT = { 'ml': 'lasers', 'c': 'projectiles', 'mc': 'projectiles', + 'advmc': 'projectiles', 'axmc': 'experimental', + 'axmce': 'experimental', + 'ntp': 'experimental', 'fc': 'projectiles', 'rfl': 'experimental', 'pa': 'projectiles', 'rg': 'projectiles', 'mr': 'ordnance', + 'amr': 'ordnance', 'axmr': 'experimental', + 'axmre': 'experimental', 'rcpl': 'experimental', 'dtl': 'experimental', 'tbsc': 'experimental', @@ -104,8 +109,8 @@ const CATEGORIES = { // Hardpoints 'lasers': ['pl', 'ul', 'bl'], - 'projectiles': ['mc', 'c', 'fc', 'pa', 'rg'], - 'ordnance': ['mr', 'tp', 'nl'], + 'projectiles': ['mc', 'advmc', 'c', 'fc', 'pa', 'rg'], + 'ordnance': ['mr', 'amr', 'tp', 'nl'], // Utilities 'sb': ['sb'], 'hs': ['hs'], @@ -113,7 +118,7 @@ const CATEGORIES = { 'defence': ['ch', 'po', 'ec'], 'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners // Experimental - 'experimental': ['axmc', 'axmr', 'rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',], + 'experimental': ['axmc', 'axmce', 'axmr', 'axmre', 'ntp','rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',], 'weapon stabilizers': ['ews'], // Guardian 'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc'], @@ -213,16 +218,30 @@ export default class AvailableModulesMenu extends TranslatedComponent { if (categories.length === 1) { // Show category header instead of group header if (m && grp == m.grp) { - list.push(
this.groupElem = elem} key={category} + // If this is a missing module/weapon, skip it + if (m.grp == "mh" || m.grp == "mm"){ + continue; + } else { + list.push(
this.groupElem = elem} key={category} className={'select-category upp'}>{translate(category)}
); + } } else { - list.push(
{translate(category)}
); + if (category == "mh" || category == "mm"){ + continue; + } else { + list.push(
{translate(category)}
); + } } } else { // Show category header as well as group header if (!categoryHeader) { - list.push(
{translate(category)}
); - categoryHeader = true; + if (category == "mh" || category == "mm"){ + continue; + } + else { + list.push(
{translate(category)}
); + categoryHeader = true; + } } if (m && grp == m.grp) { list.push(
this.groupElem = elem} key={grp} @@ -241,7 +260,11 @@ export default class AvailableModulesMenu extends TranslatedComponent { } else if (i.mount === 'T') { mount = 'Turreted'; } - const fuzz = { grp, m: i, name: `${i.class}${i.rating}${mount ? ' ' + mount : ''} ${translate(grp)}` }; + let special = ''; + if (typeof(i.special) !== 'undefined') { + special = `(${translate(i.special)})`; + } + const fuzz = { grp, m: i, name: `${i.class}${i.rating}${mount ? ' ' + mount : ''} ${translate(grp)} ${translate(special)}` }; fuzzy.push(fuzz); } } @@ -298,6 +321,11 @@ export default class AvailableModulesMenu extends TranslatedComponent { let itemsOnThisRow = 0; for (let i = 0; i < sortedModules.length; i++) { let m = sortedModules[i]; + // If m.grp is mh or mm, or m.symbol contains 'Missing' skip it + if (m.grp == 'mh' || m.grp == 'mm' || (typeof(m.symbol) !== 'undefined' && m.symbol.includes("Missing"))) { + // If this is a missing module, skip it + continue; + } let mount = null; let disabled = false; prevName = m.name; diff --git a/src/app/components/HardpointSlot.jsx b/src/app/components/HardpointSlot.jsx index 724d9fd5..e9edda43 100644 --- a/src/app/components/HardpointSlot.jsx +++ b/src/app/components/HardpointSlot.jsx @@ -136,6 +136,7 @@ export default class HardpointSlot extends Slot { {showModuleResistances && m.getThermalResistance() ?
{translate('thermres')}: {formats.pct(m.getThermalResistance())}
: null} {m.getIntegrity() ?
{translate('integrity')}: {formats.int(m.getIntegrity())}
: null} + {m.getInfo() ?
{translate(m.getInfo())}
: null} {m && validMods.length > 0 ?
this.modButton = modButton}>
: null }
; diff --git a/src/app/components/LineChart.jsx b/src/app/components/LineChart.jsx index b4113ee6..76078aa6 100644 --- a/src/app/components/LineChart.jsx +++ b/src/app/components/LineChart.jsx @@ -1,281 +1,281 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import ContainerDimensions from 'react-container-dimensions'; -import * as d3 from 'd3'; -import TranslatedComponent from './TranslatedComponent'; - -const MARGIN = { top: 15, right: 20, bottom: 35, left: 60 }; - -/** - * Line Chart - */ -export default class LineChart extends TranslatedComponent { - - static defaultProps = { - code: '', - xMin: 0, - yMin: 0, - points: 20, - colors: ['#ff8c0d'], - aspect: 0.5 - }; - - static propTypes = { - func: PropTypes.func.isRequired, - xLabel: PropTypes.string.isRequired, - xMin: PropTypes.number, - xMax: PropTypes.number.isRequired, - xUnit: PropTypes.string.isRequired, - xMark: PropTypes.number, - yLabel: PropTypes.string.isRequired, - yMin: PropTypes.number, - yMax: PropTypes.number.isRequired, - yUnit: PropTypes.string, - series: PropTypes.array, - colors: PropTypes.array, - points: PropTypes.number, - aspect: PropTypes.number, - code: PropTypes.string, - }; - - /** - * Constructor - * @param {Object} props React Component properties - * @param {Object} context React Component context - */ - constructor(props, context) { - super(props); - - this._updateDimensions = this._updateDimensions.bind(this); - this._updateSeries = this._updateSeries.bind(this); - this._tooltip = this._tooltip.bind(this); - this._showTip = this._showTip.bind(this); - this._hideTip = this._hideTip.bind(this); - this._moveTip = this._moveTip.bind(this); - - const series = props.series; - - let xScale = d3.scaleLinear(); - let yScale = d3.scaleLinear(); - let xAxisScale = d3.scaleLinear(); - - this.xAxis = d3.axisBottom(xAxisScale).tickSizeOuter(0); - this.yAxis = d3.axisLeft(yScale).ticks(6).tickSizeOuter(0); - - this.state = { - xScale, - xAxisScale, - yScale, - tipHeight: 2 + (1.2 * (series ? series.length : 0.8)), - }; - } - - /** - * Update tooltip content - * @param {number} xPos x coordinate - * @param {number} width current container width - */ - _tooltip(xPos, width) { - let { xLabel, yLabel, xUnit, yUnit, func, series } = this.props; - let { xScale, yScale } = this.state; - let { formats, translate } = this.context.language; - let x0 = xScale.invert(xPos), - y0 = func(x0), - tips = this.tipContainer, - yTotal = 0, - flip = (xPos / width > 0.50), - tipWidth = 0, - tipHeightPx = tips.selectAll('rect').node().getBoundingClientRect().height; - - - xPos = xScale(x0); // Clamp xPos - - tips.selectAll('text.text-tip.y').text(function(d, i) { - let yVal = series ? y0[series[i]] : y0; - yTotal += yVal; - return (series ? translate(series[i]) : '') + ' ' + formats.f2(yVal); - }).append('tspan').attr('class', 'metric').text(yUnit ? ' ' + yUnit : ''); - - tips.selectAll('text').each(function() { - if (this.getBBox().width > tipWidth) { - tipWidth = Math.ceil(this.getBBox().width); - } - }); - - let tipY = Math.floor(yScale(yTotal / (series ? series.length : 1)) - (tipHeightPx / 2)); - - tipWidth += 8; - tips.attr('transform', 'translate(' + xPos + ',' + tipY + ')'); - tips.selectAll('text.text-tip').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start'); - tips.selectAll('text.text-tip.x').text(formats.f2(x0)).append('tspan').attr('class', 'metric').text(' ' + xUnit); - tips.selectAll('rect').attr('width', tipWidth + 4).attr('x', flip ? -tipWidth - 12 : 8).attr('y', 0).style('text-anchor', flip ? 'end' : 'start'); - this.markersContainer.selectAll('circle').attr('cx', xPos).attr('cy', (d, i) => yScale(series ? y0[series[i]] : y0)); - } - - /** - * Update dimensions based on properties and scale - * @param {Object} props React Component properties - * @param {number} scale size ratio / scale - * @param {number} width current width of the container - * @returns {Object} calculated dimensions - */ - _updateDimensions(props, scale, width) { - const { xMax, xMin, yMin, yMax } = props; - const innerWidth = width - MARGIN.left - MARGIN.right; - const outerHeight = Math.round(width * props.aspect); - const innerHeight = outerHeight - MARGIN.top - MARGIN.bottom; - - this.state.xScale.range([0, innerWidth]).domain([xMin, xMax || 1]).clamp(true); - this.state.xAxisScale.range([0, innerWidth]).domain([xMin, xMax]).clamp(true); - this.state.yScale.range([innerHeight, 0]).domain([yMin, yMax + (yMax - yMin) * 0.1]); // 10% higher than maximum value for tooltip visibility - return { innerWidth, outerHeight, innerHeight }; - } - - /** - * Show tooltip - * @param {SyntheticEvent} e Event - */ - _showTip(e) { - e.preventDefault(); - this.tipContainer.style('display', null); - this.markersContainer.style('display', null); - this._moveTip(e); - } - - /** - * Move and update tooltip - * @param {SyntheticEvent} e Event - * @param {number} width current container width - */ - _moveTip(e, width) { - let clientX = e.touches ? e.touches[0].clientX : e.clientX; - this._tooltip(Math.round(clientX - e.currentTarget.getBoundingClientRect().left), width); - } - - /** - * Hide tooltip - * @param {SyntheticEvent} e Event - */ - _hideTip(e) { - e.preventDefault(); - this.tipContainer.style('display', 'none'); - this.markersContainer.style('display', 'none'); - } - - /** - * Update series generated from props - * @param {Object} props React Component properties - * @param {Object} state React Component state - */ - _updateSeries(props, state) { - let { func, xMin, xMax, series, points } = props; - let delta = (xMax - xMin) / points; - let seriesData = new Array(points); - - if (delta) { - seriesData = new Array(points); - for (let i = 0, x = xMin; i < points; i++) { - seriesData[i] = [x, func(x)]; - x += delta; - } - seriesData[points - 1] = [xMax, func(xMax)]; - } else { - let yVal = func(xMin); - seriesData = [[0, yVal], [1, yVal]]; - } - - const markerElems = []; - const detailElems = []; - const seriesLines = []; - for (let i = 0, l = series ? series.length : 1; i < l; i++) { - const yAccessor = series ? function(d) { return state.yScale(d[1][this]); }.bind(series[i]) : (d) => state.yScale(d[1]); - seriesLines.push(d3.line().x((d, i) => this.state.xScale(d[0])).y(yAccessor)); - detailElems.push(); - markerElems.push(); - } - - const tipHeight = 2 + (1.2 * (seriesLines ? seriesLines.length : 0.8)); - - this.setState({ markerElems, detailElems, seriesLines, seriesData, tipHeight }); - } - - /** - * Update dimensions and series data based on props and context. - */ - componentWillMount() { - this._updateSeries(this.props, this.state); - } - - /** - * Update state based on property and context changes - * @param {Object} nextProps Incoming/Next properties - * @param {Object} nextContext Incoming/Next conext - */ - componentWillReceiveProps(nextProps, nextContext) { - const props = this.props; - - if (props.code != nextProps.code) { - this._updateSeries(nextProps, this.state); - } - } - - /** - * Render the chart - * @return {React.Component} Chart SVG - */ - render() { - return ( - - { ({ width, height }) => { - const { innerWidth, outerHeight, innerHeight } = this._updateDimensions(this.props, this.context.sizeRatio, width, height); - const { xMin, xMax, xLabel, yLabel, xUnit, yUnit, xMark, colors } = this.props; - const { tipHeight, detailElems, markerElems, seriesData, seriesLines } = this.state; - const lines = seriesLines.map((line, i) => ).reverse(); - - const markX = xMark ? innerWidth * (xMark - xMin) / (xMax - xMin) : 0; - const xmark = xMark ? : ''; - return ( -
- - - {xmark} - {lines} - d3.select(elem).call(this.xAxis)} transform={`translate(0,${innerHeight})`}> - - {xLabel} - ({xUnit}) - - - d3.select(elem).call(this.yAxis)}> - - {yLabel} - { yUnit && ({yUnit}) } - - - this.tipContainer = d3.select(g)} style={{ display: 'none' }}> - - {detailElems} - - this.markersContainer = d3.select(g)} style={{ display: 'none' }}> - {markerElems} - - this._moveTip(e, width)} - onTouchMove={e => this._moveTip(e, width)} - /> - - -
- ); - }} -
- ); - } -} +import React from 'react'; +import PropTypes from 'prop-types'; +import ContainerDimensions from 'react-container-dimensions'; +import * as d3 from 'd3'; +import TranslatedComponent from './TranslatedComponent'; + +const MARGIN = { top: 15, right: 20, bottom: 35, left: 60 }; + +/** + * Line Chart + */ +export default class LineChart extends TranslatedComponent { + + static defaultProps = { + code: '', + xMin: 0, + yMin: 0, + points: 20, + colors: ['#ff8c0d'], + aspect: 0.5 + }; + + static propTypes = { + func: PropTypes.func.isRequired, + xLabel: PropTypes.string.isRequired, + xMin: PropTypes.number, + xMax: PropTypes.number.isRequired, + xUnit: PropTypes.string.isRequired, + xMark: PropTypes.number, + yLabel: PropTypes.string.isRequired, + yMin: PropTypes.number, + yMax: PropTypes.number.isRequired, + yUnit: PropTypes.string, + series: PropTypes.array, + colors: PropTypes.array, + points: PropTypes.number, + aspect: PropTypes.number, + code: PropTypes.string, + }; + + /** + * Constructor + * @param {Object} props React Component properties + * @param {Object} context React Component context + */ + constructor(props, context) { + super(props); + + this._updateDimensions = this._updateDimensions.bind(this); + this._updateSeries = this._updateSeries.bind(this); + this._tooltip = this._tooltip.bind(this); + this._showTip = this._showTip.bind(this); + this._hideTip = this._hideTip.bind(this); + this._moveTip = this._moveTip.bind(this); + + const series = props.series; + + let xScale = d3.scaleLinear(); + let yScale = d3.scaleLinear(); + let xAxisScale = d3.scaleLinear(); + + this.xAxis = d3.axisBottom(xAxisScale).tickSizeOuter(0); + this.yAxis = d3.axisLeft(yScale).ticks(6).tickSizeOuter(0); + + this.state = { + xScale, + xAxisScale, + yScale, + tipHeight: 2 + (1.2 * (series ? series.length : 0.8)), + }; + } + + /** + * Update tooltip content + * @param {number} xPos x coordinate + * @param {number} width current container width + */ + _tooltip(xPos, width) { + let { xLabel, yLabel, xUnit, yUnit, func, series } = this.props; + let { xScale, yScale } = this.state; + let { formats, translate } = this.context.language; + let x0 = xScale.invert(xPos), + y0 = func(x0), + tips = this.tipContainer, + yTotal = 0, + flip = (xPos / width > 0.50), + tipWidth = 0, + tipHeightPx = tips.selectAll('rect').node().getBoundingClientRect().height; + + + xPos = xScale(x0); // Clamp xPos + + tips.selectAll('text.text-tip.y').text(function(d, i) { + let yVal = series ? y0[series[i]] : y0; + yTotal += yVal; + return (series ? translate(series[i]) : '') + ' ' + formats.f2(yVal); + }).append('tspan').attr('class', 'metric').text(yUnit ? ' ' + yUnit : ''); + + tips.selectAll('text').each(function() { + if (this.getBBox().width > tipWidth) { + tipWidth = Math.ceil(this.getBBox().width); + } + }); + + let tipY = Math.floor(yScale(yTotal / (series ? series.length : 1)) - (tipHeightPx / 2)); + + tipWidth += 8; + tips.attr('transform', 'translate(' + xPos + ',' + tipY + ')'); + tips.selectAll('text.text-tip').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start'); + tips.selectAll('text.text-tip.x').text(formats.f2(x0)).append('tspan').attr('class', 'metric').text(' ' + xUnit); + tips.selectAll('rect').attr('width', tipWidth + 4).attr('x', flip ? -tipWidth - 12 : 8).attr('y', 0).style('text-anchor', flip ? 'end' : 'start'); + this.markersContainer.selectAll('circle').attr('cx', xPos).attr('cy', (d, i) => yScale(series ? y0[series[i]] : y0)); + } + + /** + * Update dimensions based on properties and scale + * @param {Object} props React Component properties + * @param {number} scale size ratio / scale + * @param {number} width current width of the container + * @returns {Object} calculated dimensions + */ + _updateDimensions(props, scale, width) { + const { xMax, xMin, yMin, yMax } = props; + const innerWidth = width - MARGIN.left - MARGIN.right; + const outerHeight = Math.round(width * props.aspect); + const innerHeight = outerHeight - MARGIN.top - MARGIN.bottom; + + this.state.xScale.range([0, innerWidth]).domain([xMin, xMax || 1]).clamp(true); + this.state.xAxisScale.range([0, innerWidth]).domain([xMin, xMax]).clamp(true); + this.state.yScale.range([innerHeight, 0]).domain([yMin, yMax + (yMax - yMin) * 0.1]); // 10% higher than maximum value for tooltip visibility + return { innerWidth, outerHeight, innerHeight }; + } + + /** + * Show tooltip + * @param {SyntheticEvent} e Event + */ + _showTip(e) { + e.preventDefault(); + this.tipContainer.style('display', null); + this.markersContainer.style('display', null); + this._moveTip(e); + } + + /** + * Move and update tooltip + * @param {SyntheticEvent} e Event + * @param {number} width current container width + */ + _moveTip(e, width) { + let clientX = e.touches ? e.touches[0].clientX : e.clientX; + this._tooltip(Math.round(clientX - e.currentTarget.getBoundingClientRect().left), width); + } + + /** + * Hide tooltip + * @param {SyntheticEvent} e Event + */ + _hideTip(e) { + e.preventDefault(); + this.tipContainer.style('display', 'none'); + this.markersContainer.style('display', 'none'); + } + + /** + * Update series generated from props + * @param {Object} props React Component properties + * @param {Object} state React Component state + */ + _updateSeries(props, state) { + let { func, xMin, xMax, series, points } = props; + let delta = (xMax - xMin) / points; + let seriesData = new Array(points); + + if (delta) { + seriesData = new Array(points); + for (let i = 0, x = xMin; i < points; i++) { + seriesData[i] = [x, func(x)]; + x += delta; + } + seriesData[points - 1] = [xMax, func(xMax)]; + } else { + let yVal = func(xMin); + seriesData = [[0, yVal], [1, yVal]]; + } + + const markerElems = []; + const detailElems = []; + const seriesLines = []; + for (let i = 0, l = series ? series.length : 1; i < l; i++) { + const yAccessor = series ? function(d) { return state.yScale(d[1][this]); }.bind(series[i]) : (d) => state.yScale(d[1]); + seriesLines.push(d3.line().x((d, i) => this.state.xScale(d[0])).y(yAccessor)); + detailElems.push(); + markerElems.push(); + } + + const tipHeight = 2 + (1.2 * (seriesLines ? seriesLines.length : 0.8)); + + this.setState({ markerElems, detailElems, seriesLines, seriesData, tipHeight }); + } + + /** + * Update dimensions and series data based on props and context. + */ + componentWillMount() { + this._updateSeries(this.props, this.state); + } + + /** + * Update state based on property and context changes + * @param {Object} nextProps Incoming/Next properties + * @param {Object} nextContext Incoming/Next conext + */ + componentWillReceiveProps(nextProps, nextContext) { + const props = this.props; + + if (props.code != nextProps.code) { + this._updateSeries(nextProps, this.state); + } + } + + /** + * Render the chart + * @return {React.Component} Chart SVG + */ + render() { + return ( + + { ({ width, height }) => { + const { innerWidth, outerHeight, innerHeight } = this._updateDimensions(this.props, this.context.sizeRatio, width, height); + const { xMin, xMax, xLabel, yLabel, xUnit, yUnit, xMark, colors } = this.props; + const { tipHeight, detailElems, markerElems, seriesData, seriesLines } = this.state; + const lines = seriesLines.map((line, i) => ).reverse(); + + const markX = xMark ? innerWidth * (xMark - xMin) / (xMax - xMin) : 0; + const xmark = xMark ? : ''; + return ( +
+ + + {xmark} + {lines} + d3.select(elem).call(this.xAxis)} transform={`translate(0,${innerHeight})`}> + + {xLabel} + ({xUnit}) + + + d3.select(elem).call(this.yAxis)}> + + {yLabel} + { yUnit && ({yUnit}) } + + + this.tipContainer = d3.select(g)} style={{ display: 'none' }}> + + {detailElems} + + this.markersContainer = d3.select(g)} style={{ display: 'none' }}> + {markerElems} + + this._moveTip(e, width)} + onTouchMove={e => this._moveTip(e, width)} + /> + + +
+ ); + }} +
+ ); + } +} diff --git a/src/app/components/ModalPermalink.jsx b/src/app/components/ModalPermalink.jsx index 96d611e6..975e97bc 100644 --- a/src/app/components/ModalPermalink.jsx +++ b/src/app/components/ModalPermalink.jsx @@ -34,6 +34,18 @@ export default class ModalPermalink extends TranslatedComponent { ); } + /** + * Copy the shortened URL to the clipboard + * @param {Event} e Click event + * @return {void} + */ + copyShortLink() { + let copyText = document.getElementById("shortenedUrl"); + // Copy the text inside the shortendUrl input to the clipboard + copyText.select(); + document.execCommand("copy"); + } + /** * Render the modal * @return {React.Component} Modal Content @@ -42,15 +54,17 @@ export default class ModalPermalink extends TranslatedComponent { let translate = this.context.language.translate; return
e.stopPropagation() }> -

{translate('permalink')}

+

{translate('permalink')}


{translate('URL')}

e.target.select() }/>

{translate('shortened')}

- e.target.select() }/> + e.target.select() }/>

-

s.orbis.zone is the new URL shortener domain, old eddp.co urls are considered end of life and could go down at any moment. Sorry for any inconvenience.

+
+

s.orbis.zone is the URL shortener domain. These links should persist indefinitely going forward. If for some reason there is a problem with the link shortening process, please report it in the EDCD Discord Server.

+
; } diff --git a/src/app/components/ModalShoppingList.jsx b/src/app/components/ModalShoppingList.jsx index cd2e2ec3..5b96b29b 100644 --- a/src/app/components/ModalShoppingList.jsx +++ b/src/app/components/ModalShoppingList.jsx @@ -12,7 +12,8 @@ const base64url = require('base64url'); export default class ModalShoppingList extends TranslatedComponent { static propTypes = { - ship: PropTypes.object.isRequired + ship: PropTypes.object.isRequired, + buildName: PropTypes.string }; /** @@ -90,8 +91,10 @@ export default class ModalShoppingList extends TranslatedComponent { request .get('http://localhost:44405/commanders') .end((err, res) => { + this.display = 'block'; if (err) { console.log(err); + this.display = 'none'; return this.setState({ failed: true }); } const cmdrs = JSON.parse(res.text); @@ -147,6 +150,34 @@ export default class ModalShoppingList extends TranslatedComponent { } } + /** + * Fix issues with the item name for bulkheads when sending to EDOMH + * @param {*} ship Ship object + * @param {*} item Item name + * @returns updated item name + */ + fixArmourItemNameForEDOMH(ship, item) { + // The module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object + switch (ship.bulkheads.m.name){ + case "Lightweight Alloy": + item = ship.id + "_Armour_Grade1"; + break; + case "Reinforced Alloy": + item = ship.id + "_Armour_Grade2"; + break; + case "Military Grade Composite": + item = ship.id + "_Armour_Grade3"; + break; + case "Mirrored Surface Composite": + item = ship.id + "_Armour_Mirrored"; + break; + case "Reactive Surface Composite": + item = ship.id + "_Armour_Reactive"; + break; + } + return item; + } + /** * Send all blueprints to EDOMH. This is a modified copy of registerBPs because this.state.blueprints was empty when I tried to modify sendToEDEng and I couldn't figure out why * @param {Event} event React event @@ -154,6 +185,7 @@ export default class ModalShoppingList extends TranslatedComponent { sendToEDOMH(event) { event.preventDefault(); const ship = this.props.ship; + const buildName = this.props.buildName; let blueprints = []; //create the json @@ -166,20 +198,38 @@ export default class ModalShoppingList extends TranslatedComponent { continue; } if (module.m.blueprint.special) { + let item = ""; + // If the module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object + if (module.m.blueprint.fdname.includes("Armour_")) { + item = this.fixArmourItemNameForEDOMH(ship, item) + } + else { + item = module.m.symbol; + } + blueprints.push({ - "item": module.m.symbol, + "item": item, "blueprint": module.m.blueprint.special.edname }); } - for (const g in module.m.blueprint.grades) { + for (let g in module.m.blueprint.grades) { if (!module.m.blueprint.grades.hasOwnProperty(g)) { continue; } - if (g < module.m.blueprint.grade) { + // We only want the grade that the module is currently at, not every grade up to that point + if (Number(g) !== module.m.blueprint.grade) { continue; } + let item = ""; + // If the module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object + if (module.m.blueprint.fdname.includes("Armour_")) { + item = this.fixArmourItemNameForEDOMH(ship, item) + } + else { + item = module.m.symbol; + } blueprints.push({ - "item": module.m.symbol, + "item": item, "blueprint": module.m.blueprint.fdname, "grade": module.m.blueprint.grade, "highestGradePercentage":1.0 @@ -188,16 +238,18 @@ export default class ModalShoppingList extends TranslatedComponent { } } + let shipName = buildName + " - " + ship.name; + //create JSON to encode let baseJson = { "version":1, - "name":ship.name, // TO-DO: Import build name and put that here correctly + "name": shipName, // TO-DO: Import build name and put that here correctly "items": blueprints - } - + } + let JSONString = JSON.stringify(baseJson) let deflated = zlib.deflateSync(JSONString) - + //actually encode let link = base64url.encode(deflated) link = "edomh://coriolis/?" + link; @@ -219,14 +271,15 @@ export default class ModalShoppingList extends TranslatedComponent { if (!module.m.blueprint.grade || !module.m.blueprint.grades) { continue; } - for (const g in module.m.blueprint.grades) { + for (let g in module.m.blueprint.grades) { if (!module.m.blueprint.grades.hasOwnProperty(g)) { continue; } - if (g > module.m.blueprint.grade) { + // Ignore grades higher than the grade selected + if (Number(g) > module.m.blueprint.grade) { continue; } - for (const i in module.m.blueprint.grades[g].components) { + for (let i in module.m.blueprint.grades[g].components) { if (!module.m.blueprint.grades[g].components.hasOwnProperty(i)) { continue; } @@ -236,16 +289,16 @@ export default class ModalShoppingList extends TranslatedComponent { mats[i] = module.m.blueprint.grades[g].components[i] * this.state.matsPerGrade[g]; } } - if (module.m.blueprint.special) { - for (const j in module.m.blueprint.special.components) { - if (!module.m.blueprint.special.components.hasOwnProperty(j)) { - continue; - } - if (mats[j]) { - mats[j] += module.m.blueprint.special.components[j]; - } else { - mats[j] = module.m.blueprint.special.components[j]; - } + } + if (module.m.blueprint.special) { + for (const j in module.m.blueprint.special.components) { + if (!module.m.blueprint.special.components.hasOwnProperty(j)) { + continue; + } + if (mats[j]) { + mats[j] += module.m.blueprint.special.components[j]; + } else { + mats[j] = module.m.blueprint.special.components[j]; } } } @@ -302,34 +355,46 @@ export default class ModalShoppingList extends TranslatedComponent { this.sendToEDEng = this.sendToEDEng.bind(this); this.sendToEDOMH = this.sendToEDOMH.bind(this); return
e.stopPropagation() }> -

{translate('PHRASE_SHOPPING_MATS')}

- - -
- - -
- - -
- - -
- - +

{translate('PHRASE_SHOPPING_MATS')}

-