From bb4fcdf32dd8efa1854e34f4c8cd6d98c1f4f511 Mon Sep 17 00:00:00 2001 From: mgabdev <> Date: Tue, 7 Apr 2020 21:06:59 -0400 Subject: [PATCH] Progress --- .eslintrc.js | 10 +- app/javascript/gabsocial/actions/compose.js | 26 +- .../gabsocial/actions/notifications.js | 30 +- app/javascript/gabsocial/actions/settings.js | 2 +- app/javascript/gabsocial/actions/tenor.js | 14 +- app/javascript/gabsocial/actions/timelines.js | 17 +- app/javascript/gabsocial/api.js | 2 +- .../gabsocial/assets/hidden_icon.js | 28 + .../gabsocial/components/account.js | 1 + .../autosuggest_emoji/autosuggest_emoji.js | 20 +- .../autosuggest_textbox.js | 65 +- app/javascript/gabsocial/components/avatar.js | 1 + app/javascript/gabsocial/components/block.js | 6 + .../gabsocial/components/column_header.js | 16 +- .../gabsocial/components/comment.js | 48 +- .../gabsocial/components/comment_list.js | 160 +-- .../gabsocial/components/display_name.js | 2 +- .../emoji/__tests__/emoji_index-test.js | 2 +- .../gabsocial/components/file_input.js | 17 +- .../components/floating_action_button.js | 2 +- .../components/group_collection_item.js | 80 +- .../gabsocial/components/group_list_item.js | 18 +- .../gabsocial/components/hashtag_item.js | 1 + app/javascript/gabsocial/components/icon.js | 131 ++- app/javascript/gabsocial/components/image.js | 35 +- .../intersection_observer_article.js | 2 +- .../gabsocial/components/link_footer.js | 3 +- .../components/media_gallery/media_gallery.js | 136 ++- .../components/modal/gif_picker_modal.js | 3 +- .../gabsocial/components/modal/modal_base.js | 7 +- .../gabsocial/components/modal/modal_root.js | 4 +- .../components/modal/pro_upgrade_modal.js | 1 + .../components/popover/popover_base.js | 11 +- .../components/popover/popover_root.js | 38 +- .../gabsocial/components/profile_header.js | 28 +- .../gabsocial/components/recursive_comment.js | 2 +- .../components/relative_timestamp.js | 54 +- .../gabsocial/components/scrollable_list.js | 20 +- .../components/sensitive_media_item.js | 50 + .../gabsocial/components/sidebar.js | 8 +- .../components/sidebar_section_item.js | 14 +- .../gabsocial/components/status/status.js | 8 +- .../gabsocial/components/status_card.js | 13 +- .../status_content/status_content.js | 16 +- .../timeline_queue_button_header.js | 2 +- .../gabsocial/components/trends_item.js | 10 +- app/javascript/gabsocial/components/video.js | 2 +- .../gabsocial/containers/status_container.js | 14 +- .../containers/status_list_container.js | 3 +- .../gabsocial/features/account_gallery.js | 4 +- .../gabsocial/features/blocked_accounts.js | 2 +- .../gabsocial/features/blocked_domains.js | 2 +- .../components/compose_form/compose_form.js | 58 +- .../compose/components/emoji_picker_button.js | 2 +- .../compose/components/gif_selector_button.js | 2 +- .../components/quoted_status_preview.js | 23 - .../components/status_visibility_button.js | 25 +- .../components/upload_form/upload_form.js | 2 +- .../gabsocial/features/compose/compose.js | 2 +- .../containers/compose_form_container.js | 5 +- .../quoted_status_preview_container.js | 8 - .../features/compose/util/counter.js | 6 +- .../follow_requests/follow_requests.js | 2 +- .../gabsocial/features/followers.js | 2 +- .../gabsocial/features/following.js | 2 +- .../gabsocial/features/group_members.js | 2 +- .../features/group_removed_accounts.js | 2 +- .../gabsocial/features/groups_collection.js | 29 +- .../gabsocial/features/hashtag_timeline.js | 18 +- .../gabsocial/features/introduction.js | 6 +- .../gabsocial/features/liked_statuses.js | 2 +- app/javascript/gabsocial/features/mutes.js | 2 +- .../features/notifications/notifications.js | 2 +- .../containers/detailed_status_container.js | 2 +- .../gabsocial/features/status/status.js | 60 +- .../features/ui/util/wrapped_route.js | 2 +- app/javascript/gabsocial/main.js | 5 - app/javascript/gabsocial/middleware/sounds.js | 58 - app/javascript/gabsocial/pages/groups_page.js | 21 +- app/javascript/gabsocial/pages/lists_page.js | 5 +- .../gabsocial/pages/profile_page.js | 6 +- app/javascript/gabsocial/performance.js | 33 - app/javascript/gabsocial/reducers/compose.js | 2 +- app/javascript/gabsocial/reducers/modal.js | 23 +- app/javascript/gabsocial/reducers/popover.js | 20 +- app/javascript/gabsocial/reducers/tenor.js | 60 +- .../service_worker/web_push_notifications.js | 2 +- .../gabsocial/store/configureStore.js | 2 - app/javascript/gabsocial/utils/is_mobile.js | 4 +- app/javascript/packs/public.js | 7 - app/javascript/styles/global.css | 20 +- app/serializers/rest/status_serializer.rb | 2 - babel.config.js | 1 - config/webpack/shared.js | 9 +- package.json | 182 ++- public/sounds/boop.mp3 | Bin 12280 -> 0 bytes public/sounds/boop.ogg | Bin 5247 -> 0 bytes public/sounds/ribbit.mp3 | Bin 6957 -> 0 bytes public/sounds/ribbit.ogg | Bin 10318 -> 0 bytes public/sounds/ribbit.wav | Bin 70478 -> 0 bytes yarn.lock | 1036 +++-------------- 101 files changed, 1069 insertions(+), 1886 deletions(-) create mode 100644 app/javascript/gabsocial/assets/hidden_icon.js create mode 100644 app/javascript/gabsocial/components/sensitive_media_item.js delete mode 100644 app/javascript/gabsocial/features/compose/components/quoted_status_preview.js delete mode 100644 app/javascript/gabsocial/features/compose/containers/quoted_status_preview_container.js delete mode 100644 app/javascript/gabsocial/middleware/sounds.js delete mode 100644 app/javascript/gabsocial/performance.js delete mode 100644 public/sounds/boop.mp3 delete mode 100644 public/sounds/boop.ogg delete mode 100644 public/sounds/ribbit.mp3 delete mode 100644 public/sounds/ribbit.ogg delete mode 100644 public/sounds/ribbit.wav diff --git a/.eslintrc.js b/.eslintrc.js index 26a1ea7c..f2113e44 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,6 +10,13 @@ module.exports = { globals: { ATTACHMENT_HOST: false, + _s: true, + PropTypes: true, + PureComponent: true, + React: { + Component: true, + }, + connect: true, }, parser: 'babel-eslint', @@ -98,8 +105,9 @@ module.exports = { classes: 'always', }, ], + 'prefer-const': 'error', quotes: ['error', 'single'], - semi: 'error', + semi: 'off', strict: 'off', 'valid-typeof': 'error', diff --git a/app/javascript/gabsocial/actions/compose.js b/app/javascript/gabsocial/actions/compose.js index 0628584a..2a54b1d3 100644 --- a/app/javascript/gabsocial/actions/compose.js +++ b/app/javascript/gabsocial/actions/compose.js @@ -1,7 +1,6 @@ import api from '../api'; import { CancelToken, isCancel } from 'axios'; -import { throttle } from 'lodash'; -import moment from 'moment'; +import throttle from 'lodash.throttle' import { search as emojiSearch } from '../components/emoji/emoji_mart_search_light'; import { urlRegex } from '../features/compose/util/url_regex' import { tagHistory } from '../settings'; @@ -133,7 +132,7 @@ export function mentionCompose(account, routerHistory) { export function handleComposeSubmit(dispatch, getState, response, status) { if (!dispatch || !getState) return; - const isScheduledStatus = response.data['scheduled_at'] !== undefined; + const isScheduledStatus = response.data.scheduled_at !== undefined; if (isScheduledStatus) { // dispatch(showAlertForError({ // response: { @@ -154,7 +153,7 @@ export function handleComposeSubmit(dispatch, getState, response, status) { const timeline = getState().getIn(['timelines', timelineId]); if (timeline && timeline.get('items').size > 0 && timeline.getIn(['items', 0]) !== null && timeline.get('online')) { - let dequeueArgs = {}; + const dequeueArgs = {}; if (timelineId === 'community') dequeueArgs.onlyMedia = getState().getIn(['settings', 'community', 'other', 'onlyMedia']); dispatch(dequeueTimeline(timelineId, null, dequeueArgs)); dispatch(updateTimeline(timelineId, { ...response.data })); @@ -174,19 +173,19 @@ export function submitCompose(routerHistory, group) { if (!me) return; let status = getState().getIn(['compose', 'text'], ''); - let statusMarkdown = getState().getIn(['compose', 'text_markdown'], ''); + const statusMarkdown = getState().getIn(['compose', 'text_markdown'], ''); const media = getState().getIn(['compose', 'media_attachments']); - // : hack : + // : hack : //Prepend http:// to urls in status that don't have protocol status = status.replace(urlRegex, (match) =>{ const hasProtocol = match.startsWith('https://') || match.startsWith('http://') return hasProtocol ? match : `http://${match}` }) - statusMarkdown = statusMarkdown.replace(urlRegex, (match) =>{ - const hasProtocol = match.startsWith('https://') || match.startsWith('http://') - return hasProtocol ? match : `http://${match}` - }) + // statusMarkdown = statusMarkdown.replace(urlRegex, (match) =>{ + // const hasProtocol = match.startsWith('https://') || match.startsWith('http://') + // return hasProtocol ? match : `http://${match}` + // }) dispatch(submitComposeRequest()); dispatch(closeModal()); @@ -197,12 +196,13 @@ export function submitCompose(routerHistory, group) { : `/api/v1/statuses/${id}`; const method = id === null ? 'post' : 'put'; - let scheduled_at = getState().getIn(['compose', 'scheduled_at'], null); - if (scheduled_at !== null) scheduled_at = moment.utc(scheduled_at).toDate(); + const scheduled_at = getState().getIn(['compose', 'scheduled_at'], null); + // : todo : + // if (scheduled_at !== null) scheduled_at = moment.utc(scheduled_at).toDate(); api(getState)[method](endpoint, { status, - statusMarkdown, + // statusMarkdown, scheduled_at, in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null), quote_of_id: getState().getIn(['compose', 'quote_of_id'], null), diff --git a/app/javascript/gabsocial/actions/notifications.js b/app/javascript/gabsocial/actions/notifications.js index 655bce69..7e7ad7da 100644 --- a/app/javascript/gabsocial/actions/notifications.js +++ b/app/javascript/gabsocial/actions/notifications.js @@ -16,7 +16,6 @@ import { me } from '../initial_state'; export const NOTIFICATIONS_INITIALIZE = 'NOTIFICATIONS_INITIALIZE'; export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE'; -export const NOTIFICATIONS_UPDATE_NOOP = 'NOTIFICATIONS_UPDATE_NOOP'; export const NOTIFICATIONS_UPDATE_QUEUE = 'NOTIFICATIONS_UPDATE_QUEUE'; export const NOTIFICATIONS_DEQUEUE = 'NOTIFICATIONS_DEQUEUE'; @@ -76,7 +75,6 @@ export function updateNotificationsQueue(notification, intlMessages, intlLocale, return (dispatch, getState) => { const showAlert = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true); const filters = getFilters(getState(), { contextType: 'notifications' }); - const playSound = getState().getIn(['settings', 'notifications', 'sounds', notification.type], true); let filtered = false; @@ -101,13 +99,6 @@ export function updateNotificationsQueue(notification, intlMessages, intlLocale, }); } - if (playSound && !filtered) { - dispatch({ - type: NOTIFICATIONS_UPDATE_NOOP, - meta: { sound: 'ribbit' }, - }); - } - if (isOnNotificationsPage) { dispatch({ type: NOTIFICATIONS_UPDATE_QUEUE, @@ -115,8 +106,7 @@ export function updateNotificationsQueue(notification, intlMessages, intlLocale, intlMessages, intlLocale, }); - } - else { + } else { dispatch(updateNotifications(notification, intlMessages, intlLocale)); } } @@ -127,15 +117,13 @@ export function dequeueNotifications() { const queuedNotifications = getState().getIn(['notifications', 'queuedNotifications'], ImmutableList()); const totalQueuedNotificationsCount = getState().getIn(['notifications', 'totalQueuedNotificationsCount'], 0); - if (totalQueuedNotificationsCount == 0) { + if (totalQueuedNotificationsCount === 0) { return; - } - else if (totalQueuedNotificationsCount > 0 && totalQueuedNotificationsCount <= MAX_QUEUED_NOTIFICATIONS) { + } else if (totalQueuedNotificationsCount > 0 && totalQueuedNotificationsCount <= MAX_QUEUED_NOTIFICATIONS) { queuedNotifications.forEach(block => { dispatch(updateNotifications(block.notification, block.intlMessages, block.intlLocale)); }); - } - else { + } else { dispatch(expandNotifications()); } @@ -167,10 +155,10 @@ export function expandNotifications({ maxId } = {}, done = noOp) { done(); return; } - - console.log("activeFilter:", activeFilter) - console.log("excludeTypesFromSettings(getState()):", excludeTypesFromSettings(getState())) - console.log("excludeTypesFromFilter(activeFilter):", excludeTypesFromFilter(activeFilter)) + + console.log('activeFilter:', activeFilter) + console.log('excludeTypesFromSettings(getState()):', excludeTypesFromSettings(getState())) + console.log('excludeTypesFromFilter(activeFilter):', excludeTypesFromFilter(activeFilter)) // : todo : // filter verified and following here too @@ -268,7 +256,7 @@ export function markReadNotifications() { const last_read = getState().getIn(['notifications', 'lastRead']); if (top_notification && top_notification > last_read) { - api(getState).post('/api/v1/notifications/mark_read', {id: top_notification}).then(response => { + api(getState).post('/api/v1/notifications/mark_read', { id: top_notification }).then(response => { dispatch({ type: NOTIFICATIONS_MARK_READ, notification: top_notification, diff --git a/app/javascript/gabsocial/actions/settings.js b/app/javascript/gabsocial/actions/settings.js index c4ad0662..5a6fccfb 100644 --- a/app/javascript/gabsocial/actions/settings.js +++ b/app/javascript/gabsocial/actions/settings.js @@ -1,5 +1,5 @@ import api from '../api'; -import { debounce } from 'lodash'; +import debounce from 'lodash.debounce'; // import { showAlertForError } from './alerts'; import { me } from '../initial_state'; diff --git a/app/javascript/gabsocial/actions/tenor.js b/app/javascript/gabsocial/actions/tenor.js index 1bb2ad76..7b9fd53a 100644 --- a/app/javascript/gabsocial/actions/tenor.js +++ b/app/javascript/gabsocial/actions/tenor.js @@ -29,7 +29,7 @@ export const fetchGifCategories = () => { } } -export const fetchGifResults = () => { +export const fetchGifResults = (maxId) => { return function (dispatch, getState) { if (!me) return @@ -38,12 +38,12 @@ export const fetchGifResults = () => { const searchText = getState().getIn(['tenor', 'searchText'], ''); axios.get(`https://api.tenor.com/v1/search?q=${searchText}&media_filter=minimal&limit=30&key=${tenorkey}`) - .then((response) => { - console.log("response:", response) - dispatch(fetchGifResultsSuccess(response.data.results)) - }).catch(function (error) { - dispatch(fetchGifResultsFail(error)) - }) + .then((response) => { + console.log('response:', response) + dispatch(fetchGifResultsSuccess(response.data.results)) + }).catch(function (error) { + dispatch(fetchGifResultsFail(error)) + }) } } diff --git a/app/javascript/gabsocial/actions/timelines.js b/app/javascript/gabsocial/actions/timelines.js index 5f0a4e05..4313580e 100644 --- a/app/javascript/gabsocial/actions/timelines.js +++ b/app/javascript/gabsocial/actions/timelines.js @@ -55,29 +55,24 @@ export function dequeueTimeline(timeline, expandFunc, optionalExpandArgs) { let shouldDispatchDequeue = true; - if (totalQueuedItemsCount == 0) { + if (totalQueuedItemsCount === 0) { return; - } - else if (totalQueuedItemsCount > 0 && totalQueuedItemsCount <= MAX_QUEUED_ITEMS) { + } else if (totalQueuedItemsCount > 0 && totalQueuedItemsCount <= MAX_QUEUED_ITEMS) { queuedItems.forEach(status => { dispatch(updateTimeline(timeline, status.toJS(), null)); }); - } - else { + } else { if (typeof expandFunc === 'function') { dispatch(clearTimeline(timeline)); expandFunc(); - } - else { + } else { if (timeline === 'home') { dispatch(clearTimeline(timeline)); dispatch(expandHomeTimeline(optionalExpandArgs)); - } - else if (timeline === 'community') { + } else if (timeline === 'community') { dispatch(clearTimeline(timeline)); dispatch(expandCommunityTimeline(optionalExpandArgs)); - } - else { + } else { shouldDispatchDequeue = false; } } diff --git a/app/javascript/gabsocial/api.js b/app/javascript/gabsocial/api.js index 6781b907..9d07fbaa 100644 --- a/app/javascript/gabsocial/api.js +++ b/app/javascript/gabsocial/api.js @@ -14,7 +14,7 @@ export const getLinks = response => { return LinkHeader.parse(value); }; -let csrfHeader = {}; +const csrfHeader = {}; function setCSRFHeader() { const csrfToken = document.querySelector('meta[name=csrf-token]'); diff --git a/app/javascript/gabsocial/assets/hidden_icon.js b/app/javascript/gabsocial/assets/hidden_icon.js new file mode 100644 index 00000000..5e60d5da --- /dev/null +++ b/app/javascript/gabsocial/assets/hidden_icon.js @@ -0,0 +1,28 @@ +const HiddenIcon = ({ + className = '', + width = '16px', + height = '16px', + viewBox = '0 0 48 48', + title = 'Hidden', +}) => ( + + + + + + + +) + +export default HiddenIcon \ No newline at end of file diff --git a/app/javascript/gabsocial/components/account.js b/app/javascript/gabsocial/components/account.js index c3ab12bc..3b5374d6 100644 --- a/app/javascript/gabsocial/components/account.js +++ b/app/javascript/gabsocial/components/account.js @@ -93,6 +93,7 @@ class Account extends ImmutablePureComponent { ) } + // : todo : cleanup let buttonOptions let buttonText diff --git a/app/javascript/gabsocial/components/autosuggest_emoji/autosuggest_emoji.js b/app/javascript/gabsocial/components/autosuggest_emoji/autosuggest_emoji.js index 6d08233c..a8ced018 100644 --- a/app/javascript/gabsocial/components/autosuggest_emoji/autosuggest_emoji.js +++ b/app/javascript/gabsocial/components/autosuggest_emoji/autosuggest_emoji.js @@ -1,25 +1,25 @@ -import unicodeMapping from '../emoji/emoji_unicode_mapping_light'; +import unicodeMapping from '../emoji/emoji_unicode_mapping_light' -const assetHost = process.env.CDN_HOST || ''; +const assetHost = process.env.CDN_HOST || '' export default class AutosuggestEmoji extends PureComponent { static propTypes = { emoji: PropTypes.object.isRequired, - }; + } render () { - const { emoji } = this.props; - let url; + const { emoji } = this.props + let url if (emoji.custom) { - url = emoji.imageUrl; + url = emoji.imageUrl } else { - const mapping = unicodeMapping[emoji.native] || unicodeMapping[emoji.native.replace(/\uFE0F$/, '')]; + const mapping = unicodeMapping[emoji.native] || unicodeMapping[emoji.native.replace(/\uFE0F$/, '')] - if (!mapping) return null; + if (!mapping) return null - url = `${assetHost}/emoji/${mapping.filename}.svg`; + url = `${assetHost}/emoji/${mapping.filename}.svg` } return ( @@ -27,7 +27,7 @@ export default class AutosuggestEmoji extends PureComponent { {emoji.native {emoji.colons} - ); + ) } } diff --git a/app/javascript/gabsocial/components/autosuggest_textbox/autosuggest_textbox.js b/app/javascript/gabsocial/components/autosuggest_textbox/autosuggest_textbox.js index bab2e51e..3006fcd2 100644 --- a/app/javascript/gabsocial/components/autosuggest_textbox/autosuggest_textbox.js +++ b/app/javascript/gabsocial/components/autosuggest_textbox/autosuggest_textbox.js @@ -2,8 +2,6 @@ import { Fragment } from 'react' import ImmutablePropTypes from 'react-immutable-proptypes' import classNames from 'classnames/bind' import ImmutablePureComponent from 'react-immutable-pure-component' -import Textarea from 'react-textarea-autosize' -import ContentEditable from 'react-contenteditable' import { isRtl } from '../../utils/rtl' import { textAtCursorMatchesToken } from '../../utils/cursor_token_match' import AutosuggestAccount from '../autosuggest_account' @@ -83,39 +81,39 @@ export default class AutosuggestTextbox extends ImmutablePureComponent { if (e.which === 229 || e.isComposing) return; switch (e.key) { - case 'Escape': - if (suggestions.size === 0 || suggestionsHidden) { - document.querySelector('.ui').parentElement.focus(); - } else { - e.preventDefault(); - this.setState({ suggestionsHidden: true }); - } + case 'Escape': + if (suggestions.size === 0 || suggestionsHidden) { + document.querySelector('.ui').parentElement.focus(); + } else { + e.preventDefault(); + this.setState({ suggestionsHidden: true }); + } - break; - case 'ArrowDown': - if (suggestions.size > 0 && !suggestionsHidden) { - e.preventDefault(); - this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) }); - } + break; + case 'ArrowDown': + if (suggestions.size > 0 && !suggestionsHidden) { + e.preventDefault(); + this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) }); + } - break; - case 'ArrowUp': - if (suggestions.size > 0 && !suggestionsHidden) { - e.preventDefault(); - this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) }); - } + break; + case 'ArrowUp': + if (suggestions.size > 0 && !suggestionsHidden) { + e.preventDefault(); + this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) }); + } - break; - case 'Enter': - case 'Tab': - // Select suggestion - if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) { - e.preventDefault(); - e.stopPropagation(); - this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion)); - } + break; + case 'Enter': + case 'Tab': + // Select suggestion + if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) { + e.preventDefault(); + e.stopPropagation(); + this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion)); + } - break; + break; } if (e.defaultPrevented || !this.props.onKeyDown) return; @@ -210,7 +208,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent { id, maxLength, textarea, - prependIcon + prependIcon, } = this.props const { suggestionsHidden } = this.state @@ -270,7 +268,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent { onPaste={this.onPaste} aria-autocomplete='list' /> */ } - + { /*