From 1307474755f876f99240f877767b09bb6f1188dc Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Thu, 23 Aug 2018 18:08:50 +0200 Subject: [PATCH 1/5] Added tooltips to offence table summary --- src/app/components/Offence.jsx | 144 ++++++++++++++++++++------------- 1 file changed, 89 insertions(+), 55 deletions(-) diff --git a/src/app/components/Offence.jsx b/src/app/components/Offence.jsx index 737303d0..68d8186c 100644 --- a/src/app/components/Offence.jsx +++ b/src/app/components/Offence.jsx @@ -42,6 +42,63 @@ export function weaponComparator(translate, propComparator, desc) { }; } +/** + * Creates a tooltip that shows damage by type. + * @param {function} translate Translation function + * @param {Object} formats Object that holds format functions + * @param {Object} sdpsObject Object that holds sdps split up by type + * @returns {Array} Tooltip + */ +function getSDpsTooltip(translate, formats, sdpsObject) { + return Object.keys(sdpsObject).filter(key => sdpsObject[key]) + .map(key => { + return ( +
+ {translate(key) + ' ' + formats.f1(sdpsObject[key])} +
+ ); + }); +} + +/** + * Returns a data object used by {@link PieChart} that shows damage by type. + * @param {function} translate Translation function + * @param {Object} sdpsObject Object that holds sdps split up by type + * @returns {Object} Data object + */ +function getSDpsData(translate, sdpsObject) { + return Object.keys(sdpsObject).map(key => { + return { + value: Math.round(sdpsObject[key]), + label: translate(key) + }; + }); +} + +/** + * Adds all damage of `add` onto `addOn`. + * @param {Object} addOn Object that holds sdps split up by type (will be mutated) + * @param {Object} add Object that holds sdps split up by type + */ +function addSDps(addOn, add) { + Object.keys(addOn).map(k => addOn[k] += (add[k] ? add[k] : 0)); +} + +/** + * Calculates the overall sdps of an sdps object. + * @param {Object} sdpsObject Object that holds sdps spluit up by type + */ +function sumSDps(sdpsObject) { + if (sdpsObject.total) { + return sdpsObject.total; + } + + return Object.keys(sdpsObject).reduce( + (acc, k) => acc + (sdpsObject[k] ? sdpsObject[k] : 0), + 0 + ); +} + /** * Offence information * Offence information consists of four panels: @@ -144,59 +201,36 @@ export default class Offence extends TranslatedComponent { const timeToDrain = Calc.timeToDrainWep(ship, wep); - let absoluteShieldsSDps = 0; - let explosiveShieldsSDps = 0; - let kineticShieldsSDps = 0; - let thermalShieldsSDps = 0; - let absoluteArmourSDps = 0; - let explosiveArmourSDps = 0; - let kineticArmourSDps = 0; - let thermalArmourSDps = 0; let totalSEps = 0; - let totalSDps = 0; + let totalSDpsObject = {'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0}; + let shieldsSDpsObject = {'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0}; + let armourSDpsObject = {'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0}; const rows = []; for (let i = 0; i < damage.length; i++) { const weapon = damage[i]; - totalSDps += weapon.sdps.base.total; totalSEps += weapon.seps; - absoluteShieldsSDps += weapon.sdps.shields.absolute; - explosiveShieldsSDps += weapon.sdps.shields.explosive; - kineticShieldsSDps += weapon.sdps.shields.kinetic; - thermalShieldsSDps += weapon.sdps.shields.thermal; - absoluteArmourSDps += weapon.sdps.armour.absolute; - explosiveArmourSDps += weapon.sdps.armour.explosive; - kineticArmourSDps += weapon.sdps.armour.kinetic; - thermalArmourSDps += weapon.sdps.armour.thermal; + addSDps(totalSDpsObject, weapon.sdps.base); + addSDps(shieldsSDpsObject, weapon.sdps.shields); + addSDps(armourSDpsObject, weapon.sdps.armour); + + const baseSDpsTooltipDetails = getSDpsTooltip(translate, formats, weapon.sdps.base); const effectivenessShieldsTooltipDetails = []; effectivenessShieldsTooltipDetails.push(
{translate('range') + ' ' + formats.pct1(weapon.effectiveness.shields.range)}
); effectivenessShieldsTooltipDetails.push(
{translate('resistance') + ' ' + formats.pct1(weapon.effectiveness.shields.resistance)}
); effectivenessShieldsTooltipDetails.push(
{translate('power distributor') + ' ' + formats.pct1(weapon.effectiveness.shields.sys)}
); - const baseSDpsTooltipDetails = []; - if (weapon.sdps.shields.absolute) baseSDpsTooltipDetails.push(
{translate('absolute') + ' ' + formats.f1(weapon.sdps.base.absolute)}
); - if (weapon.sdps.shields.explosive) baseSDpsTooltipDetails.push(
{translate('explosive') + ' ' + formats.f1(weapon.sdps.base.explosive)}
); - if (weapon.sdps.shields.kinetic) baseSDpsTooltipDetails.push(
{translate('kinetic') + ' ' + formats.f1(weapon.sdps.base.kinetic)}
); - if (weapon.sdps.shields.thermal) baseSDpsTooltipDetails.push(
{translate('thermal') + ' ' + formats.f1(weapon.sdps.base.thermal)}
); - - const effectiveShieldsSDpsTooltipDetails = []; - if (weapon.sdps.shields.absolute) effectiveShieldsSDpsTooltipDetails.push(
{translate('absolute') + ' ' + formats.f1(weapon.sdps.shields.absolute)}
); - if (weapon.sdps.shields.explosive) effectiveShieldsSDpsTooltipDetails.push(
{translate('explosive') + ' ' + formats.f1(weapon.sdps.shields.explosive)}
); - if (weapon.sdps.shields.kinetic) effectiveShieldsSDpsTooltipDetails.push(
{translate('kinetic') + ' ' + formats.f1(weapon.sdps.shields.kinetic)}
); - if (weapon.sdps.shields.thermal) effectiveShieldsSDpsTooltipDetails.push(
{translate('thermal') + ' ' + formats.f1(weapon.sdps.shields.thermal)}
); + const effectiveShieldsSDpsTooltipDetails = getSDpsTooltip(translate, formats, weapon.sdps.armour); const effectivenessArmourTooltipDetails = []; effectivenessArmourTooltipDetails.push(
{translate('range') + ' ' + formats.pct1(weapon.effectiveness.armour.range)}
); effectivenessArmourTooltipDetails.push(
{translate('resistance') + ' ' + formats.pct1(weapon.effectiveness.armour.resistance)}
); effectivenessArmourTooltipDetails.push(
{translate('hardness') + ' ' + formats.pct1(weapon.effectiveness.armour.hardness)}
); - const effectiveArmourSDpsTooltipDetails = []; - if (weapon.sdps.armour.absolute) effectiveArmourSDpsTooltipDetails.push(
{translate('absolute') + ' ' + formats.f1(weapon.sdps.armour.absolute)}
); - if (weapon.sdps.armour.explosive) effectiveArmourSDpsTooltipDetails.push(
{translate('explosive') + ' ' + formats.f1(weapon.sdps.armour.explosive)}
); - if (weapon.sdps.armour.kinetic) effectiveArmourSDpsTooltipDetails.push(
{translate('kinetic') + ' ' + formats.f1(weapon.sdps.armour.kinetic)}
); - if (weapon.sdps.armour.thermal) effectiveArmourSDpsTooltipDetails.push(
{translate('thermal') + ' ' + formats.f1(weapon.sdps.armour.thermal)}
); + + const effectiveArmourSDpsTooltipDetails = getSDpsTooltip(translate, formats, weapon.sdps.armour); rows.push( @@ -215,20 +249,16 @@ export default class Offence extends TranslatedComponent { ); } - const totalShieldsSDps = absoluteShieldsSDps + explosiveShieldsSDps + kineticShieldsSDps + thermalShieldsSDps; - const totalArmourSDps = absoluteArmourSDps + explosiveArmourSDps + kineticArmourSDps + thermalArmourSDps; + const totalSDps = sumSDps(totalSDpsObject); + const totalSDpsTooltipDetails = getSDpsTooltip(translate, formats, totalSDpsObject); - const shieldsSDpsData = []; - shieldsSDpsData.push({ value: Math.round(absoluteShieldsSDps), label: translate('absolute') }); - shieldsSDpsData.push({ value: Math.round(explosiveShieldsSDps), label: translate('explosive') }); - shieldsSDpsData.push({ value: Math.round(kineticShieldsSDps), label: translate('kinetic') }); - shieldsSDpsData.push({ value: Math.round(thermalShieldsSDps), label: translate('thermal') }); + const totalShieldsSDps = sumSDps(shieldsSDpsObject); + const totalShieldsSDpsTooltipDetails = getSDpsTooltip(translate, formats, shieldsSDpsObject); + const shieldsSDpsData = getSDpsData(translate, shieldsSDpsObject); - const armourSDpsData = []; - armourSDpsData.push({ value: Math.round(absoluteArmourSDps), label: translate('absolute') }); - armourSDpsData.push({ value: Math.round(explosiveArmourSDps), label: translate('explosive') }); - armourSDpsData.push({ value: Math.round(kineticArmourSDps), label: translate('kinetic') }); - armourSDpsData.push({ value: Math.round(thermalArmourSDps), label: translate('thermal') }); + const totalArmourSDps = sumSDps(armourSDpsObject); + const totalArmourSDpsTooltipDetails = getSDpsTooltip(translate, formats, armourSDpsObject); + const armourSDpsData = getSDpsData(translate, armourSDpsObject); const timeToDepleteShields = Calc.timeToDeplete(opponentShields.total, totalShieldsSDps, totalSEps, pd.getWeaponsCapacity(), pd.getWeaponsRechargeRate() * (wep / 4)); const timeToDepleteArmour = Calc.timeToDeplete(opponentArmour.total, totalArmourSDps, totalSEps, pd.getWeaponsCapacity(), pd.getWeaponsRechargeRate() * (wep / 4)); @@ -252,15 +282,19 @@ export default class Offence extends TranslatedComponent { {'eft'} - - {rows} - - ={formats.f1(totalSDps)} - ={formats.f1(totalShieldsSDps)} - - ={formats.f1(totalArmourSDps)} - - + + {rows} + {rows.length > 0 && + + + ={formats.f1(totalSDps)} + ={formats.f1(totalShieldsSDps)} + + ={formats.f1(totalArmourSDps)} + + + } +
From da097e0955c2c79b16e3b9bd6aaec8f6015270e2 Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Thu, 23 Aug 2018 18:09:18 +0200 Subject: [PATCH 2/5] Added piechart for overall damage in offence tab --- src/app/components/Offence.jsx | 5 +++++ src/app/i18n/en.json | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/app/components/Offence.jsx b/src/app/components/Offence.jsx index 68d8186c..8f7abb36 100644 --- a/src/app/components/Offence.jsx +++ b/src/app/components/Offence.jsx @@ -251,6 +251,7 @@ export default class Offence extends TranslatedComponent { const totalSDps = sumSDps(totalSDpsObject); const totalSDpsTooltipDetails = getSDpsTooltip(translate, formats, totalSDpsObject); + const totalSDpsData = getSDpsData(translate, totalSDpsObject); const totalShieldsSDps = sumSDps(shieldsSDpsObject); const totalShieldsSDpsTooltipDetails = getSDpsTooltip(translate, formats, shieldsSDpsObject); @@ -305,6 +306,10 @@ export default class Offence extends TranslatedComponent {

{translate('PHRASE_EFFECTIVE_SDPS_ARMOUR')}
{formats.f1(totalArmourSDps)}

{translate('PHRASE_TIME_TO_REMOVE_ARMOUR')}
{timeToDepleteArmour === Infinity ? translate('never') : formats.time(timeToDepleteArmour)}

+
+

{translate('overall damage')}

+ +

{translate('shield damage sources')}

diff --git a/src/app/i18n/en.json b/src/app/i18n/en.json index 99624a88..cb436226 100644 --- a/src/app/i18n/en.json +++ b/src/app/i18n/en.json @@ -39,6 +39,7 @@ "PHRASE_TIME_TO_LOSE_ARMOUR": "Armour will hold for", "PHRASE_MODULE_PROTECTION_EXTERNAL": "Protection for hardpoints", "PHRASE_MODULE_PROTECTION_INTERNAL": "Protection for all other modules", + "PHRASE_OVERALL_DAMAGE": "Breakdown of sources for sustained DPS", "PHRASE_SHIELD_DAMAGE": "Breakdown of sources for sustained DPS against shields", "PHRASE_ARMOUR_DAMAGE": "Breakdown of sources for sustained DPS against armour", "PHRASE_TIME_TO_REMOVE_SHIELDS": "Will remove shields in", @@ -297,6 +298,7 @@ "opponent": "opponent", "opponent's shields": "opponent's shields", "opponent's armour": "opponent's armour", + "overall damage": "overall damage", "shield damage sources": "shield damage sources", "armour damage sources": "armour damage sources", "never": "never", From 1bbea7dda0c96e65580474defe581885d59aa9a2 Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Thu, 23 Aug 2018 18:21:00 +0200 Subject: [PATCH 3/5] Improved docs --- src/app/components/Offence.jsx | 22 +++++++++++----------- src/app/shipyard/Calculations.js | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/app/components/Offence.jsx b/src/app/components/Offence.jsx index 8f7abb36..83450bdf 100644 --- a/src/app/components/Offence.jsx +++ b/src/app/components/Offence.jsx @@ -44,9 +44,9 @@ export function weaponComparator(translate, propComparator, desc) { /** * Creates a tooltip that shows damage by type. - * @param {function} translate Translation function - * @param {Object} formats Object that holds format functions - * @param {Object} sdpsObject Object that holds sdps split up by type + * @param {function} translate Translation function + * @param {Object} formats Object that holds format functions + * @param {Calc.SDps} sdpsObject Object that holds sdps split up by type * @returns {Array} Tooltip */ function getSDpsTooltip(translate, formats, sdpsObject) { @@ -62,9 +62,9 @@ function getSDpsTooltip(translate, formats, sdpsObject) { /** * Returns a data object used by {@link PieChart} that shows damage by type. - * @param {function} translate Translation function - * @param {Object} sdpsObject Object that holds sdps split up by type - * @returns {Object} Data object + * @param {function} translate Translation function + * @param {Calc.SDps} sdpsObject Object that holds sdps split up by type + * @returns {Object} Data object */ function getSDpsData(translate, sdpsObject) { return Object.keys(sdpsObject).map(key => { @@ -77,8 +77,8 @@ function getSDpsData(translate, sdpsObject) { /** * Adds all damage of `add` onto `addOn`. - * @param {Object} addOn Object that holds sdps split up by type (will be mutated) - * @param {Object} add Object that holds sdps split up by type + * @param {Calc.SDps} addOn Object that holds sdps split up by type (will be mutated) + * @param {Calc.SDps} add Object that holds sdps split up by type */ function addSDps(addOn, add) { Object.keys(addOn).map(k => addOn[k] += (add[k] ? add[k] : 0)); @@ -86,7 +86,7 @@ function addSDps(addOn, add) { /** * Calculates the overall sdps of an sdps object. - * @param {Object} sdpsObject Object that holds sdps spluit up by type + * @param {Calc.SDps} sdpsObject Object that holds sdps spluit up by type */ function sumSDps(sdpsObject) { if (sdpsObject.total) { @@ -127,7 +127,7 @@ export default class Offence extends TranslatedComponent { this._sort = this._sort.bind(this); const damage = Calc.offenceMetrics(props.ship, props.opponent, props.wep, props.opponentSys, props.engagementrange); - this.state = { + this.state = { predicate: 'n', desc: true, damage @@ -247,7 +247,7 @@ export default class Offence extends TranslatedComponent { {formats.f1(weapon.sdps.armour.total)} {formats.pct1(weapon.effectiveness.armour.total)} ); - } + } const totalSDps = sumSDps(totalSDpsObject); const totalSDpsTooltipDetails = getSDpsTooltip(translate, formats, totalSDpsObject); diff --git a/src/app/shipyard/Calculations.js b/src/app/shipyard/Calculations.js index 7fb348dd..d0cd0e2a 100644 --- a/src/app/shipyard/Calculations.js +++ b/src/app/shipyard/Calculations.js @@ -824,14 +824,42 @@ export function _sustainedDps(ship, opponent, opponentShields, opponentArmour, e return { shieldsdps, armoursdps, eps }; } +/** + * Stores SDPS split up by type. + * @typedef {Object} SDps + * @property {number} absolute Damage of type absolute + * @property {number} explosive Damage of type explosive + * @property {number} kinetic Damage of type kinetic + * @property {number} thermal Damage of type thermal + * @property {number} [total] Sum of all damage types + */ + +/** + * An object that holds information about SDPS for a given weapon and opponent. + * @typedef {Object} WeaponDamage + * @property {number} eps Energy per second + * @property {Object} damage An object that stores damage inflicted by + * the weapon. + * @property {Object} effectiveness An object that stores the effectiveness of + * the weapon against the opponent given. + */ + +/** + * Stores overall SDPS and against a given opponent's shields and armour. + * @typedef {Object} WeaponDamage~damage + * @property {SDps} base Overall SDPS. + * @property {SDps} shields SDPS against the given opponent's shields. + * @property {SDps} armour SDPS against the given opponent's armour. + */ + /** * Calculate the sustained DPS for a weapon at a given range * @param {Object} m The weapon - * @param {Object} opponent The opponent ship + * @param {Object} opponent The opponent ship * @param {Object} opponentShields The opponent's shield resistances * @param {Object} opponentArmour The opponent's armour resistances * @param {int} engagementrange The range between the ship and opponent - * @returns {Object} Sustained DPS for shield and armour + * @returns {WeaponDamage} Sustained DPS for shield and armour */ export function _weaponSustainedDps(m, opponent, opponentShields, opponentArmour, engagementrange) { const opponentHasShields = opponentShields.generator ? true : false; From afbfe3ea12afddfab4b78e27223d6d545ce8e98e Mon Sep 17 00:00:00 2001 From: William Blythe Date: Sat, 25 Aug 2018 13:59:14 +1000 Subject: [PATCH 4/5] update orbis integration --- src/app/pages/OutfittingPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/pages/OutfittingPage.jsx b/src/app/pages/OutfittingPage.jsx index 062b3415..7fc02bc5 100644 --- a/src/app/pages/OutfittingPage.jsx +++ b/src/app/pages/OutfittingPage.jsx @@ -513,7 +513,7 @@ export default class OutfittingPage extends Page { const ship = this.state.ship; ship.coriolisId = ship.id; data.coriolisShip = ship; - data.coriolisShip.url = window.location.href; + data.url = window.location.href; data.title = this.state.buildName || ship.id; data.description = this.state.buildName || ship.id; data.ShipName = ship.id; From 0aecbbf8929b0b6f4253bb916ef302aa7dc805c8 Mon Sep 17 00:00:00 2001 From: willyb321 Date: Sun, 26 Aug 2018 09:44:44 +1000 Subject: [PATCH 5/5] [test] switch to service workers dont merge to live until can be confirmed to work well --- package-lock.json | 245 ++++++++++++++++++++ package.json | 19 +- src/app/Coriolis.jsx | 46 +++- src/app/components/AvailableModulesMenu.jsx | 2 +- src/index.ejs | 2 +- src/sw.js | 40 ++++ webpack.config.prod.js | 14 +- 7 files changed, 344 insertions(+), 24 deletions(-) create mode 100644 src/sw.js diff --git a/package-lock.json b/package-lock.json index 43c25f9b..fca17783 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2455,6 +2455,12 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -6984,6 +6990,12 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true + }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -7830,6 +7842,23 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, + "isemail": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.1.3.tgz", + "integrity": "sha512-5xbsG5wYADIcB+mfLsd+nst1V/D+I7EU7LEZPo2GOIMu4JzfcRs5yQoypP4avA7QtUqgxYLKBYNv4IdzBmbhdw==", + "dev": true, + "requires": { + "punycode": "2.x.x" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -8952,6 +8981,17 @@ } } }, + "joi": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-11.4.0.tgz", + "integrity": "sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==", + "dev": true, + "requires": { + "hoek": "4.x.x", + "isemail": "3.x.x", + "topo": "2.x.x" + } + }, "js-base64": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.3.2.tgz", @@ -9469,6 +9509,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, "lodash.assignin": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", @@ -9553,6 +9599,25 @@ "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", "dev": true }, + "lodash.template": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", + "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", + "dev": true, + "requires": { + "lodash._reinterpolate": "~3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz", + "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", + "dev": true, + "requires": { + "lodash._reinterpolate": "~3.0.0" + } + }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -11104,6 +11169,12 @@ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", "dev": true }, + "pretty-bytes": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz", + "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=", + "dev": true + }, "pretty-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", @@ -12728,6 +12799,15 @@ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", "dev": true }, + "topo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz", + "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", + "dev": true, + "requires": { + "hoek": "4.x.x" + } + }, "toposort": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.6.tgz", @@ -13403,6 +13483,171 @@ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, + "workbox-background-sync": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-3.4.1.tgz", + "integrity": "sha512-Ksb2nCg/2wOyBMhSBqSbtCEwuKaf5sHgTY8HdCxbLIQSzDh9/qZqg+1P11CKlgJmHtje3EK3B8EsrzukZo10xA==", + "dev": true, + "requires": { + "workbox-core": "^3.4.1" + } + }, + "workbox-broadcast-cache-update": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-broadcast-cache-update/-/workbox-broadcast-cache-update-3.4.1.tgz", + "integrity": "sha512-+WPqHFk4ER4RICAMOYrP88yBbiUQ9ZOFNruqwbl9YxGfbADV16OEGmYpIs+Az6HT6DNDCx8eQqtFiaG8N3O11Q==", + "dev": true, + "requires": { + "workbox-core": "^3.4.1" + } + }, + "workbox-build": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-3.4.1.tgz", + "integrity": "sha512-Qi04XdHjkXbRN0CV5XO1oqDWbJSIm7VYhxmxjtnVcKK8PrMT6rOUFUi9ziDI+8UQgcXbLK4ZChWf2ptZS1/MbA==", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "common-tags": "^1.4.0", + "fs-extra": "^4.0.2", + "glob": "^7.1.2", + "joi": "^11.1.1", + "lodash.template": "^4.4.0", + "pretty-bytes": "^4.0.2", + "workbox-background-sync": "^3.4.1", + "workbox-broadcast-cache-update": "^3.4.1", + "workbox-cache-expiration": "^3.4.1", + "workbox-cacheable-response": "^3.4.1", + "workbox-core": "^3.4.1", + "workbox-google-analytics": "^3.4.1", + "workbox-navigation-preload": "^3.4.1", + "workbox-precaching": "^3.4.1", + "workbox-range-requests": "^3.4.1", + "workbox-routing": "^3.4.1", + "workbox-strategies": "^3.4.1", + "workbox-streams": "^3.4.1", + "workbox-sw": "^3.4.1" + }, + "dependencies": { + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "workbox-cache-expiration": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-cache-expiration/-/workbox-cache-expiration-3.4.1.tgz", + "integrity": "sha512-AzOPB+dwfxg13v4+q5jWkxsw/oim9mPIzew1anu8ALA3vB8qySaJJToXp+ZlVh/Co+sDK0tgjlB76bvSFHgZ4g==", + "dev": true, + "requires": { + "workbox-core": "^3.4.1" + } + }, + "workbox-cacheable-response": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-3.4.1.tgz", + "integrity": "sha512-SO2k830JT93GitPwc5tzJI49d9VwyVxXwiCbyvo+Sqo+dcvWSrmpsyuXdzy6zuasbPrWUF0vsFj1uGtZbOym8Q==", + "dev": true, + "requires": { + "workbox-core": "^3.4.1" + } + }, + "workbox-core": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-3.4.1.tgz", + "integrity": "sha512-RqMV2so9/KLAu9aUxJ/85pvrZMUn835B8zoHmqRyGNetiDr8B1zSBeKXPZAjFlX/88KdhizNwiRlJtqlXtM4tA==", + "dev": true + }, + "workbox-google-analytics": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-3.4.1.tgz", + "integrity": "sha512-w6Osz2Rr1/4+W0gram6Yzg6NNWLvHP51RwFCNAZSpEnipr0qSEtD+yvwrdaHfiJHWhcK2yH/V6E1MV8Hrczmvw==", + "dev": true, + "requires": { + "workbox-background-sync": "^3.4.1", + "workbox-core": "^3.4.1", + "workbox-routing": "^3.4.1", + "workbox-strategies": "^3.4.1" + } + }, + "workbox-navigation-preload": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-3.4.1.tgz", + "integrity": "sha512-P3FHAcyZ8db2QiW/BpMkuosC1OkRsEoUaT7U3QOgg7JSjjsJoEbF7G5olNe+P+PQYdVhJA7TCuptI6dy2gLS/g==", + "dev": true, + "requires": { + "workbox-core": "^3.4.1" + } + }, + "workbox-precaching": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-3.4.1.tgz", + "integrity": "sha512-ykU2mly9xmRrCW6iMeUWYydWiso/WSE16+7wponhI0WC53jiQSt2JvykWm0VpWFJSs6ZTSZZ1WK2gs/brRnPug==", + "dev": true, + "requires": { + "workbox-core": "^3.4.1" + } + }, + "workbox-range-requests": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-3.4.1.tgz", + "integrity": "sha512-ktgjl6liZrRTmQjPw1pBblC5umHnTb8XcvFVitdGz17B23jj6cUV4EXzEU2ilGn6jO6+MLV1Vn9SWajtLSc2Gg==", + "dev": true, + "requires": { + "workbox-core": "^3.4.1" + } + }, + "workbox-routing": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-3.4.1.tgz", + "integrity": "sha512-6j6cXMUYfMPYTycmElxVOfBTr6WV5zAn/JUFJ7GJ5pYFIE9cqztprnrcOsWJ42+AiNIeHPbKfyIWE/rZVviMxQ==", + "dev": true, + "requires": { + "workbox-core": "^3.4.1" + } + }, + "workbox-strategies": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-3.4.1.tgz", + "integrity": "sha512-7mJuzFsgejflzjfnChXCFma1S0mi9WC6wlSU2wE50M7bJmEuf9A3j3MojpKcsTEM58hbhbnU6QF/u9iIV7+opw==", + "dev": true, + "requires": { + "workbox-core": "^3.4.1" + } + }, + "workbox-streams": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-3.4.1.tgz", + "integrity": "sha512-krw+5bp+oe9Za5c6WlTWM3SgZGfExYcqRSn1gsyYgKeXmgzTwf+DOb5Lwult0KSWlJfq8B3Wk7sW8Sl7lRzSbA==", + "dev": true, + "requires": { + "workbox-core": "^3.4.1" + } + }, + "workbox-sw": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-3.4.1.tgz", + "integrity": "sha512-nnm2by5oaQGXRH7x4M5/n2KqjUGVmP4P8azUmJITnYa3DWVYn/ghDg3LJ5+h4A28vYq9V6ePgATaEPfb6B5pug==", + "dev": true + }, + "workbox-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-dwIaEJK27xbGKMQv1sbSjywxhfX74nMW1zgUP9XUtpFeykH0e5Dm1j7wbQezXU3mFoaO7xuzqwGpAFxMKc0xMA==", + "dev": true, + "requires": { + "json-stable-stringify": "^1.0.1", + "workbox-build": "^3.4.1" + } + }, "worker-farm": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.5.1.tgz", diff --git a/package.json b/package.json index 9c30e406..785f0ff3 100644 --- a/package.json +++ b/package.json @@ -65,9 +65,16 @@ "babel-preset-react": "*", "babel-preset-stage-0": "*", "create-react-class": "^15.6.2", - "css-loader": "^0.28.0", "cross-env": "^5.1.4", + "css-loader": "^0.28.0", "d3-selection": "1", + "esdoc": "^1.1.0", + "esdoc-custom-theme": "^1.4.2", + "esdoc-ecmascript-proposal-plugin": "^1.0.0", + "esdoc-jsx-plugin": "^1.0.0", + "esdoc-publish-html-plugin": "^1.1.2", + "esdoc-react-plugin": "^1.0.1", + "esdoc-standard-plugin": "^1.0.0", "eslint": "3.19.0", "eslint-plugin-react": "^6.10.3", "expose-loader": "^0.7.3", @@ -91,16 +98,10 @@ "uglify-js": "^2.4.11", "url-loader": "^0.5.8", "webpack": "^2.4.1", + "webpack-bugsnag-plugins": "^1.1.1", "webpack-dev-server": "^2.4.4", "webpack-notifier": "^1.6.0", - "webpack-bugsnag-plugins": "^1.1.1", - "esdoc": "^1.1.0", - "esdoc-ecmascript-proposal-plugin": "^1.0.0", - "esdoc-jsx-plugin": "^1.0.0", - "esdoc-react-plugin": "^1.0.1", - "esdoc-standard-plugin": "^1.0.0", - "esdoc-publish-html-plugin": "^1.1.2", - "esdoc-custom-theme": "^1.4.2" + "workbox-webpack-plugin": "^3.4.1" }, "dependencies": { "babel-polyfill": "*", diff --git a/src/app/Coriolis.jsx b/src/app/Coriolis.jsx index 75d65ab7..e7a84e8c 100644 --- a/src/app/Coriolis.jsx +++ b/src/app/Coriolis.jsx @@ -322,14 +322,48 @@ export default class Coriolis extends React.Component { */ componentWillMount() { // Listen for appcache updated event, present refresh to update view - if (window.applicationCache) { - window.applicationCache.addEventListener('updateready', () => { - if (window.applicationCache.status == window.applicationCache.UPDATEREADY) { - this.setState({ appCacheUpdate: true }); // Browser downloaded a new app cache. - } + // Check that service workers are registered + if ('serviceWorker' in navigator) { + // Your service-worker.js *must* be located at the top-level directory relative to your site. + // It won't be able to control pages unless it's located at the same level or higher than them. + // *Don't* register service worker file in, e.g., a scripts/ sub-directory! + // See https://github.com/slightlyoff/ServiceWorker/issues/468 + const self = this; + navigator.serviceWorker.register('/service-worker.js').then(function(reg) { + // updatefound is fired if service-worker.js changes. + reg.onupdatefound = function() { + // The updatefound event implies that reg.installing is set; see + // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event + var installingWorker = reg.installing; + + installingWorker.onstatechange = function() { + switch (installingWorker.state) { + case 'installed': + if (navigator.serviceWorker.controller) { + // At this point, the old content will have been purged and the fresh content will + // have been added to the cache. + // It's the perfect time to display a "New content is available; please refresh." + // message in the page's interface. + console.log('New or updated content is available.'); + self.setState({ appCacheUpdate: true }); // Browser downloaded a new app cache. + } else { + // At this point, everything has been precached. + // It's the perfect time to display a "Content is cached for offline use." message. + console.log('Content is now available offline!'); + self.setState({ appCacheUpdate: true }); // Browser downloaded a new app cache. + } + break; + + case 'redundant': + console.error('The installing service worker became redundant.'); + break; + } + }; + }; + }).catch(function(e) { + console.error('Error during service worker registration:', e); }); } - window.onerror = this._onError.bind(this); window.addEventListener('resize', () => this.emitter.emit('windowResize')); document.getElementById('coriolis').addEventListener('scroll', () => this._tooltip()); diff --git a/src/app/components/AvailableModulesMenu.jsx b/src/app/components/AvailableModulesMenu.jsx index b7ee95a6..6e3db231 100644 --- a/src/app/components/AvailableModulesMenu.jsx +++ b/src/app/components/AvailableModulesMenu.jsx @@ -97,7 +97,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', 'mahr', ], + 'experimental': ['axmc', 'axmr', 'rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'mahr',], // Guardian 'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc'] diff --git a/src/index.ejs b/src/index.ejs index 32bccb3d..b6954789 100644 --- a/src/index.ejs +++ b/src/index.ejs @@ -1,5 +1,5 @@ - > + Coriolis EDCD Edition diff --git a/src/sw.js b/src/sw.js new file mode 100644 index 00000000..efe159ba --- /dev/null +++ b/src/sw.js @@ -0,0 +1,40 @@ +console.log('Hello from sw.js'); + +if (workbox) { + console.log('Yay! Workbox is loaded 🎉'); + workbox.routing.registerRoute( + new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'), + workbox.strategies.cacheFirst({ + cacheName: 'google-fonts', + plugins: [ + new workbox.expiration.Plugin({ + maxEntries: 30 + }), + new workbox.cacheableResponse.Plugin({ + statuses: [0, 200] + }) + ] + }) + ); + workbox.routing.registerRoute( + /\.(?:png|gif|jpg|jpeg|svg)$/, + workbox.strategies.cacheFirst({ + cacheName: 'images', + plugins: [ + new workbox.expiration.Plugin({ + maxEntries: 60, + maxAgeSeconds: 30 * 24 * 60 * 60 // 30 Days + }) + ] + }) + ); + workbox.routing.registerRoute( + /\.(?:js|css)$/, + workbox.strategies.staleWhileRevalidate({ + cacheName: 'static-resources' + }) + ); + workbox.googleAnalytics.initialize(); +} else { + console.log('Boo! Workbox didn\'t load 😬'); +} diff --git a/webpack.config.prod.js b/webpack.config.prod.js index c0c78bc1..f5d9fac0 100644 --- a/webpack.config.prod.js +++ b/webpack.config.prod.js @@ -3,7 +3,8 @@ const exec = require('child_process').exec; const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); -const AppCachePlugin = require('appcache-webpack-plugin'); +const { InjectManifest } = require('workbox-webpack-plugin'); + const { BugsnagSourceMapUploaderPlugin } = require('webpack-bugsnag-plugins'); const pkgJson = require('./package'); const buildDate = new Date(); @@ -75,12 +76,11 @@ module.exports = { new CopyDirPlugin(path.join(__dirname, 'src/schemas'), 'schemas'), new CopyDirPlugin(path.join(__dirname, 'src/images/logo/*'), ''), new CopyDirPlugin(path.join(__dirname, 'src/.htaccess'), ''), - new AppCachePlugin({ - network: ['*'], - settings: ['prefer-online'], - exclude: ['index.html', /.*\.map$/], - output: 'coriolis.appcache' - }) + new InjectManifest({ + swSrc: './src/sw.js', + importWorkboxFrom: 'cdn', + swDest: 'service-worker.js' + }), ], module: { rules: [