diff --git a/client/coral-embed-stream/src/actions/stream.js b/client/coral-embed-stream/src/actions/stream.js index d936879e9..7250b86f3 100644 --- a/client/coral-embed-stream/src/actions/stream.js +++ b/client/coral-embed-stream/src/actions/stream.js @@ -1,35 +1,24 @@ import pym from 'coral-framework/services/pym'; import * as actions from '../constants/stream'; +import {buildUrl} from 'coral-framework/utils'; +import queryString from 'query-string'; export const setActiveReplyBox = (id) => ({type: actions.SET_ACTIVE_REPLY_BOX, id}); -function removeParam(key, sourceURL) { - let rtn = sourceURL.split('?')[0]; - let param; - let params_arr = []; - let queryString = (sourceURL.indexOf('?') !== -1) ? sourceURL.split('?')[1] : ''; - if (queryString !== '') { - params_arr = queryString.split('&'); - for (let i = params_arr.length - 1; i >= 0; i -= 1) { - param = params_arr[i].split('=')[0]; - if (param === key) { - params_arr.splice(i, 1); - } - } - rtn = `${rtn}?${params_arr.join('&')}`; - } - return rtn; -} - export const viewAllComments = () => { + const search = queryString.stringify({ + ...queryString.parse(location.search), + comment_id: undefined, + }); + // remove the comment_id url param - const modifiedUrl = removeParam('comment_id', location.href); + const url = buildUrl({...location, search}); try { // "window" here refers to the embedded iframe - window.history.replaceState({}, document.title, modifiedUrl); + window.history.replaceState({}, document.title, url); // also change the parent url pym.sendMessage('coral-view-all-comments'); @@ -38,6 +27,28 @@ export const viewAllComments = () => { return {type: actions.VIEW_ALL_COMMENTS}; }; +export const viewComment = (id) => { + + const search = queryString.stringify({ + ...queryString.parse(location.search), + comment_id: id, + }); + + // remove the comment_id url param + const url = buildUrl({...location, search}); + + try { + + // "window" here refers to the embedded iframe + window.history.replaceState({}, document.title, url); + + // also change the parent url + pym.sendMessage('coral-view-comment', id); + } catch (e) { /* not sure if we're worried about old browsers */ } + + return {type: actions.VIEW_COMMENT, id}; +}; + export const addCommentClassName = (className) => ({ type: actions.ADD_COMMENT_CLASSNAME, className diff --git a/client/coral-embed-stream/src/constants/stream.js b/client/coral-embed-stream/src/constants/stream.js index 622a86c18..7ac9427cf 100644 --- a/client/coral-embed-stream/src/constants/stream.js +++ b/client/coral-embed-stream/src/constants/stream.js @@ -1,6 +1,7 @@ export const SET_ACTIVE_REPLY_BOX = 'SET_ACTIVE_REPLY_BOX'; export const ADDTL_COMMENTS_ON_LOAD_MORE = 10; export const VIEW_ALL_COMMENTS = 'VIEW_ALL_COMMENTS'; +export const VIEW_COMMENT = 'VIEW_COMMENT'; export const ADD_COMMENT_CLASSNAME = 'ADD_COMMENT_CLASSNAME'; export const REMOVE_COMMENT_CLASSNAME = 'REMOVE_COMMENT_CLASSNAME'; export const THREADING_LEVEL = process.env.TALK_THREADING_LEVEL; diff --git a/client/coral-embed-stream/src/reducers/stream.js b/client/coral-embed-stream/src/reducers/stream.js index 4f4fcf47f..2bb8cf0d3 100644 --- a/client/coral-embed-stream/src/reducers/stream.js +++ b/client/coral-embed-stream/src/reducers/stream.js @@ -17,9 +17,9 @@ function getQueryVariable(variable) { const initialState = { activeReplyBox: '', - assetId: getQueryVariable('asset_id'), - assetUrl: getQueryVariable('asset_url'), - commentId: getQueryVariable('comment_id'), + assetId: getQueryVariable('asset_id') || '', + assetUrl: getQueryVariable('asset_url') || '', + commentId: getQueryVariable('comment_id') || '', commentClassNames: [], activeTab: 'all', previousTab: '', @@ -48,6 +48,11 @@ export default function stream(state = initialState, action) { ...state, commentId: '', }; + case actions.VIEW_COMMENT: + return { + ...state, + commentId: action.id, + }; case actions.ADD_COMMENT_CLASSNAME : return { ...state, diff --git a/client/coral-embed/src/index.js b/client/coral-embed/src/index.js index 702308c3a..eb61f3b90 100644 --- a/client/coral-embed/src/index.js +++ b/client/coral-embed/src/index.js @@ -1,7 +1,8 @@ import pym from 'pym.js'; import URLSearchParams from 'url-search-params'; -import {stringify} from 'querystring'; +import {buildUrl} from 'coral-framework/utils'; +import queryString from 'query-string'; // TODO: Styles should live in a separate file const snackbarStyles = { @@ -39,7 +40,7 @@ function buildStreamIframeUrl(talkBaseUrl, query) { 'embed/stream?' ].join(''); - url += stringify(query); + url += queryString.stringify(query); return url; } @@ -98,10 +99,37 @@ function configurePymParent(pymParent, opts) { // remove the permalink comment id from the hash pymParent.onMessage('coral-view-all-comments', function() { + + const search = queryString.stringify({ + ...queryString.parse(location.search), + commentId: undefined, + }); + + // remove the commentId url param + const url = buildUrl({...location, search}); + window.history.replaceState( {}, document.title, - location.origin + location.pathname + location.search + url, + ); + }); + + // remove the permalink comment id from the hash + pymParent.onMessage('coral-view-comment', function(id) { + + const search = queryString.stringify({ + ...queryString.parse(location.search), + commentId: id, + }); + + // remove the commentId url param + const url = buildUrl({...location, search}); + + window.history.replaceState( + {}, + document.title, + url, ); }); @@ -193,12 +221,18 @@ Talk.render = function(el, opts) { let urlParams = new URLSearchParams(window.location.search); - query.comment_id = urlParams.get('commentId'); + if (urlParams.get('commentId')) { + query.comment_id = urlParams.get('commentId'); + } - query.asset_id = opts.asset_id; + if (opts.asset_id) { + query.asset_id = opts.asset_id; + } - query.asset_url = opts.asset_url; - if (!query.asset_url) { + if (opts.asset_url) { + query.asset_url = opts.asset_url; + } + else { try { query.asset_url = document.querySelector('link[rel="canonical"]').href; } catch (e) { diff --git a/client/coral-framework/utils/index.js b/client/coral-framework/utils/index.js index 0917b73ba..974be9502 100644 --- a/client/coral-framework/utils/index.js +++ b/client/coral-framework/utils/index.js @@ -167,3 +167,12 @@ export function insertCommentsSorted(nodes, comments, sortOrder = 'CHRONOLOGICAL } export const isTagged = (tags, which) => tags.some((t) => t.tag.name === which); + +export function buildUrl({protocol, hostname, port, pathname, search, hash} = window.location) { + if (search && search[0] !== '?') { + search = `?${search}`; + } else if (search === '?') { + search = ''; + } + return `${protocol}//${hostname}${port ? `:${port}` : ''}${pathname}${search}${hash}`; +} diff --git a/package.json b/package.json index 76b0c299a..ee41de42d 100644 --- a/package.json +++ b/package.json @@ -111,6 +111,7 @@ "passport-jwt": "^2.2.1", "passport-local": "^1.0.0", "prop-types": "^15.5.10", + "query-strings": "^0.0.1", "react-apollo": "^1.1.0", "react-input-autosize": "^1.1.4", "react-recaptcha": "^2.2.6", diff --git a/plugins/talk-plugin-featured-comments/client/components/FeaturedComment.js b/plugins/talk-plugin-featured-comments/client/components/FeaturedComment.js index 61fc9810e..f28d01b6d 100644 --- a/plugins/talk-plugin-featured-comments/client/components/FeaturedComment.js +++ b/plugins/talk-plugin-featured-comments/client/components/FeaturedComment.js @@ -6,7 +6,7 @@ import {timeago} from 'coral-framework/services/i18n'; import {Slot} from 'plugin-api/beta/client/components'; import {Icon} from 'plugin-api/beta/client/components/ui'; -const FeaturedComment = ({comment, asset, setActiveTab}) => { +const FeaturedComment = ({comment, asset, viewComment}) => { return (