commit
7f6315841c
|
@ -3,8 +3,8 @@ FROM ubuntu:18.04 as build-dep
|
||||||
# Use bash for the shell
|
# Use bash for the shell
|
||||||
SHELL ["bash", "-c"]
|
SHELL ["bash", "-c"]
|
||||||
|
|
||||||
# Install Node
|
# Install Node v12 (LTS)
|
||||||
ENV NODE_VER="12.11.1"
|
ENV NODE_VER="12.13.1"
|
||||||
RUN echo "Etc/UTC" > /etc/localtime && \
|
RUN echo "Etc/UTC" > /etc/localtime && \
|
||||||
apt update && \
|
apt update && \
|
||||||
apt -y install wget python && \
|
apt -y install wget python && \
|
||||||
|
|
10
Gemfile
10
Gemfile
|
@ -12,7 +12,7 @@ gem 'thor', '~> 0.20'
|
||||||
gem 'hamlit-rails', '~> 0.2'
|
gem 'hamlit-rails', '~> 0.2'
|
||||||
gem 'pg', '~> 1.1'
|
gem 'pg', '~> 1.1'
|
||||||
gem 'makara', '~> 0.4'
|
gem 'makara', '~> 0.4'
|
||||||
gem 'pghero', '~> 2.3'
|
gem 'pghero', '~> 2.4'
|
||||||
gem 'dotenv-rails', '~> 2.7'
|
gem 'dotenv-rails', '~> 2.7'
|
||||||
|
|
||||||
gem 'aws-sdk-s3', '~> 1.55', require: false
|
gem 'aws-sdk-s3', '~> 1.55', require: false
|
||||||
|
@ -27,7 +27,7 @@ gem 'active_model_serializers', '~> 0.10'
|
||||||
gem 'addressable', '~> 2.7'
|
gem 'addressable', '~> 2.7'
|
||||||
gem 'bootsnap', '~> 1.4', require: false
|
gem 'bootsnap', '~> 1.4', require: false
|
||||||
gem 'browser'
|
gem 'browser'
|
||||||
gem 'charlock_holmes', '~> 0.7.6'
|
gem 'charlock_holmes', '~> 0.7.7'
|
||||||
gem 'iso-639'
|
gem 'iso-639'
|
||||||
gem 'chewy', '~> 5.1'
|
gem 'chewy', '~> 5.1'
|
||||||
gem 'cld3', '~> 3.2.4'
|
gem 'cld3', '~> 3.2.4'
|
||||||
|
@ -38,7 +38,7 @@ group :pam_authentication, optional: true do
|
||||||
gem 'devise_pam_authenticatable2', '~> 9.2'
|
gem 'devise_pam_authenticatable2', '~> 9.2'
|
||||||
end
|
end
|
||||||
|
|
||||||
gem 'net-ldap', '~> 0.10'
|
gem 'net-ldap', '~> 0.16'
|
||||||
gem 'omniauth-cas', '~> 1.1'
|
gem 'omniauth-cas', '~> 1.1'
|
||||||
gem 'omniauth-saml', '~> 1.10'
|
gem 'omniauth-saml', '~> 1.10'
|
||||||
gem 'omniauth', '~> 1.9'
|
gem 'omniauth', '~> 1.9'
|
||||||
|
@ -68,12 +68,12 @@ gem 'oj', '~> 3.9'
|
||||||
gem 'ostatus2', '~> 2.0'
|
gem 'ostatus2', '~> 2.0'
|
||||||
gem 'ox', '~> 2.11'
|
gem 'ox', '~> 2.11'
|
||||||
gem 'parslet'
|
gem 'parslet'
|
||||||
gem 'parallel', '~> 1.18'
|
gem 'parallel', '~> 1.19'
|
||||||
gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
|
gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
|
||||||
gem 'pundit', '~> 2.1'
|
gem 'pundit', '~> 2.1'
|
||||||
gem 'premailer-rails'
|
gem 'premailer-rails'
|
||||||
gem 'rack-attack', '~> 6.2'
|
gem 'rack-attack', '~> 6.2'
|
||||||
gem 'rack-cors', '~> 1.0', require: 'rack/cors'
|
gem 'rack-cors', '~> 1.1', require: 'rack/cors'
|
||||||
gem 'rails-i18n', '~> 5.1'
|
gem 'rails-i18n', '~> 5.1'
|
||||||
gem 'rails-settings-cached', '~> 0.6'
|
gem 'rails-settings-cached', '~> 0.6'
|
||||||
gem 'redis', '~> 4.1', require: ['redis', 'redis/connection/hiredis']
|
gem 'redis', '~> 4.1', require: ['redis', 'redis/connection/hiredis']
|
||||||
|
|
24
Gemfile.lock
24
Gemfile.lock
|
@ -133,7 +133,7 @@ GEM
|
||||||
bootsnap (1.4.5)
|
bootsnap (1.4.5)
|
||||||
msgpack (~> 1.0)
|
msgpack (~> 1.0)
|
||||||
brakeman (4.7.1)
|
brakeman (4.7.1)
|
||||||
browser (2.6.1)
|
browser (2.7.1)
|
||||||
builder (3.2.3)
|
builder (3.2.3)
|
||||||
bullet (6.0.2)
|
bullet (6.0.2)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
|
@ -168,7 +168,7 @@ GEM
|
||||||
xpath (~> 3.2)
|
xpath (~> 3.2)
|
||||||
case_transform (0.2)
|
case_transform (0.2)
|
||||||
activesupport
|
activesupport
|
||||||
charlock_holmes (0.7.6)
|
charlock_holmes (0.7.7)
|
||||||
chewy (5.1.0)
|
chewy (5.1.0)
|
||||||
activesupport (>= 4.0)
|
activesupport (>= 4.0)
|
||||||
elasticsearch (>= 2.0.0)
|
elasticsearch (>= 2.0.0)
|
||||||
|
@ -385,7 +385,7 @@ GEM
|
||||||
multi_json (1.13.1)
|
multi_json (1.13.1)
|
||||||
multipart-post (2.1.1)
|
multipart-post (2.1.1)
|
||||||
necromancer (0.5.0)
|
necromancer (0.5.0)
|
||||||
net-ldap (0.16.1)
|
net-ldap (0.16.2)
|
||||||
net-scp (2.0.0)
|
net-scp (2.0.0)
|
||||||
net-ssh (>= 2.6.5, < 6.0.0)
|
net-ssh (>= 2.6.5, < 6.0.0)
|
||||||
net-ssh (5.2.0)
|
net-ssh (5.2.0)
|
||||||
|
@ -425,7 +425,7 @@ GEM
|
||||||
paperclip-av-transcoder (0.6.4)
|
paperclip-av-transcoder (0.6.4)
|
||||||
av (~> 0.9.0)
|
av (~> 0.9.0)
|
||||||
paperclip (>= 2.5.2)
|
paperclip (>= 2.5.2)
|
||||||
parallel (1.18.0)
|
parallel (1.19.1)
|
||||||
parallel_tests (2.29.2)
|
parallel_tests (2.29.2)
|
||||||
parallel
|
parallel
|
||||||
parser (2.6.5.0)
|
parser (2.6.5.0)
|
||||||
|
@ -435,7 +435,7 @@ GEM
|
||||||
equatable (~> 0.6)
|
equatable (~> 0.6)
|
||||||
tty-color (~> 0.5)
|
tty-color (~> 0.5)
|
||||||
pg (1.1.4)
|
pg (1.1.4)
|
||||||
pghero (2.3.0)
|
pghero (2.4.1)
|
||||||
activerecord (>= 5)
|
activerecord (>= 5)
|
||||||
pkg-config (1.4.0)
|
pkg-config (1.4.0)
|
||||||
premailer (1.11.1)
|
premailer (1.11.1)
|
||||||
|
@ -463,8 +463,8 @@ GEM
|
||||||
rack (2.0.7)
|
rack (2.0.7)
|
||||||
rack-attack (6.2.1)
|
rack-attack (6.2.1)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rack-cors (1.0.6)
|
rack-cors (1.1.0)
|
||||||
rack (>= 1.6.0)
|
rack (>= 2.0.0)
|
||||||
rack-protection (2.0.7)
|
rack-protection (2.0.7)
|
||||||
rack
|
rack
|
||||||
rack-proxy (0.6.5)
|
rack-proxy (0.6.5)
|
||||||
|
@ -699,7 +699,7 @@ DEPENDENCIES
|
||||||
capistrano-rbenv (~> 2.1)
|
capistrano-rbenv (~> 2.1)
|
||||||
capistrano-yarn (~> 2.0)
|
capistrano-yarn (~> 2.0)
|
||||||
capybara (~> 3.29)
|
capybara (~> 3.29)
|
||||||
charlock_holmes (~> 0.7.6)
|
charlock_holmes (~> 0.7.7)
|
||||||
chewy (~> 5.1)
|
chewy (~> 5.1)
|
||||||
cld3 (~> 3.2.4)
|
cld3 (~> 3.2.4)
|
||||||
climate_control (~> 0.2)
|
climate_control (~> 0.2)
|
||||||
|
@ -744,7 +744,7 @@ DEPENDENCIES
|
||||||
memory_profiler
|
memory_profiler
|
||||||
microformats (~> 4.1)
|
microformats (~> 4.1)
|
||||||
mime-types (~> 3.3)
|
mime-types (~> 3.3)
|
||||||
net-ldap (~> 0.10)
|
net-ldap (~> 0.16)
|
||||||
nilsimsa!
|
nilsimsa!
|
||||||
nokogiri (~> 1.10)
|
nokogiri (~> 1.10)
|
||||||
nsa (~> 0.2)
|
nsa (~> 0.2)
|
||||||
|
@ -756,11 +756,11 @@ DEPENDENCIES
|
||||||
ox (~> 2.11)
|
ox (~> 2.11)
|
||||||
paperclip (~> 6.0)
|
paperclip (~> 6.0)
|
||||||
paperclip-av-transcoder (~> 0.6)
|
paperclip-av-transcoder (~> 0.6)
|
||||||
parallel (~> 1.18)
|
parallel (~> 1.19)
|
||||||
parallel_tests (~> 2.29)
|
parallel_tests (~> 2.29)
|
||||||
parslet
|
parslet
|
||||||
pg (~> 1.1)
|
pg (~> 1.1)
|
||||||
pghero (~> 2.3)
|
pghero (~> 2.4)
|
||||||
pkg-config (~> 1.4)
|
pkg-config (~> 1.4)
|
||||||
posix-spawn!
|
posix-spawn!
|
||||||
premailer-rails
|
premailer-rails
|
||||||
|
@ -770,7 +770,7 @@ DEPENDENCIES
|
||||||
puma (~> 4.2)
|
puma (~> 4.2)
|
||||||
pundit (~> 2.1)
|
pundit (~> 2.1)
|
||||||
rack-attack (~> 6.2)
|
rack-attack (~> 6.2)
|
||||||
rack-cors (~> 1.0)
|
rack-cors (~> 1.1)
|
||||||
rails (~> 5.2.3)
|
rails (~> 5.2.3)
|
||||||
rails-controller-testing (~> 1.0)
|
rails-controller-testing (~> 1.0)
|
||||||
rails-i18n (~> 5.1)
|
rails-i18n (~> 5.1)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
class Api::ProofsController < Api::BaseController
|
class Api::ProofsController < Api::BaseController
|
||||||
include AccountOwnedConcern
|
include AccountOwnedConcern
|
||||||
|
|
||||||
|
skip_before_action :require_authenticated_user!
|
||||||
|
|
||||||
before_action :set_provider
|
before_action :set_provider
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -263,7 +263,7 @@ export function uploadCompose(files) {
|
||||||
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
|
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
|
||||||
},
|
},
|
||||||
}).then(({ data }) => dispatch(uploadComposeSuccess(data, f)));
|
}).then(({ data }) => dispatch(uploadComposeSuccess(data, f)));
|
||||||
}).catch(error => dispatch(uploadComposeFail(error, true)));
|
}).catch(error => dispatch(uploadComposeFail(error)));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -294,11 +294,10 @@ export function changeUploadComposeSuccess(media) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function changeUploadComposeFail(error, decrement = false) {
|
export function changeUploadComposeFail(error) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_UPLOAD_CHANGE_FAIL,
|
type: COMPOSE_UPLOAD_CHANGE_FAIL,
|
||||||
error: error,
|
error: error,
|
||||||
decrement: decrement,
|
|
||||||
skipLoading: true,
|
skipLoading: true,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -376,6 +376,22 @@ class Status extends ImmutablePureComponent {
|
||||||
this.props.onOpenVideo(media, startTime);
|
this.props.onOpenVideo(media, startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleHotkeyOpenMedia = e => {
|
||||||
|
const { status, onOpenMedia, onOpenVideo } = this.props;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (status.get('media_attachments').size > 0) {
|
||||||
|
if (status.getIn(['media_attachments', 0, 'type']) === 'audio') {
|
||||||
|
// TODO: toggle play/paused?
|
||||||
|
} else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
||||||
|
onOpenVideo(status.getIn(['media_attachments', 0]), 0);
|
||||||
|
} else {
|
||||||
|
onOpenMedia(status.get('media_attachments'), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleHotkeyReply = e => {
|
handleHotkeyReply = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.onReply(this.props.status, this.context.router.history);
|
this.props.onReply(this.props.status, this.context.router.history);
|
||||||
|
@ -503,6 +519,7 @@ class Status extends ImmutablePureComponent {
|
||||||
bookmark: this.handleHotkeyBookmark,
|
bookmark: this.handleHotkeyBookmark,
|
||||||
toggleCollapse: this.handleHotkeyCollapse,
|
toggleCollapse: this.handleHotkeyCollapse,
|
||||||
toggleSensitive: this.handleHotkeyToggleSensitive,
|
toggleSensitive: this.handleHotkeyToggleSensitive,
|
||||||
|
openMedia: this.handleHotkeyOpenMedia,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
|
|
|
@ -67,6 +67,10 @@ class KeyboardShortcuts extends ImmutablePureComponent {
|
||||||
<td><kbd>enter</kbd>, <kbd>o</kbd></td>
|
<td><kbd>enter</kbd>, <kbd>o</kbd></td>
|
||||||
<td><FormattedMessage id='keyboard_shortcuts.enter' defaultMessage='to open status' /></td>
|
<td><FormattedMessage id='keyboard_shortcuts.enter' defaultMessage='to open status' /></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><kbd>e</kbd></td>
|
||||||
|
<td><FormattedMessage id='keyboard_shortcuts.open_media' defaultMessage='to open media' /></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><kbd>x</kbd></td>
|
<td><kbd>x</kbd></td>
|
||||||
<td><FormattedMessage id='keyboard_shortcuts.toggle_hidden' defaultMessage='to show/hide text behind CW' /></td>
|
<td><FormattedMessage id='keyboard_shortcuts.toggle_hidden' defaultMessage='to show/hide text behind CW' /></td>
|
||||||
|
|
|
@ -320,6 +320,22 @@ class Status extends ImmutablePureComponent {
|
||||||
this.props.dispatch(openModal('VIDEO', { media, time }));
|
this.props.dispatch(openModal('VIDEO', { media, time }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleHotkeyOpenMedia = e => {
|
||||||
|
const { status } = this.props;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (status.get('media_attachments').size > 0) {
|
||||||
|
if (status.getIn(['media_attachments', 0, 'type']) === 'audio') {
|
||||||
|
// TODO: toggle play/paused?
|
||||||
|
} else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
||||||
|
this.handleOpenVideo(status.getIn(['media_attachments', 0]), 0);
|
||||||
|
} else {
|
||||||
|
this.handleOpenMedia(status.get('media_attachments'), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleMuteClick = (account) => {
|
handleMuteClick = (account) => {
|
||||||
this.props.dispatch(initMuteModal(account));
|
this.props.dispatch(initMuteModal(account));
|
||||||
}
|
}
|
||||||
|
@ -529,6 +545,7 @@ class Status extends ImmutablePureComponent {
|
||||||
openProfile: this.handleHotkeyOpenProfile,
|
openProfile: this.handleHotkeyOpenProfile,
|
||||||
toggleSpoiler: this.handleExpandedToggle,
|
toggleSpoiler: this.handleExpandedToggle,
|
||||||
toggleSensitive: this.handleHotkeyToggleSensitive,
|
toggleSensitive: this.handleHotkeyToggleSensitive,
|
||||||
|
openMedia: this.handleHotkeyOpenMedia,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -214,7 +214,7 @@ class FocalPointModal extends ImmutablePureComponent {
|
||||||
langPath: `${assetHost}/ocr/lang-data`,
|
langPath: `${assetHost}/ocr/lang-data`,
|
||||||
});
|
});
|
||||||
|
|
||||||
let media_url = media.get('file');
|
let media_url = media.get('url');
|
||||||
|
|
||||||
if (window.URL && URL.createObjectURL) {
|
if (window.URL && URL.createObjectURL) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -107,6 +107,7 @@ const keyMap = {
|
||||||
bookmark: 'd',
|
bookmark: 'd',
|
||||||
toggleCollapse: 'shift+x',
|
toggleCollapse: 'shift+x',
|
||||||
toggleSensitive: 'h',
|
toggleSensitive: 'h',
|
||||||
|
openMedia: 'e',
|
||||||
};
|
};
|
||||||
|
|
||||||
class SwitchingColumnsArea extends React.PureComponent {
|
class SwitchingColumnsArea extends React.PureComponent {
|
||||||
|
|
|
@ -488,7 +488,7 @@ class Video extends React.PureComponent {
|
||||||
|
|
||||||
<div className='video-player__buttons-bar'>
|
<div className='video-player__buttons-bar'>
|
||||||
<div className='video-player__buttons left'>
|
<div className='video-player__buttons left'>
|
||||||
<button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
|
<button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay} autoFocus={detailed}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
|
||||||
<button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
|
<button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
|
||||||
<div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
|
<div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
|
||||||
|
|
||||||
|
|
|
@ -429,7 +429,7 @@ export default function compose(state = initialState, action) {
|
||||||
case COMPOSE_UPLOAD_SUCCESS:
|
case COMPOSE_UPLOAD_SUCCESS:
|
||||||
return appendMedia(state, fromJS(action.media), action.file);
|
return appendMedia(state, fromJS(action.media), action.file);
|
||||||
case COMPOSE_UPLOAD_FAIL:
|
case COMPOSE_UPLOAD_FAIL:
|
||||||
return state.set('is_uploading', false).update('pending_media_attachments', n => action.decrement ? n - 1 : n);
|
return state.set('is_uploading', false).update('pending_media_attachments', n => n - 1);
|
||||||
case COMPOSE_UPLOAD_UNDO:
|
case COMPOSE_UPLOAD_UNDO:
|
||||||
return removeMedia(state, action.media_id);
|
return removeMedia(state, action.media_id);
|
||||||
case COMPOSE_UPLOAD_PROGRESS:
|
case COMPOSE_UPLOAD_PROGRESS:
|
||||||
|
|
|
@ -652,7 +652,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.counter {
|
.counter {
|
||||||
width: 33.3%;
|
min-width: 33.3%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
color: $darker-text-color;
|
color: $darker-text-color;
|
||||||
|
|
|
@ -236,7 +236,7 @@ export function uploadCompose(files) {
|
||||||
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
|
dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
|
||||||
},
|
},
|
||||||
}).then(({ data }) => dispatch(uploadComposeSuccess(data, f)));
|
}).then(({ data }) => dispatch(uploadComposeSuccess(data, f)));
|
||||||
}).catch(error => dispatch(uploadComposeFail(error, true)));
|
}).catch(error => dispatch(uploadComposeFail(error)));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -267,11 +267,10 @@ export function changeUploadComposeSuccess(media) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function changeUploadComposeFail(error, decrement = false) {
|
export function changeUploadComposeFail(error) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_UPLOAD_CHANGE_FAIL,
|
type: COMPOSE_UPLOAD_CHANGE_FAIL,
|
||||||
error: error,
|
error: error,
|
||||||
decrement: decrement,
|
|
||||||
skipLoading: true,
|
skipLoading: true,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -214,6 +214,22 @@ class Status extends ImmutablePureComponent {
|
||||||
this.props.onOpenVideo(media, startTime);
|
this.props.onOpenVideo(media, startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleHotkeyOpenMedia = e => {
|
||||||
|
const { status, onOpenMedia, onOpenVideo } = this.props;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (status.get('media_attachments').size > 0) {
|
||||||
|
if (status.getIn(['media_attachments', 0, 'type']) === 'audio') {
|
||||||
|
// TODO: toggle play/paused?
|
||||||
|
} else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
||||||
|
onOpenVideo(status.getIn(['media_attachments', 0]), 0);
|
||||||
|
} else {
|
||||||
|
onOpenMedia(status.get('media_attachments'), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleHotkeyReply = e => {
|
handleHotkeyReply = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.onReply(this._properStatus(), this.context.router.history);
|
this.props.onReply(this._properStatus(), this.context.router.history);
|
||||||
|
@ -293,6 +309,7 @@ class Status extends ImmutablePureComponent {
|
||||||
moveDown: this.handleHotkeyMoveDown,
|
moveDown: this.handleHotkeyMoveDown,
|
||||||
toggleHidden: this.handleHotkeyToggleHidden,
|
toggleHidden: this.handleHotkeyToggleHidden,
|
||||||
toggleSensitive: this.handleHotkeyToggleSensitive,
|
toggleSensitive: this.handleHotkeyToggleSensitive,
|
||||||
|
openMedia: this.handleHotkeyOpenMedia,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
|
|
|
@ -56,6 +56,10 @@ class KeyboardShortcuts extends ImmutablePureComponent {
|
||||||
<td><kbd>enter</kbd>, <kbd>o</kbd></td>
|
<td><kbd>enter</kbd>, <kbd>o</kbd></td>
|
||||||
<td><FormattedMessage id='keyboard_shortcuts.enter' defaultMessage='to open status' /></td>
|
<td><FormattedMessage id='keyboard_shortcuts.enter' defaultMessage='to open status' /></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><kbd>e</kbd></td>
|
||||||
|
<td><FormattedMessage id='keyboard_shortcuts.open_media' defaultMessage='to open media' /></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><kbd>x</kbd></td>
|
<td><kbd>x</kbd></td>
|
||||||
<td><FormattedMessage id='keyboard_shortcuts.toggle_hidden' defaultMessage='to show/hide text behind CW' /></td>
|
<td><FormattedMessage id='keyboard_shortcuts.toggle_hidden' defaultMessage='to show/hide text behind CW' /></td>
|
||||||
|
|
|
@ -281,6 +281,22 @@ class Status extends ImmutablePureComponent {
|
||||||
this.props.dispatch(openModal('VIDEO', { media, time }));
|
this.props.dispatch(openModal('VIDEO', { media, time }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleHotkeyOpenMedia = e => {
|
||||||
|
const { status } = this.props;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (status.get('media_attachments').size > 0) {
|
||||||
|
if (status.getIn(['media_attachments', 0, 'type']) === 'audio') {
|
||||||
|
// TODO: toggle play/paused?
|
||||||
|
} else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
||||||
|
this.handleOpenVideo(status.getIn(['media_attachments', 0]), 0);
|
||||||
|
} else {
|
||||||
|
this.handleOpenMedia(status.get('media_attachments'), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleMuteClick = (account) => {
|
handleMuteClick = (account) => {
|
||||||
this.props.dispatch(initMuteModal(account));
|
this.props.dispatch(initMuteModal(account));
|
||||||
}
|
}
|
||||||
|
@ -506,6 +522,7 @@ class Status extends ImmutablePureComponent {
|
||||||
openProfile: this.handleHotkeyOpenProfile,
|
openProfile: this.handleHotkeyOpenProfile,
|
||||||
toggleHidden: this.handleHotkeyToggleHidden,
|
toggleHidden: this.handleHotkeyToggleHidden,
|
||||||
toggleSensitive: this.handleHotkeyToggleSensitive,
|
toggleSensitive: this.handleHotkeyToggleSensitive,
|
||||||
|
openMedia: this.handleHotkeyOpenMedia,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -214,7 +214,7 @@ class FocalPointModal extends ImmutablePureComponent {
|
||||||
langPath: `${assetHost}/ocr/lang-data`,
|
langPath: `${assetHost}/ocr/lang-data`,
|
||||||
});
|
});
|
||||||
|
|
||||||
let media_url = media.get('file');
|
let media_url = media.get('url');
|
||||||
|
|
||||||
if (window.URL && URL.createObjectURL) {
|
if (window.URL && URL.createObjectURL) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -100,6 +100,7 @@ const keyMap = {
|
||||||
goToRequests: 'g r',
|
goToRequests: 'g r',
|
||||||
toggleHidden: 'x',
|
toggleHidden: 'x',
|
||||||
toggleSensitive: 'h',
|
toggleSensitive: 'h',
|
||||||
|
openMedia: 'e',
|
||||||
};
|
};
|
||||||
|
|
||||||
class SwitchingColumnsArea extends React.PureComponent {
|
class SwitchingColumnsArea extends React.PureComponent {
|
||||||
|
|
|
@ -467,7 +467,7 @@ class Video extends React.PureComponent {
|
||||||
|
|
||||||
<div className='video-player__buttons-bar'>
|
<div className='video-player__buttons-bar'>
|
||||||
<div className='video-player__buttons left'>
|
<div className='video-player__buttons left'>
|
||||||
<button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
|
<button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay} autoFocus={detailed}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
|
||||||
<button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
|
<button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
|
||||||
|
|
||||||
<div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
|
<div className='video-player__volume' onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
|
||||||
|
|
|
@ -328,7 +328,7 @@ export default function compose(state = initialState, action) {
|
||||||
case COMPOSE_UPLOAD_SUCCESS:
|
case COMPOSE_UPLOAD_SUCCESS:
|
||||||
return appendMedia(state, fromJS(action.media), action.file);
|
return appendMedia(state, fromJS(action.media), action.file);
|
||||||
case COMPOSE_UPLOAD_FAIL:
|
case COMPOSE_UPLOAD_FAIL:
|
||||||
return state.set('is_uploading', false).update('pending_media_attachments', n => action.decrement ? n - 1 : n);
|
return state.set('is_uploading', false).update('pending_media_attachments', n => n - 1);
|
||||||
case COMPOSE_UPLOAD_UNDO:
|
case COMPOSE_UPLOAD_UNDO:
|
||||||
return removeMedia(state, action.media_id);
|
return removeMedia(state, action.media_id);
|
||||||
case COMPOSE_UPLOAD_PROGRESS:
|
case COMPOSE_UPLOAD_PROGRESS:
|
||||||
|
|
|
@ -646,7 +646,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.counter {
|
.counter {
|
||||||
width: 33.3%;
|
min-width: 33.3%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
color: $darker-text-color;
|
color: $darker-text-color;
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class StatusRelationshipsPresenter
|
class StatusRelationshipsPresenter
|
||||||
attr_reader :reblogs_map, :favourites_map, :mutes_map, :pins_map
|
attr_reader :reblogs_map, :favourites_map, :mutes_map, :pins_map,
|
||||||
|
:bookmarks_map
|
||||||
|
|
||||||
def initialize(statuses, current_account_id = nil, **options)
|
def initialize(statuses, current_account_id = nil, **options)
|
||||||
if current_account_id.nil?
|
if current_account_id.nil?
|
||||||
|
|
|
@ -97,8 +97,8 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def bookmarked
|
def bookmarked
|
||||||
if instance_options && instance_options[:bookmarks]
|
if instance_options && instance_options[:relationships]
|
||||||
instance_options[:bookmarks].bookmarks_map[object.id] || false
|
instance_options[:relationships].bookmarks_map[object.id] || false
|
||||||
else
|
else
|
||||||
current_user.account.bookmarked?(object)
|
current_user.account.bookmarked?(object)
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,7 +30,7 @@ class ActivityPub::ProcessPollService < BaseService
|
||||||
|
|
||||||
voters_count = @json['votersCount']
|
voters_count = @json['votersCount']
|
||||||
|
|
||||||
latest_options = items.map { |item| item['name'].presence || item['content'] }
|
latest_options = items.map { |item| item['name'].presence || item['content'] }.compact
|
||||||
|
|
||||||
# If for some reasons the options were changed, it invalidates all previous
|
# If for some reasons the options were changed, it invalidates all previous
|
||||||
# votes, so we need to remove them
|
# votes, so we need to remove them
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
= simple_form_for current_user, url: settings_preferences_notifications_path, html: { method: :put } do |f|
|
= simple_form_for current_user, url: settings_preferences_notifications_path, html: { method: :put } do |f|
|
||||||
= render 'shared/error_messages', object: current_user
|
= render 'shared/error_messages', object: current_user
|
||||||
|
|
||||||
|
%h4= t('notifications.email_events')
|
||||||
|
|
||||||
|
%p.hint = t('notifications.email_events_hint')
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff|
|
= f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff|
|
||||||
= ff.input :follow, as: :boolean, wrapper: :with_label
|
= ff.input :follow, as: :boolean, wrapper: :with_label
|
||||||
|
@ -21,6 +25,8 @@
|
||||||
= f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff|
|
= f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff|
|
||||||
= ff.input :digest, as: :boolean, wrapper: :with_label
|
= ff.input :digest, as: :boolean, wrapper: :with_label
|
||||||
|
|
||||||
|
%h4 = t('notifications.other_settings')
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.simple_fields_for :interactions, hash_to_object(current_user.settings.interactions) do |ff|
|
= f.simple_fields_for :interactions, hash_to_object(current_user.settings.interactions) do |ff|
|
||||||
= ff.input :must_be_follower, as: :boolean, wrapper: :with_label
|
= ff.input :must_be_follower, as: :boolean, wrapper: :with_label
|
||||||
|
|
|
@ -900,6 +900,10 @@ en:
|
||||||
body: 'Your status was boosted by %{name}:'
|
body: 'Your status was boosted by %{name}:'
|
||||||
subject: "%{name} boosted your status"
|
subject: "%{name} boosted your status"
|
||||||
title: New boost
|
title: New boost
|
||||||
|
notifications:
|
||||||
|
email_events: Events for e-mail notifications
|
||||||
|
email_events_hint: 'Select events that you want to receive notifications for:'
|
||||||
|
other_settings: Other notifications settings
|
||||||
number:
|
number:
|
||||||
human:
|
human:
|
||||||
decimal_units:
|
decimal_units:
|
||||||
|
|
|
@ -163,14 +163,14 @@ en:
|
||||||
text: Why do you want to join?
|
text: Why do you want to join?
|
||||||
notification_emails:
|
notification_emails:
|
||||||
digest: Send digest e-mails
|
digest: Send digest e-mails
|
||||||
favourite: Send e-mail when someone favourites your status
|
favourite: Someone favourited your status
|
||||||
follow: Send e-mail when someone follows you
|
follow: Someone followed you
|
||||||
follow_request: Send e-mail when someone requests to follow you
|
follow_request: Someone requested to follow you
|
||||||
mention: Send e-mail when someone mentions you
|
mention: Someone mentioned you
|
||||||
pending_account: Send e-mail when a new account needs review
|
pending_account: New account needs review
|
||||||
reblog: Send e-mail when someone boosts your status
|
reblog: Someone boosted your status
|
||||||
report: Send e-mail when a new report is submitted
|
report: New report is submitted
|
||||||
trending_tag: Send e-mail when an unreviewed hashtag is trending
|
trending_tag: An unreviewed hashtag is trending
|
||||||
tag:
|
tag:
|
||||||
listable: Allow this hashtag to appear in searches and on the profile directory
|
listable: Allow this hashtag to appear in searches and on the profile directory
|
||||||
name: Hashtag
|
name: Hashtag
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
databases:
|
||||||
|
primary:
|
||||||
|
# Database URL (defaults to app database)
|
||||||
|
# url: <%= ENV["DATABASE_URL"] %>
|
||||||
|
|
||||||
|
# Add more databases
|
||||||
|
# other:
|
||||||
|
# url: <%= ENV["OTHER_DATABASE_URL"] %>
|
||||||
|
|
||||||
|
# Minimum time for long running queries
|
||||||
|
# long_running_query_sec: 60
|
||||||
|
|
||||||
|
# Minimum average time for slow queries
|
||||||
|
# slow_query_ms: 20
|
||||||
|
|
||||||
|
# Minimum calls for slow queries
|
||||||
|
# slow_query_calls: 100
|
||||||
|
|
||||||
|
# Minimum connections for high connections warning
|
||||||
|
# total_connections_threshold: 500
|
||||||
|
|
||||||
|
# Statement timeout for explain
|
||||||
|
# explain_timeout_sec: 10
|
||||||
|
|
||||||
|
# Time zone (defaults to app time zone)
|
||||||
|
# time_zone: "Pacific Time (US & Canada)"
|
||||||
|
|
||||||
|
# Basic authentication
|
||||||
|
# username: admin
|
||||||
|
# password: secret
|
||||||
|
|
||||||
|
# Stats database URL (defaults to app database)
|
||||||
|
# stats_database_url: <%= ENV["PGHERO_STATS_DATABASE_URL"] %>
|
||||||
|
|
||||||
|
# AWS configuration (defaults to app AWS config)
|
||||||
|
# also need aws_db_instance_identifier with each database
|
||||||
|
# aws_access_key_id: ...
|
||||||
|
# aws_secret_access_key: ...
|
||||||
|
# aws_region: us-east-1
|
||||||
|
|
||||||
|
override_csp: true
|
14
package.json
14
package.json
|
@ -64,14 +64,14 @@
|
||||||
"@babel/plugin-proposal-class-properties": "^7.7.0",
|
"@babel/plugin-proposal-class-properties": "^7.7.0",
|
||||||
"@babel/plugin-proposal-decorators": "^7.7.0",
|
"@babel/plugin-proposal-decorators": "^7.7.0",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.6.2",
|
"@babel/plugin-proposal-object-rest-spread": "^7.6.2",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
"@babel/plugin-syntax-dynamic-import": "^7.7.4",
|
||||||
"@babel/plugin-transform-react-inline-elements": "^7.2.0",
|
"@babel/plugin-transform-react-inline-elements": "^7.7.4",
|
||||||
"@babel/plugin-transform-react-jsx-self": "^7.2.0",
|
"@babel/plugin-transform-react-jsx-self": "^7.7.4",
|
||||||
"@babel/plugin-transform-react-jsx-source": "^7.5.0",
|
"@babel/plugin-transform-react-jsx-source": "^7.5.0",
|
||||||
"@babel/plugin-transform-runtime": "^7.5.5",
|
"@babel/plugin-transform-runtime": "^7.7.4",
|
||||||
"@babel/preset-env": "^7.7.1",
|
"@babel/preset-env": "^7.7.4",
|
||||||
"@babel/preset-react": "^7.7.0",
|
"@babel/preset-react": "^7.7.0",
|
||||||
"@babel/runtime": "^7.7.2",
|
"@babel/runtime": "^7.7.4",
|
||||||
"@clusterws/cws": "^0.16.0",
|
"@clusterws/cws": "^0.16.0",
|
||||||
"array-includes": "^3.0.3",
|
"array-includes": "^3.0.3",
|
||||||
"atrament": "^0.2.3",
|
"atrament": "^0.2.3",
|
||||||
|
@ -161,7 +161,7 @@
|
||||||
"stringz": "^2.0.0",
|
"stringz": "^2.0.0",
|
||||||
"substring-trie": "^1.0.2",
|
"substring-trie": "^1.0.2",
|
||||||
"terser-webpack-plugin": "^2.2.1",
|
"terser-webpack-plugin": "^2.2.1",
|
||||||
"tesseract.js": "^2.0.0-beta.2",
|
"tesseract.js": "^2.0.0-alpha.16",
|
||||||
"throng": "^4.0.0",
|
"throng": "^4.0.0",
|
||||||
"tiny-queue": "^0.2.1",
|
"tiny-queue": "^0.2.1",
|
||||||
"uuid": "^3.3.3",
|
"uuid": "^3.3.3",
|
||||||
|
|
Loading…
Reference in New Issue