Skip to content

Commit

Permalink
Merge branch 'master' into dependabot/npm_and_yarn/www/uglifyjs-webpa…
Browse files Browse the repository at this point in the history
…ck-plugin-1.2.0
  • Loading branch information
taneliang authored Feb 19, 2018
2 parents db55fed + 06c678f commit ecf751e
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 27 deletions.
4 changes: 4 additions & 0 deletions www/flow-typed/package-dep-libdefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ declare module '@material/fab' {
declare module '@material/snackbar' {
declare module.exports: any;
}

declare module 'bowser' {
declare module.exports: any;
}
5 changes: 3 additions & 2 deletions www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"enzyme-to-json": "^3.3.1",
"eslint": "^4.17.0",
"eslint": "^4.18.0",
"eslint-config-airbnb": "^16.1.0",
"eslint-config-prettier": "^2.9.0",
"eslint-import-resolver-webpack": "^0.8.4",
Expand All @@ -75,7 +75,7 @@
"moment": "^2.20.1",
"node-sass": "^4.7.2",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"postcss-custom-properties": "^6.2.0",
"postcss-custom-properties": "^7.0.0",
"postcss-loader": "^2.1.0",
"prettier": "^1.10.2",
"react-dev-utils": "^5.0.0",
Expand All @@ -102,6 +102,7 @@
"autotrack": "^2.4.1",
"axios": "^0.17.1",
"bootstrap": "4.0.0",
"bowser": "^1.9.2",
"classnames": "^2.2.5",
"core-js": "^2.5.1",
"downshift": "^1.28.0",
Expand Down
87 changes: 87 additions & 0 deletions www/src/js/bootstrapping/browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// @flow

// This script checks for browser compatibility and is executed outside React's scope. If a browser
// is incompatible or not optimal for using the app, a pop-up dialog is appended into the DOM body.
// This is so that in cases where the React app completely fails to render anything at all, the
// user will at least be able to see the dialog warning them of the browser incompatibility.

import bowser from 'bowser';
import { canUseBrowserLocalStorage } from 'storage/localStorage';
import styles from './browser.scss';

const LOCAL_STORAGE_KEY = 'dismissedBrowserWarning';
const composeAnchorText = (innerHTML, href) =>
`<a href=${href} target="_blank" rel="noopener noreferrer">${innerHTML}</a>`;
const linkForChrome = composeAnchorText('Google Chrome', 'https://www.google.com/chrome/');
const linkForFirefox = composeAnchorText('Mozilla Firefox', 'https://www.mozilla.org/en-US/');
const linkForChromePlayStore = composeAnchorText(
'updating your web browser',
'http://play.google.com/store/apps/details?id=com.android.chrome',
);

const browserCanUseLocalStorage = canUseBrowserLocalStorage();

if (
!bowser.check(
{
edge: '14',
chrome: '56',
firefox: '52',
safari: '9',
},
true,
)
) {
if (
(browserCanUseLocalStorage && !localStorage.getItem(LOCAL_STORAGE_KEY)) ||
!browserCanUseLocalStorage
) {
const promptText = (() => {
// Users can only update Safari by updating the OS in iOS
if (bowser.ios)
return `NUSMods may not work properly. Please consider updating your device to iOS 11 or higher.`;
if (bowser.android && bowser.chrome)
return `NUSMods may not work properly. Please consider ${linkForChromePlayStore}.`;
return `NUSMods may not work properly. Please consider updating your web browser or switching to the latest version of ${linkForChrome} or ${linkForFirefox}.`;
})();
const template = `
<div class="${styles.modal}">
<h3>Your web browser is outdated or unsupported</h3>
<p>${promptText}</p>
<div class="form-row align-items-center">
<div class="col-auto">
<button class="btn btn-primary" id="browserWarning-continue" type="button">Continue to NUSMods</button>
</div>
${
// Show "don't show again" only if the browser supports localStorage
browserCanUseLocalStorage
? `
<div class="col-auto ${styles.checkboxContainer}">
<div class="form-check form-check-inline">
<input class="form-check-input" id="browserWarning-ignore" type="checkbox">
<label class="form-check-label" for="browserWarning-ignore">Don't show this message again</label>
</div>
</div>
`
: ''
}
</div>
</div>
`;
const container = document.createElement('div');
container.className = styles.browserWarning;
container.innerHTML = template;
const body = document.body;
if (body) body.appendChild(container);

const element = document.getElementById('browserWarning-continue');
if (element) {
element.addEventListener('click', () => {
const checkbox = document.getElementById('browserWarning-ignore');
if (browserCanUseLocalStorage && checkbox && checkbox.checked)
localStorage.setItem(LOCAL_STORAGE_KEY, navigator.userAgent);
if (body) body.removeChild(container);
});
}
}
}
25 changes: 25 additions & 0 deletions www/src/js/bootstrapping/browser.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@import '~styles/utils/modules-entry';

.browserWarning {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: $browser-warning-z-index;
overflow: hidden;
background: rgba(0, 0, 0, 0.5);

.modal {
max-width: 48em;
padding: 2em;
margin-right: auto;
margin-left: auto;
background: #fff;

.checkboxContainer {
padding-top: 0.5em;
padding-bottom: 0.5em;
}
}
}
1 change: 1 addition & 0 deletions www/src/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'bootstrapping/polyfill';

// Import Sentry earliest to capture exceptions
import 'bootstrapping/sentry';
import 'bootstrapping/browser';

import ReactDOM from 'react-dom';
import ReactModal from 'react-modal';
Expand Down
33 changes: 19 additions & 14 deletions www/src/js/storage/localStorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,7 @@ export function createLocalStorageShim() {
return storage;
}

// Shim localStorage if it doesn't exist
// Returns an object that behaves like localStorage
export default function getLocalStorage() {
// If we've performed all our checks before, just assume results will be the same
// Key assumption: writability of localStorage doesn't change while page is loaded
if (usableLocalStorage) return usableLocalStorage;

export function canUseBrowserLocalStorage() {
try {
// Ensure that accessing localStorage doesn't throw
// Next line throws on Chrome with cookies disabled
Expand All @@ -43,14 +37,25 @@ export default function getLocalStorage() {
storage.removeItem('____writetest');
}

// Only set storage AFTER we know it can be used
usableLocalStorage = storage;
// Only return true AFTER we know it can be used
return true;
} catch (e) {
// Shim if we can't use localStorage
// Once set, don't override
if (!usableLocalStorage) {
usableLocalStorage = createLocalStorageShim();
}
return false;
}
}

// Returns localStorage if it can be used, if not then it returns a shim
export default function getLocalStorage() {
// If we've performed all our checks before, just assume results will be the same
// Key assumption: writability of localStorage doesn't change while page is loaded
if (usableLocalStorage) return usableLocalStorage;

// Sets usableLocalStorage on the first execution
if (canUseBrowserLocalStorage()) {
usableLocalStorage = window.localStorage;
} else {
usableLocalStorage = createLocalStorageShim();
}

return usableLocalStorage;
}
46 changes: 45 additions & 1 deletion www/src/js/storage/localStorage.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createLocalStorageShim } from './localStorage';
import getLocalStorage, { createLocalStorageShim, canUseBrowserLocalStorage } from './localStorage';

describe('#createLocalStorageShim', () => {
test('should store and return data', () => {
Expand Down Expand Up @@ -42,3 +42,47 @@ describe('#createLocalStorageShim', () => {
expect(() => shim.removeItem('key')).not.toThrow();
});
});

describe('#canUseBrowserLocalStorage', () => {
test('should return false if localStorage is undefined', () => {
window.localStorage = undefined;
expect(canUseBrowserLocalStorage()).toEqual(false);
});

test('should return false if localStorage throws when writing on iOS <=10 on private browsing', () => {
window.localStorage = {
...createLocalStorageShim(),
// the length is set here because canUseBrowserLocalStorage uses a hack to detect private browsing
length: 0,
setItem: () => {
throw new Error();
},
};
expect(canUseBrowserLocalStorage()).toEqual(false);
});

test('should return true if localStorage is localStorage-like object', () => {
window.localStorage = createLocalStorageShim();
expect(canUseBrowserLocalStorage()).toEqual(true);
});
});

describe('#getLocalStorage', () => {
test("should return the actual browser's localStorage if the browser can use localStorage", () => {
expect(canUseBrowserLocalStorage()).toEqual(true);
expect(getLocalStorage()).toBe(window.localStorage);
});

test('should return a shim if browser cannot use localStorage', () => {
window.localStorage = undefined;
expect(canUseBrowserLocalStorage()).toEqual(false);
expect(getLocalStorage()).toMatchObject(
expect.objectContaining({
clear: expect.any(Function),
setItem: expect.any(Function),
getItem: expect.any(Function),
removeItem: expect.any(Function),
}),
);
});
});
2 changes: 1 addition & 1 deletion www/src/js/test-utils/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export const nextTick = util.promisify(process.nextTick);
* components that have async actions, such as making network requests
*/
export async function waitFor(condition: () => boolean, intervalInMs: number = 5) {
// eslint-disable-next-line no-await-in-loop
while (!condition()) {
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve) => setTimeout(resolve, intervalInMs));
}
}
1 change: 1 addition & 0 deletions www/src/styles/constants.scss
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ $nusmods-theme-colors: (
);

// Z-index
$browser-warning-z-index: 9999;
$snackbar-z-index: 2500;
$sentry-z-index: 2000;
$modal-z-index: 1500;
Expand Down
3 changes: 1 addition & 2 deletions www/src/styles/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
// 3rd-party imports
@import 'bootstrap/bootstrap';
@import 'bootstrap/style-override';

@import "material/material";
@import 'material/material';

// Utils
@import 'utils/css-variables';
Expand Down
26 changes: 19 additions & 7 deletions www/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,10 @@ [email protected]:
version "4.0.0"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.0.0.tgz#ceb03842c145fcc1b9b4e15da2a05656ba68469a"

bowser@^1.9.2:
version "1.9.2"
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.2.tgz#d66fc868ca5f4ba895bee1363c343fe7b37d3394"

brace-expansion@^1.0.0, brace-expansion@^1.1.7:
version "1.1.8"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
Expand Down Expand Up @@ -2940,9 +2944,9 @@ eslint-visitor-keys@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"

eslint@^4.17.0:
version "4.17.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.17.0.tgz#dc24bb51ede48df629be7031c71d9dc0ee4f3ddf"
eslint@^4.18.0:
version "4.18.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.18.0.tgz#ebd0ba795af6dc59aa5cee17938160af5950e051"
dependencies:
ajv "^5.3.0"
babel-code-frame "^6.22.0"
Expand Down Expand Up @@ -6409,12 +6413,12 @@ postcss-convert-values@^2.3.4:
postcss "^5.0.11"
postcss-value-parser "^3.1.2"

postcss-custom-properties@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-6.2.0.tgz#5d929a7f06e9b84e0f11334194c0ba9a30acfbe9"
postcss-custom-properties@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-7.0.0.tgz#24dc4fbe6d6ed550ea4fd3b11204660e9ffa3b33"
dependencies:
balanced-match "^1.0.0"
postcss "^6.0.13"
postcss "^6.0.18"

postcss-discard-comments@^2.0.4:
version "2.0.4"
Expand Down Expand Up @@ -6744,6 +6748,14 @@ postcss@^6.0.17:
source-map "^0.6.1"
supports-color "^5.1.0"

postcss@^6.0.18:
version "6.0.19"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.19.tgz#76a78386f670b9d9494a655bf23ac012effd1555"
dependencies:
chalk "^2.3.1"
source-map "^0.6.1"
supports-color "^5.2.0"

prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
Expand Down

0 comments on commit ecf751e

Please sign in to comment.