diff --git a/web/app/common/constants.js b/web/app/common/constants.js index 77937f25..a4e1ef28 100644 --- a/web/app/common/constants.js +++ b/web/app/common/constants.js @@ -38,3 +38,29 @@ export const BLOCKING_DURATIONS = [ value: `${60 * 24}m`, }, ]; + +/** + * Defines if browser storage features (cookies, localsrotage) + * are available or blocked via browser preferences + */ +export const STORAGE_AVAILABLE = (() => { + try { + localStorage.setItem('localstorage_availability_test', null); + localStorage.removeItem('localstorage_availability_test'); + } catch (e) { + return false; + } + return true; +})(); + +/** + * Defines whether iframe loaded in cross origin environment + * Usefull for checking if some privacy restriction may be applied + */ +export const IS_THIRD_PARTY = (() => { + try { + return window.parent.document.location.host !== window.location.host; + } catch (e) { + return true; + } +})(); diff --git a/web/app/common/localStorage.js b/web/app/common/localStorage.js new file mode 100644 index 00000000..417f7dc4 --- /dev/null +++ b/web/app/common/localStorage.js @@ -0,0 +1,30 @@ +export const isAvailable = (() => { + try { + localStorage.setItem('localstorage_availability_test', null); + localStorage.removeItem('localstorage_availability_test'); + } catch (e) { + return false; + } + return true; +})(); + +const failMessage = 'remark42: localStorage access denied, check browser preferences'; + +export const setItem = isAvailable + ? localStorage.setItem.bind(localStorage) + : () => { + console.error(failMessage); // eslint-disable-line no-console + }; + +export const getItem = isAvailable + ? localStorage.getItem.bind(localStorage) + : () => { + console.error(failMessage); // eslint-disable-line no-console + return null; + }; + +export const removeItem = isAvailable + ? localStorage.removeItem.bind(localStorage) + : () => { + console.error(failMessage); // eslint-disable-line no-console + }; diff --git a/web/app/components/auth-panel/auth-panel.jsx b/web/app/components/auth-panel/auth-panel.jsx index 2ed169dc..1cc5ef76 100644 --- a/web/app/components/auth-panel/auth-panel.jsx +++ b/web/app/components/auth-panel/auth-panel.jsx @@ -4,7 +4,7 @@ import { h, Component } from 'preact'; import UserId from './__user-id/auth-panel__user-id'; import Dropdown, { DropdownItem } from 'components/dropdown'; import Button from 'components/button'; -import { PROVIDER_NAMES } from 'common/constants'; +import { PROVIDER_NAMES, STORAGE_AVAILABLE, IS_THIRD_PARTY } from 'common/constants'; import { requestDeletion } from 'utils/email'; import { getHandleClickProps } from 'common/accessibility'; @@ -76,28 +76,46 @@ export default class AuthPanel extends Component { )} - {!loggedIn && ( -
- Sign in to comment using{' '} - {providers.map((provider, i) => { - const comma = i === 0 ? '' : i === providers.length - 1 ? ' or ' : ', '; + {STORAGE_AVAILABLE && + !loggedIn && ( +
+ Sign in to comment using{' '} + {providers.map((provider, i) => { + const comma = i === 0 ? '' : i === providers.length - 1 ? ' or ' : ', '; - return ( - - {comma} - props.onSignIn(provider))} - role="link" - > - {PROVIDER_NAMES[provider]} + return ( + + {comma} + props.onSignIn(provider))} + role="link" + > + {PROVIDER_NAMES[provider]} + - - ); - })} - {'.'} -
- )} + ); + })} + {'.'} +
+ )} + + {!STORAGE_AVAILABLE && + IS_THIRD_PARTY && ( +
+ Disable third-party cookies blocking to sign in or open comments in{' '} + + new page + +
+ )} + + {!STORAGE_AVAILABLE && + !IS_THIRD_PARTY &&
Allow cookies to sign in and comment
}
{user.admin && ( diff --git a/web/app/components/thread/getCollapsedComments.js b/web/app/components/thread/getCollapsedComments.js index 6568e6af..b240a8b5 100644 --- a/web/app/components/thread/getCollapsedComments.js +++ b/web/app/components/thread/getCollapsedComments.js @@ -1,5 +1,6 @@ import { LS_COLLAPSE_KEY } from 'common/constants'; +import { getItem } from 'common/localStorage'; -const getCollapsedComments = () => JSON.parse(localStorage.getItem(LS_COLLAPSE_KEY) || '[]'); +const getCollapsedComments = () => JSON.parse(getItem(LS_COLLAPSE_KEY) || '[]'); export default getCollapsedComments; diff --git a/web/app/components/thread/saveCollapsedComments.js b/web/app/components/thread/saveCollapsedComments.js index 3d0179c2..bb2da2de 100644 --- a/web/app/components/thread/saveCollapsedComments.js +++ b/web/app/components/thread/saveCollapsedComments.js @@ -1,5 +1,6 @@ import { LS_COLLAPSE_KEY } from 'common/constants'; +import { setItem } from 'common/localStorage'; -const saveCollapsedComments = comments => localStorage.setItem(LS_COLLAPSE_KEY, JSON.stringify(comments)); +const saveCollapsedComments = comments => setItem(LS_COLLAPSE_KEY, JSON.stringify(comments)); export default saveCollapsedComments; diff --git a/web/comments.ejs b/web/comments.ejs new file mode 100644 index 00000000..dbd08fc9 --- /dev/null +++ b/web/comments.ejs @@ -0,0 +1,58 @@ + + + + + + remark42 + + + + +
+
+
+
+ + + + + diff --git a/web/webpack.config.js b/web/webpack.config.js index 2b7efeed..869af3a1 100644 --- a/web/webpack.config.js +++ b/web/webpack.config.js @@ -114,6 +114,11 @@ module.exports = { filename: 'last-comments.html', inject: false, }), + new Html({ + template: path.resolve(__dirname, 'comments.ejs'), + filename: 'comments.html', + inject: false, + }), new ExtractText({ filename: `remark.css`, allChunks: true,