Update to v4.1.0rc3
This commit is contained in:
commit
822569fedc
907 changed files with 51658 additions and 18972 deletions
|
@ -17,6 +17,8 @@ class AccountsController < ApplicationController
|
|||
respond_to do |format|
|
||||
format.html do
|
||||
expires_in 0, public: true unless user_signed_in?
|
||||
|
||||
@rss_url = rss_url
|
||||
end
|
||||
|
||||
format.rss do
|
||||
|
|
|
@ -21,7 +21,7 @@ module Admin
|
|||
account_action.save!
|
||||
|
||||
if account_action.with_report?
|
||||
redirect_to admin_reports_path
|
||||
redirect_to admin_reports_path, notice: I18n.t('admin.reports.processed_msg', id: params[:report_id])
|
||||
else
|
||||
redirect_to admin_account_path(@account.id)
|
||||
end
|
||||
|
|
|
@ -55,12 +55,14 @@ module Admin
|
|||
def approve
|
||||
authorize @account.user, :approve?
|
||||
@account.user.approve!
|
||||
log_action :approve, @account.user
|
||||
redirect_to admin_accounts_path(status: 'pending'), notice: I18n.t('admin.accounts.approved_msg', username: @account.acct)
|
||||
end
|
||||
|
||||
def reject
|
||||
authorize @account.user, :reject?
|
||||
DeleteAccountService.new.call(@account, reserve_email: false, reserve_username: false)
|
||||
log_action :reject, @account.user
|
||||
redirect_to admin_accounts_path(status: 'pending'), notice: I18n.t('admin.accounts.rejected_msg', username: @account.acct)
|
||||
end
|
||||
|
||||
|
|
|
@ -4,6 +4,18 @@ module Admin
|
|||
class DomainBlocksController < BaseController
|
||||
before_action :set_domain_block, only: [:show, :destroy, :edit, :update]
|
||||
|
||||
def batch
|
||||
authorize :domain_block, :create?
|
||||
@form = Form::DomainBlockBatch.new(form_domain_block_batch_params.merge(current_account: current_account, action: action_from_button))
|
||||
@form.save
|
||||
rescue ActionController::ParameterMissing
|
||||
flash[:alert] = I18n.t('admin.domain_blocks.no_domain_block_selected')
|
||||
rescue Mastodon::NotPermittedError
|
||||
flash[:alert] = I18n.t('admin.domain_blocks.not_permitted')
|
||||
else
|
||||
redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.created_msg')
|
||||
end
|
||||
|
||||
def new
|
||||
authorize :domain_block, :create?
|
||||
@domain_block = DomainBlock.new(domain: params[:_domain])
|
||||
|
@ -43,12 +55,8 @@ module Admin
|
|||
def update
|
||||
authorize :domain_block, :update?
|
||||
|
||||
@domain_block.update(update_params)
|
||||
|
||||
severity_changed = @domain_block.severity_changed?
|
||||
|
||||
if @domain_block.save
|
||||
DomainBlockWorker.perform_async(@domain_block.id, severity_changed)
|
||||
if @domain_block.update(update_params)
|
||||
DomainBlockWorker.perform_async(@domain_block.id, @domain_block.severity_previously_changed?)
|
||||
log_action :update, @domain_block
|
||||
redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.created_msg')
|
||||
else
|
||||
|
@ -76,5 +84,15 @@ module Admin
|
|||
def resource_params
|
||||
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate)
|
||||
end
|
||||
|
||||
def form_domain_block_batch_params
|
||||
params.require(:form_domain_block_batch).permit(domain_blocks_attributes: [:enabled, :domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate])
|
||||
end
|
||||
|
||||
def action_from_button
|
||||
if params[:save]
|
||||
'save'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ module Admin
|
|||
rescue ActionController::ParameterMissing
|
||||
flash[:alert] = I18n.t('admin.email_domain_blocks.no_email_domain_block_selected')
|
||||
rescue Mastodon::NotPermittedError
|
||||
flash[:alert] = I18n.t('admin.custom_emojis.not_permitted')
|
||||
flash[:alert] = I18n.t('admin.email_domain_blocks.not_permitted')
|
||||
ensure
|
||||
redirect_to admin_email_domain_blocks_path
|
||||
end
|
||||
|
|
58
app/controllers/admin/export_domain_allows_controller.rb
Normal file
58
app/controllers/admin/export_domain_allows_controller.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'csv'
|
||||
|
||||
module Admin
|
||||
class ExportDomainAllowsController < BaseController
|
||||
include AdminExportControllerConcern
|
||||
|
||||
before_action :set_dummy_import!, only: [:new]
|
||||
|
||||
def new
|
||||
authorize :domain_allow, :create?
|
||||
end
|
||||
|
||||
def export
|
||||
authorize :instance, :index?
|
||||
send_export_file
|
||||
end
|
||||
|
||||
def import
|
||||
authorize :domain_allow, :create?
|
||||
begin
|
||||
@import = Admin::Import.new(import_params)
|
||||
return render :new unless @import.validate
|
||||
|
||||
@import.csv_rows.each do |row|
|
||||
domain = row['#domain'].strip
|
||||
next if DomainAllow.allowed?(domain)
|
||||
|
||||
domain_allow = DomainAllow.new(domain: domain)
|
||||
log_action :create, domain_allow if domain_allow.save
|
||||
end
|
||||
flash[:notice] = I18n.t('admin.domain_allows.created_msg')
|
||||
rescue ActionController::ParameterMissing
|
||||
flash[:error] = I18n.t('admin.export_domain_allows.no_file')
|
||||
end
|
||||
redirect_to admin_instances_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def export_filename
|
||||
'domain_allows.csv'
|
||||
end
|
||||
|
||||
def export_headers
|
||||
%w(#domain)
|
||||
end
|
||||
|
||||
def export_data
|
||||
CSV.generate(headers: export_headers, write_headers: true) do |content|
|
||||
DomainAllow.allowed_domains.each do |instance|
|
||||
content << [instance.domain]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
77
app/controllers/admin/export_domain_blocks_controller.rb
Normal file
77
app/controllers/admin/export_domain_blocks_controller.rb
Normal file
|
@ -0,0 +1,77 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'csv'
|
||||
|
||||
module Admin
|
||||
class ExportDomainBlocksController < BaseController
|
||||
include AdminExportControllerConcern
|
||||
|
||||
before_action :set_dummy_import!, only: [:new]
|
||||
|
||||
def new
|
||||
authorize :domain_block, :create?
|
||||
end
|
||||
|
||||
def export
|
||||
authorize :instance, :index?
|
||||
send_export_file
|
||||
end
|
||||
|
||||
def import
|
||||
authorize :domain_block, :create?
|
||||
|
||||
@import = Admin::Import.new(import_params)
|
||||
return render :new unless @import.validate
|
||||
|
||||
@global_private_comment = I18n.t('admin.export_domain_blocks.import.private_comment_template', source: @import.data_file_name, date: I18n.l(Time.now.utc))
|
||||
|
||||
@form = Form::DomainBlockBatch.new
|
||||
@domain_blocks = @import.csv_rows.filter_map do |row|
|
||||
domain = row['#domain'].strip
|
||||
next if DomainBlock.rule_for(domain).present?
|
||||
|
||||
domain_block = DomainBlock.new(domain: domain,
|
||||
severity: row.fetch('#severity', :suspend),
|
||||
reject_media: row.fetch('#reject_media', false),
|
||||
reject_reports: row.fetch('#reject_reports', false),
|
||||
private_comment: @global_private_comment,
|
||||
public_comment: row['#public_comment'],
|
||||
obfuscate: row.fetch('#obfuscate', false))
|
||||
|
||||
if domain_block.invalid?
|
||||
flash.now[:alert] = I18n.t('admin.export_domain_blocks.invalid_domain_block', error: domain_block.errors.full_messages.join(', '))
|
||||
next
|
||||
end
|
||||
|
||||
domain_block
|
||||
rescue ArgumentError => e
|
||||
flash.now[:alert] = I18n.t('admin.export_domain_blocks.invalid_domain_block', error: e.message)
|
||||
next
|
||||
end
|
||||
|
||||
@warning_domains = Instance.where(domain: @domain_blocks.map(&:domain)).where('EXISTS (SELECT 1 FROM follows JOIN accounts ON follows.account_id = accounts.id OR follows.target_account_id = accounts.id WHERE accounts.domain = instances.domain)').pluck(:domain)
|
||||
rescue ActionController::ParameterMissing
|
||||
flash.now[:alert] = I18n.t('admin.export_domain_blocks.no_file')
|
||||
set_dummy_import!
|
||||
render :new
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def export_filename
|
||||
'domain_blocks.csv'
|
||||
end
|
||||
|
||||
def export_headers
|
||||
%w(#domain #severity #reject_media #reject_reports #public_comment #obfuscate)
|
||||
end
|
||||
|
||||
def export_data
|
||||
CSV.generate(headers: export_headers, write_headers: true) do |content|
|
||||
DomainBlock.with_limitations.each do |instance|
|
||||
content << [instance.domain, instance.severity, instance.reject_media, instance.reject_reports, instance.public_comment, instance.obfuscate]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -49,7 +49,7 @@ module Admin
|
|||
private
|
||||
|
||||
def set_instance
|
||||
@instance = Instance.find(params[:id])
|
||||
@instance = Instance.find(TagManager.instance.normalize_domain(params[:id]&.strip))
|
||||
end
|
||||
|
||||
def set_instances
|
||||
|
@ -57,7 +57,7 @@ module Admin
|
|||
end
|
||||
|
||||
def preload_delivery_failures!
|
||||
warning_domains_map = DeliveryFailureTracker.warning_domains_map
|
||||
warning_domains_map = DeliveryFailureTracker.warning_domains_map(@instances.map(&:domain))
|
||||
|
||||
@instances.each do |instance|
|
||||
instance.failure_days = warning_domains_map[instance.domain]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
module Admin
|
||||
class RelaysController < BaseController
|
||||
before_action :set_relay, except: [:index, :new, :create]
|
||||
before_action :require_signatures_enabled!, only: [:new, :create, :enable]
|
||||
before_action :warn_signatures_not_enabled!, only: [:new, :create, :enable]
|
||||
|
||||
def index
|
||||
authorize :relay, :update?
|
||||
|
@ -56,8 +56,8 @@ module Admin
|
|||
params.require(:relay).permit(:inbox_url)
|
||||
end
|
||||
|
||||
def require_signatures_enabled!
|
||||
redirect_to admin_relays_path, alert: I18n.t('admin.relays.signatures_not_enabled') if authorized_fetch_mode?
|
||||
def warn_signatures_not_enabled!
|
||||
flash.now[:error] = I18n.t('admin.relays.signatures_not_enabled') if authorized_fetch_mode?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
class Admin::Reports::ActionsController < Admin::BaseController
|
||||
before_action :set_report
|
||||
|
||||
def preview
|
||||
authorize @report, :show?
|
||||
@moderation_action = action_from_button
|
||||
end
|
||||
|
||||
def create
|
||||
authorize @report, :show?
|
||||
|
||||
|
@ -13,7 +18,8 @@ class Admin::Reports::ActionsController < Admin::BaseController
|
|||
status_ids: @report.status_ids,
|
||||
current_account: current_account,
|
||||
report_id: @report.id,
|
||||
send_email_notification: !@report.spam?
|
||||
send_email_notification: !@report.spam?,
|
||||
text: params[:text]
|
||||
)
|
||||
|
||||
status_batch_action.save!
|
||||
|
@ -23,13 +29,16 @@ class Admin::Reports::ActionsController < Admin::BaseController
|
|||
report_id: @report.id,
|
||||
target_account: @report.target_account,
|
||||
current_account: current_account,
|
||||
send_email_notification: !@report.spam?
|
||||
send_email_notification: !@report.spam?,
|
||||
text: params[:text]
|
||||
)
|
||||
|
||||
account_action.save!
|
||||
else
|
||||
return redirect_to admin_report_path(@report), alert: I18n.t('admin.reports.unknown_action_msg', action: action_from_button)
|
||||
end
|
||||
|
||||
redirect_to admin_reports_path
|
||||
redirect_to admin_reports_path, notice: I18n.t('admin.reports.processed_msg', id: @report.id)
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -47,6 +56,8 @@ class Admin::Reports::ActionsController < Admin::BaseController
|
|||
'silence'
|
||||
elsif params[:suspend]
|
||||
'suspend'
|
||||
elsif params[:moderation_action]
|
||||
params[:moderation_action]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,6 +16,26 @@ class Api::BaseController < ApplicationController
|
|||
|
||||
protect_from_forgery with: :null_session
|
||||
|
||||
content_security_policy do |p|
|
||||
# Set every directive that does not have a fallback
|
||||
p.default_src :none
|
||||
p.frame_ancestors :none
|
||||
p.form_action :none
|
||||
|
||||
# Disable every directive with a fallback to cut on response size
|
||||
p.base_uri false
|
||||
p.font_src false
|
||||
p.img_src false
|
||||
p.style_src false
|
||||
p.media_src false
|
||||
p.frame_src false
|
||||
p.manifest_src false
|
||||
p.connect_src false
|
||||
p.script_src false
|
||||
p.child_src false
|
||||
p.worker_src false
|
||||
end
|
||||
|
||||
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
|
||||
render json: { error: e.to_s }, status: 422
|
||||
end
|
||||
|
@ -129,7 +149,7 @@ class Api::BaseController < ApplicationController
|
|||
end
|
||||
|
||||
def set_cache_headers
|
||||
response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
||||
response.headers['Cache-Control'] = 'private, no-store'
|
||||
end
|
||||
|
||||
def disallow_unauthenticated_api_access?
|
||||
|
|
|
@ -21,7 +21,17 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
|
|||
private
|
||||
|
||||
def account_params
|
||||
params.permit(:display_name, :note, :avatar, :header, :locked, :bot, :discoverable, fields_attributes: [:name, :value])
|
||||
params.permit(
|
||||
:display_name,
|
||||
:note,
|
||||
:avatar,
|
||||
:header,
|
||||
:locked,
|
||||
:bot,
|
||||
:discoverable,
|
||||
:hide_collections,
|
||||
fields_attributes: [:name, :value]
|
||||
)
|
||||
end
|
||||
|
||||
def user_settings_params
|
||||
|
|
|
@ -54,12 +54,14 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
|||
def approve
|
||||
authorize @account.user, :approve?
|
||||
@account.user.approve!
|
||||
log_action :approve, @account.user
|
||||
render json: @account, serializer: REST::Admin::AccountSerializer
|
||||
end
|
||||
|
||||
def reject
|
||||
authorize @account.user, :reject?
|
||||
DeleteAccountService.new.call(@account, reserve_email: false, reserve_username: false)
|
||||
log_action :reject, @account.user
|
||||
render_empty
|
||||
end
|
||||
|
||||
|
|
|
@ -40,10 +40,8 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
|
|||
|
||||
def update
|
||||
authorize @domain_block, :update?
|
||||
@domain_block.update(domain_block_params)
|
||||
severity_changed = @domain_block.severity_changed?
|
||||
@domain_block.save!
|
||||
DomainBlockWorker.perform_async(@domain_block.id, severity_changed)
|
||||
@domain_block.update!(domain_block_params)
|
||||
DomainBlockWorker.perform_async(@domain_block.id, @domain_block.severity_previously_changed?)
|
||||
log_action :update, @domain_block
|
||||
render json: @domain_block, serializer: REST::Admin::DomainBlockSerializer
|
||||
end
|
||||
|
|
|
@ -3,6 +3,14 @@
|
|||
class Api::V1::Admin::Trends::TagsController < Api::V1::Trends::TagsController
|
||||
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||
|
||||
def index
|
||||
if current_user&.can?(:manage_taxonomies)
|
||||
render json: @tags, each_serializer: REST::Admin::TagSerializer
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def enabled?
|
||||
|
|
|
@ -13,7 +13,7 @@ class Api::V1::FiltersController < Api::BaseController
|
|||
|
||||
def create
|
||||
ApplicationRecord.transaction do
|
||||
filter_category = current_account.custom_filters.create!(resource_params)
|
||||
filter_category = current_account.custom_filters.create!(filter_params)
|
||||
@filter = filter_category.keywords.create!(keyword_params)
|
||||
end
|
||||
|
||||
|
@ -52,11 +52,11 @@ class Api::V1::FiltersController < Api::BaseController
|
|||
end
|
||||
|
||||
def resource_params
|
||||
params.permit(:phrase, :expires_in, :irreversible, context: [])
|
||||
params.permit(:phrase, :expires_in, :irreversible, :whole_word, context: [])
|
||||
end
|
||||
|
||||
def filter_params
|
||||
resource_params.slice(:expires_in, :irreversible, :context)
|
||||
resource_params.slice(:phrase, :expires_in, :irreversible, :context)
|
||||
end
|
||||
|
||||
def keyword_params
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
class Api::V1::FollowedTagsController < Api::BaseController
|
||||
TAGS_LIMIT = 100
|
||||
|
||||
before_action -> { doorkeeper_authorize! :follow, :read, :'read:follows' }, except: :show
|
||||
before_action -> { doorkeeper_authorize! :follow, :read, :'read:follows' }
|
||||
before_action :require_user!
|
||||
before_action :set_results
|
||||
|
||||
after_action :insert_pagination_headers, only: :show
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
def index
|
||||
render json: @results.map(&:tag), each_serializer: REST::TagSerializer, relationships: TagRelationshipsPresenter.new(@results.map(&:tag), current_user&.account_id)
|
||||
|
@ -43,7 +43,7 @@ class Api::V1::FollowedTagsController < Api::BaseController
|
|||
end
|
||||
|
||||
def records_continue?
|
||||
@results.size == limit_param(TAG_LIMIT)
|
||||
@results.size == limit_param(TAGS_LIMIT)
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
|
|
|
@ -6,7 +6,7 @@ class Api::V1::NotificationsController < Api::BaseController
|
|||
before_action :require_user!
|
||||
after_action :insert_pagination_headers, only: :index
|
||||
|
||||
DEFAULT_NOTIFICATIONS_LIMIT = 15
|
||||
DEFAULT_NOTIFICATIONS_LIMIT = 40
|
||||
|
||||
def index
|
||||
@notifications = load_notifications
|
||||
|
@ -31,7 +31,7 @@ class Api::V1::NotificationsController < Api::BaseController
|
|||
private
|
||||
|
||||
def load_notifications
|
||||
notifications = browserable_account_notifications.includes(from_account: :account_stat).to_a_paginated_by_id(
|
||||
notifications = browserable_account_notifications.includes(from_account: [:account_stat, :user]).to_a_paginated_by_id(
|
||||
limit_param(DEFAULT_NOTIFICATIONS_LIMIT),
|
||||
params_slice(:max_id, :since_id, :min_id)
|
||||
)
|
||||
|
|
|
@ -79,6 +79,7 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
current_account.id,
|
||||
text: status_params[:status],
|
||||
media_ids: status_params[:media_ids],
|
||||
media_attributes: status_params[:media_attributes],
|
||||
sensitive: status_params[:sensitive],
|
||||
language: status_params[:language],
|
||||
spoiler_text: status_params[:spoiler_text],
|
||||
|
@ -128,6 +129,12 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
:language,
|
||||
:scheduled_at,
|
||||
media_ids: [],
|
||||
media_attributes: [
|
||||
:id,
|
||||
:thumbnail,
|
||||
:description,
|
||||
:focus,
|
||||
],
|
||||
poll: [
|
||||
:multiple,
|
||||
:hide_totals,
|
||||
|
|
|
@ -12,7 +12,7 @@ class Api::V1::TagsController < Api::BaseController
|
|||
end
|
||||
|
||||
def follow
|
||||
TagFollow.create!(tag: @tag, account: current_account, rate_limit: true)
|
||||
TagFollow.create_with(rate_limit: true).find_or_create_by!(tag: @tag, account: current_account)
|
||||
render json: @tag, serializer: REST::TagSerializer
|
||||
end
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ class Auth::PasswordsController < Devise::PasswordsController
|
|||
super do |resource|
|
||||
if resource.errors.empty?
|
||||
resource.session_activations.destroy_all
|
||||
|
||||
resource.revoke_access!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -56,8 +56,8 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||
end
|
||||
|
||||
def configure_sign_up_params
|
||||
devise_parameter_sanitizer.permit(:sign_up) do |u|
|
||||
u.permit({ account_attributes: [:username, :display_name], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code, :agreement, :website, :confirm_password)
|
||||
devise_parameter_sanitizer.permit(:sign_up) do |user_params|
|
||||
user_params.permit({ account_attributes: [:username, :display_name], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code, :agreement, :website, :confirm_password)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -154,6 +154,6 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||
end
|
||||
|
||||
def set_cache_headers
|
||||
response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
||||
response.headers['Cache-Control'] = 'private, no-store'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,6 +14,10 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
before_action :set_instance_presenter, only: [:new]
|
||||
before_action :set_body_classes
|
||||
|
||||
content_security_policy only: :new do |p|
|
||||
p.form_action(false)
|
||||
end
|
||||
|
||||
def check_suspicious!
|
||||
user = find_user
|
||||
@login_is_suspicious = suspicious_sign_in?(user) unless user.nil?
|
||||
|
|
29
app/controllers/concerns/admin_export_controller_concern.rb
Normal file
29
app/controllers/concerns/admin_export_controller_concern.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module AdminExportControllerConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
private
|
||||
|
||||
def send_export_file
|
||||
respond_to do |format|
|
||||
format.csv { send_data export_data, filename: export_filename }
|
||||
end
|
||||
end
|
||||
|
||||
def export_data
|
||||
raise 'Override in controller'
|
||||
end
|
||||
|
||||
def export_filename
|
||||
raise 'Override in controller'
|
||||
end
|
||||
|
||||
def set_dummy_import!
|
||||
@import = Admin::Import.new
|
||||
end
|
||||
|
||||
def import_params
|
||||
params.require(:admin_import).permit(:data)
|
||||
end
|
||||
end
|
|
@ -58,7 +58,7 @@ module RateLimitHeaders
|
|||
end
|
||||
|
||||
def api_throttle_data
|
||||
most_limited_type, = request.env['rack.attack.throttle_data'].min_by { |_, v| v[:limit] - v[:count] }
|
||||
most_limited_type, = request.env['rack.attack.throttle_data'].min_by { |_key, value| value[:limit] - value[:count] }
|
||||
request.env['rack.attack.throttle_data'][most_limited_type]
|
||||
end
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ module SignatureVerification
|
|||
end
|
||||
|
||||
class SignatureParamsTransformer < Parslet::Transform
|
||||
rule(params: subtree(:p)) do
|
||||
(p.is_a?(Array) ? p : [p]).each_with_object({}) { |(key, val), h| h[key] = val }
|
||||
rule(params: subtree(:param)) do
|
||||
(param.is_a?(Array) ? param : [param]).each_with_object({}) { |(key, value), hash| hash[key] = value }
|
||||
end
|
||||
|
||||
rule(param: { key: simple(:key), value: simple(:val) }) do
|
||||
|
@ -46,11 +46,11 @@ module SignatureVerification
|
|||
end
|
||||
|
||||
def require_account_signature!
|
||||
render plain: signature_verification_failure_reason, status: signature_verification_failure_code unless signed_request_account
|
||||
render json: signature_verification_failure_reason, status: signature_verification_failure_code unless signed_request_account
|
||||
end
|
||||
|
||||
def require_actor_signature!
|
||||
render plain: signature_verification_failure_reason, status: signature_verification_failure_code unless signed_request_actor
|
||||
render json: signature_verification_failure_reason, status: signature_verification_failure_code unless signed_request_actor
|
||||
end
|
||||
|
||||
def signed_request?
|
||||
|
@ -97,11 +97,11 @@ module SignatureVerification
|
|||
|
||||
actor = stoplight_wrap_request { actor_refresh_key!(actor) }
|
||||
|
||||
raise SignatureVerificationError, "Public key not found for key #{signature_params['keyId']}" if actor.nil?
|
||||
raise SignatureVerificationError, "Could not refresh public key #{signature_params['keyId']}" if actor.nil?
|
||||
|
||||
return actor unless verify_signature(actor, signature, compare_signed_string).nil?
|
||||
|
||||
fail_with! "Verification failed for #{actor.to_log_human_identifier} #{actor.uri} using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)"
|
||||
fail_with! "Verification failed for #{actor.to_log_human_identifier} #{actor.uri} using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)", signed_string: compare_signed_string, signature: signature_params['signature']
|
||||
rescue SignatureVerificationError => e
|
||||
fail_with! e.message
|
||||
rescue HTTP::Error, OpenSSL::SSL::SSLError => e
|
||||
|
@ -118,8 +118,8 @@ module SignatureVerification
|
|||
|
||||
private
|
||||
|
||||
def fail_with!(message)
|
||||
@signature_verification_failure_reason = message
|
||||
def fail_with!(message, **options)
|
||||
@signature_verification_failure_reason = { error: message }.merge(options)
|
||||
@signed_request_actor = nil
|
||||
end
|
||||
|
||||
|
@ -209,8 +209,8 @@ module SignatureVerification
|
|||
end
|
||||
|
||||
expires_time = Time.at(signature_params['expires'].to_i).utc if signature_params['expires'].present?
|
||||
rescue ArgumentError
|
||||
return false
|
||||
rescue ArgumentError => e
|
||||
raise SignatureVerificationError, "Invalid Date header: #{e.message}"
|
||||
end
|
||||
|
||||
expires_time ||= created_time + 5.minutes unless created_time.nil?
|
||||
|
|
|
@ -4,21 +4,16 @@ module WebAppControllerConcern
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_action :redirect_unauthenticated_to_permalinks!
|
||||
prepend_before_action :redirect_unauthenticated_to_permalinks!
|
||||
before_action :set_app_body_class
|
||||
before_action :set_referrer_policy_header
|
||||
end
|
||||
|
||||
def set_app_body_class
|
||||
@body_classes = 'app-body'
|
||||
end
|
||||
|
||||
def set_referrer_policy_header
|
||||
response.headers['Referrer-Policy'] = 'origin'
|
||||
end
|
||||
|
||||
def redirect_unauthenticated_to_permalinks!
|
||||
return if user_signed_in?
|
||||
return if user_signed_in? && current_account.moved_to_account_id.nil?
|
||||
|
||||
redirect_path = PermalinkRedirector.new(request.path).redirect_path
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ class FollowerAccountsController < ApplicationController
|
|||
id: account_followers_url(@account, page: params.fetch(:page, 1)),
|
||||
type: :ordered,
|
||||
size: @account.followers_count,
|
||||
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) },
|
||||
items: follows.map { |follow| ActivityPub::TagManager.instance.uri_for(follow.account) },
|
||||
part_of: account_followers_url(@account),
|
||||
next: next_page_url,
|
||||
prev: prev_page_url
|
||||
|
|
|
@ -66,7 +66,7 @@ class FollowingAccountsController < ApplicationController
|
|||
id: account_following_index_url(@account, page: params.fetch(:page, 1)),
|
||||
type: :ordered,
|
||||
size: @account.following_count,
|
||||
items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) },
|
||||
items: follows.map { |follow| ActivityPub::TagManager.instance.uri_for(follow.target_account) },
|
||||
part_of: account_following_index_url(@account),
|
||||
next: next_page_url,
|
||||
prev: prev_page_url
|
||||
|
|
|
@ -12,8 +12,8 @@ class MediaController < ApplicationController
|
|||
before_action :check_playable, only: :player
|
||||
before_action :allow_iframing, only: :player
|
||||
|
||||
content_security_policy only: :player do |p|
|
||||
p.frame_ancestors(false)
|
||||
content_security_policy only: :player do |policy|
|
||||
policy.frame_ancestors(false)
|
||||
end
|
||||
|
||||
def show
|
||||
|
|
|
@ -7,6 +7,10 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
|
|||
before_action :authenticate_resource_owner!
|
||||
before_action :set_cache_headers
|
||||
|
||||
content_security_policy do |p|
|
||||
p.form_action(false)
|
||||
end
|
||||
|
||||
include Localized
|
||||
|
||||
private
|
||||
|
@ -30,6 +34,6 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
|
|||
end
|
||||
|
||||
def set_cache_headers
|
||||
response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
||||
response.headers['Cache-Control'] = 'private, no-store'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,7 +29,13 @@ class Settings::ApplicationsController < Settings::BaseController
|
|||
|
||||
def update
|
||||
if @application.update(application_params)
|
||||
redirect_to settings_applications_path, notice: I18n.t('generic.changes_saved_msg')
|
||||
if @application.scopes_previously_changed?
|
||||
@access_token = current_user.token_for_app(@application)
|
||||
@access_token.destroy
|
||||
redirect_to settings_application_path(@application), notice: I18n.t('applications.token_regenerated')
|
||||
else
|
||||
redirect_to settings_application_path(@application), notice: I18n.t('generic.changes_saved_msg')
|
||||
end
|
||||
else
|
||||
render :show
|
||||
end
|
||||
|
|
|
@ -14,7 +14,7 @@ class Settings::BaseController < ApplicationController
|
|||
end
|
||||
|
||||
def set_cache_headers
|
||||
response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
||||
response.headers['Cache-Control'] = 'private, no-store'
|
||||
end
|
||||
|
||||
def require_not_suspended!
|
||||
|
|
|
@ -19,6 +19,10 @@ class StatusesCleanupController < ApplicationController
|
|||
# Do nothing
|
||||
end
|
||||
|
||||
def require_functional!
|
||||
redirect_to edit_user_registration_path unless current_user.functional_or_moved?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_policy
|
||||
|
|
|
@ -17,8 +17,8 @@ class StatusesController < ApplicationController
|
|||
skip_around_action :set_locale, if: -> { request.format == :json }
|
||||
skip_before_action :require_functional!, only: [:show, :embed], unless: :whitelist_mode?
|
||||
|
||||
content_security_policy only: :embed do |p|
|
||||
p.frame_ancestors(false)
|
||||
content_security_policy only: :embed do |policy|
|
||||
policy.frame_ancestors(false)
|
||||
end
|
||||
|
||||
def show
|
||||
|
|
|
@ -65,7 +65,7 @@ class TagsController < ApplicationController
|
|||
id: tag_url(@tag),
|
||||
type: :ordered,
|
||||
size: @tag.statuses.count,
|
||||
items: @statuses.map { |s| ActivityPub::TagManager.instance.uri_for(s) }
|
||||
items: @statuses.map { |status| ActivityPub::TagManager.instance.uri_for(status) }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@ module Admin::ActionLogsHelper
|
|||
when 'Status'
|
||||
link_to log.human_identifier, log.permalink
|
||||
when 'AccountWarning'
|
||||
link_to log.human_identifier, admin_account_path(log.target_id)
|
||||
link_to log.human_identifier, disputes_strike_path(log.target_id)
|
||||
when 'Announcement'
|
||||
link_to truncate(log.human_identifier), edit_admin_announcement_path(log.target_id)
|
||||
when 'IpBlock', 'Instance', 'CustomEmoji'
|
||||
|
|
|
@ -23,19 +23,28 @@ module FormattingHelper
|
|||
|
||||
before_html = begin
|
||||
if status.spoiler_text?
|
||||
"<p><strong>#{I18n.t('rss.content_warning', locale: available_locale_or_nil(status.language) || I18n.default_locale)}</strong> #{h(status.spoiler_text)}</p><hr />"
|
||||
else
|
||||
''
|
||||
tag.p do
|
||||
tag.strong do
|
||||
I18n.t('rss.content_warning', locale: available_locale_or_nil(status.language) || I18n.default_locale)
|
||||
end
|
||||
|
||||
status.spoiler_text
|
||||
end + tag.hr
|
||||
end
|
||||
end.html_safe # rubocop:disable Rails/OutputSafety
|
||||
end
|
||||
|
||||
after_html = begin
|
||||
if status.preloadable_poll
|
||||
"<p>#{status.preloadable_poll.options.map { |o| "<input type=#{status.preloadable_poll.multiple? ? 'checkbox' : 'radio'} disabled /> #{h(o)}" }.join('<br />')}</p>"
|
||||
else
|
||||
''
|
||||
tag.p do
|
||||
safe_join(
|
||||
status.preloadable_poll.options.map do |o|
|
||||
tag.send(status.preloadable_poll.multiple? ? 'checkbox' : 'radio', o, disabled: true)
|
||||
end,
|
||||
tag.br
|
||||
)
|
||||
end
|
||||
end
|
||||
end.html_safe # rubocop:disable Rails/OutputSafety
|
||||
end
|
||||
|
||||
prerender_custom_emojis(
|
||||
safe_join([before_html, html, after_html]),
|
||||
|
|
|
@ -190,12 +190,17 @@ module LanguagesHelper
|
|||
ISO_639_3 = {
|
||||
ast: ['Asturian', 'Asturianu'].freeze,
|
||||
ckb: ['Sorani (Kurdish)', 'سۆرانی'].freeze,
|
||||
cnr: ['Montenegrin', 'crnogorski'].freeze,
|
||||
jbo: ['Lojban', 'la .lojban.'].freeze,
|
||||
kab: ['Kabyle', 'Taqbaylit'].freeze,
|
||||
kmr: ['Kurmanji (Kurdish)', 'Kurmancî'].freeze,
|
||||
ldn: ['Láadan', 'Láadan'].freeze,
|
||||
lfn: ['Lingua Franca Nova', 'lingua franca nova'].freeze,
|
||||
sco: ['Scots', 'Scots'].freeze,
|
||||
sma: ['Southern Sami', 'Åarjelsaemien Gïele'].freeze,
|
||||
smj: ['Lule Sami', 'Julevsámegiella'].freeze,
|
||||
szl: ['Silesian', 'ślůnsko godka'].freeze,
|
||||
tai: ['Tai', 'ภาษาไท or ภาษาไต'].freeze,
|
||||
tok: ['Toki Pona', 'toki pona'].freeze,
|
||||
zba: ['Balaibalan', 'باليبلن'].freeze,
|
||||
zgh: ['Standard Moroccan Tamazight', 'ⵜⴰⵎⴰⵣⵉⵖⵜ'].freeze,
|
||||
|
@ -207,8 +212,10 @@ module LanguagesHelper
|
|||
# names, but for some translations, we need the names of the
|
||||
# regional variants specifically
|
||||
REGIONAL_LOCALE_NAMES = {
|
||||
'en-GB': 'English (British)',
|
||||
'es-AR': 'Español (Argentina)',
|
||||
'es-MX': 'Español (México)',
|
||||
'fr-QC': 'Français (Canadien)',
|
||||
'pt-BR': 'Português (Brasil)',
|
||||
'pt-PT': 'Português (Portugal)',
|
||||
'sr-Latn': 'Srpski (latinica)',
|
||||
|
|
|
@ -21,7 +21,7 @@ module StatusesHelper
|
|||
def media_summary(status)
|
||||
attachments = { image: 0, video: 0, audio: 0 }
|
||||
|
||||
status.media_attachments.each do |media|
|
||||
status.ordered_media_attachments.each do |media|
|
||||
if media.video?
|
||||
attachments[:video] += 1
|
||||
elsif media.audio?
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="79" height="79" viewBox="0 0 79 75"><symbol id="logo-symbol-icon"><path d="M74.7135 16.6043C73.6199 8.54587 66.5351 2.19527 58.1366 0.964691C56.7196 0.756754 51.351 0 38.9148 0H38.822C26.3824 0 23.7135 0.756754 22.2966 0.964691C14.1319 2.16118 6.67571 7.86752 4.86669 16.0214C3.99657 20.0369 3.90371 24.4888 4.06535 28.5726C4.29578 34.4289 4.34049 40.275 4.877 46.1075C5.24791 49.9817 5.89495 53.8251 6.81328 57.6088C8.53288 64.5968 15.4938 70.4122 22.3138 72.7848C29.6155 75.259 37.468 75.6697 44.9919 73.971C45.8196 73.7801 46.6381 73.5586 47.4475 73.3063C49.2737 72.7302 51.4164 72.086 52.9915 70.9542C53.0131 70.9384 53.0308 70.9178 53.0433 70.8942C53.0558 70.8706 53.0628 70.8445 53.0637 70.8179V65.1661C53.0634 65.1412 53.0574 65.1167 53.0462 65.0944C53.035 65.0721 53.0189 65.0525 52.9992 65.0371C52.9794 65.0218 52.9564 65.011 52.9318 65.0056C52.9073 65.0002 52.8819 65.0003 52.8574 65.0059C48.0369 66.1472 43.0971 66.7193 38.141 66.7103C29.6118 66.7103 27.3178 62.6981 26.6609 61.0278C26.1329 59.5842 25.7976 58.0784 25.6636 56.5486C25.6622 56.5229 25.667 56.4973 25.6775 56.4738C25.688 56.4502 25.7039 56.4295 25.724 56.4132C25.7441 56.397 25.7678 56.3856 25.7931 56.3801C25.8185 56.3746 25.8448 56.3751 25.8699 56.3816C30.6101 57.5151 35.4693 58.0873 40.3455 58.086C41.5183 58.086 42.6876 58.086 43.8604 58.0553C48.7647 57.919 53.9339 57.6701 58.7591 56.7361C58.8794 56.7123 58.9998 56.6918 59.103 56.6611C66.7139 55.2124 73.9569 50.665 74.6929 39.1501C74.7204 38.6967 74.7892 34.4016 74.7892 33.9312C74.7926 32.3325 75.3085 22.5901 74.7135 16.6043ZM62.9996 45.3371H54.9966V25.9069C54.9966 21.8163 53.277 19.7302 49.7793 19.7302C45.9343 19.7302 44.0083 22.1981 44.0083 27.0727V37.7082H36.0534V27.0727C36.0534 22.1981 34.124 19.7302 30.279 19.7302C26.8019 19.7302 25.0651 21.8163 25.0617 25.9069V45.3371H17.0656V25.3172C17.0656 21.2266 18.1191 17.9769 20.2262 15.568C22.3998 13.1648 25.2509 11.9308 28.7898 11.9308C32.8859 11.9308 35.9812 13.492 38.0447 16.6111L40.036 19.9245L42.0308 16.6111C44.0943 13.492 47.1896 11.9308 51.2788 11.9308C54.8143 11.9308 57.6654 13.1648 59.8459 15.568C61.9529 17.9746 63.0065 21.2243 63.0065 25.3172L62.9996 45.3371Z" fill="currentColor"/></symbol><use xlink:href="#logo-symbol-icon" style="color:#fff" /></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="79" height="79" viewBox="0 0 79 75"><symbol id="logo-symbol-icon"><path d="M74.7135 16.6043C73.6199 8.54587 66.5351 2.19527 58.1366 0.964691C56.7196 0.756754 51.351 0 38.9148 0H38.822C26.3824 0 23.7135 0.756754 22.2966 0.964691C14.1319 2.16118 6.67571 7.86752 4.86669 16.0214C3.99657 20.0369 3.90371 24.4888 4.06535 28.5726C4.29578 34.4289 4.34049 40.275 4.877 46.1075C5.24791 49.9817 5.89495 53.8251 6.81328 57.6088C8.53288 64.5968 15.4938 70.4122 22.3138 72.7848C29.6155 75.259 37.468 75.6697 44.9919 73.971C45.8196 73.7801 46.6381 73.5586 47.4475 73.3063C49.2737 72.7302 51.4164 72.086 52.9915 70.9542C53.0131 70.9384 53.0308 70.9178 53.0433 70.8942C53.0558 70.8706 53.0628 70.8445 53.0637 70.8179V65.1661C53.0634 65.1412 53.0574 65.1167 53.0462 65.0944C53.035 65.0721 53.0189 65.0525 52.9992 65.0371C52.9794 65.0218 52.9564 65.011 52.9318 65.0056C52.9073 65.0002 52.8819 65.0003 52.8574 65.0059C48.0369 66.1472 43.0971 66.7193 38.141 66.7103C29.6118 66.7103 27.3178 62.6981 26.6609 61.0278C26.1329 59.5842 25.7976 58.0784 25.6636 56.5486C25.6622 56.5229 25.667 56.4973 25.6775 56.4738C25.688 56.4502 25.7039 56.4295 25.724 56.4132C25.7441 56.397 25.7678 56.3856 25.7931 56.3801C25.8185 56.3746 25.8448 56.3751 25.8699 56.3816C30.6101 57.5151 35.4693 58.0873 40.3455 58.086C41.5183 58.086 42.6876 58.086 43.8604 58.0553C48.7647 57.919 53.9339 57.6701 58.7591 56.7361C58.8794 56.7123 58.9998 56.6918 59.103 56.6611C66.7139 55.2124 73.9569 50.665 74.6929 39.1501C74.7204 38.6967 74.7892 34.4016 74.7892 33.9312C74.7926 32.3325 75.3085 22.5901 74.7135 16.6043ZM62.9996 45.3371H54.9966V25.9069C54.9966 21.8163 53.277 19.7302 49.7793 19.7302C45.9343 19.7302 44.0083 22.1981 44.0083 27.0727V37.7082H36.0534V27.0727C36.0534 22.1981 34.124 19.7302 30.279 19.7302C26.8019 19.7302 25.0651 21.8163 25.0617 25.9069V45.3371H17.0656V25.3172C17.0656 21.2266 18.1191 17.9769 20.2262 15.568C22.3998 13.1648 25.2509 11.9308 28.7898 11.9308C32.8859 11.9308 35.9812 13.492 38.0447 16.6111L40.036 19.9245L42.0308 16.6111C44.0943 13.492 47.1896 11.9308 51.2788 11.9308C54.8143 11.9308 57.6654 13.1648 59.8459 15.568C61.9529 17.9746 63.0065 21.2243 63.0065 25.3172L62.9996 45.3371Z" fill="currentColor"/></symbol><use xlink:href="#logo-symbol-icon"/></svg>
|
||||
|
||||
|
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
@ -14,24 +14,24 @@ export function submitAccountNote(id, value) {
|
|||
dispatch(submitAccountNoteSuccess(response.data));
|
||||
}).catch(error => dispatch(submitAccountNoteFail(error)));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function submitAccountNoteRequest() {
|
||||
return {
|
||||
type: ACCOUNT_NOTE_SUBMIT_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function submitAccountNoteSuccess(relationship) {
|
||||
return {
|
||||
type: ACCOUNT_NOTE_SUBMIT_SUCCESS,
|
||||
relationship,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function submitAccountNoteFail(error) {
|
||||
return {
|
||||
type: ACCOUNT_NOTE_SUBMIT_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ export function fetchAccount(id) {
|
|||
dispatch(fetchAccountFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const lookupAccount = acct => (dispatch, getState) => {
|
||||
dispatch(lookupAccountRequest(acct));
|
||||
|
@ -126,13 +126,13 @@ export function fetchAccountRequest(id) {
|
|||
type: ACCOUNT_FETCH_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchAccountSuccess() {
|
||||
return {
|
||||
type: ACCOUNT_FETCH_SUCCESS,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchAccountFail(id, error) {
|
||||
return {
|
||||
|
@ -141,7 +141,7 @@ export function fetchAccountFail(id, error) {
|
|||
error,
|
||||
skipAlert: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function followAccount(id, options = { reblogs: true }) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -156,7 +156,7 @@ export function followAccount(id, options = { reblogs: true }) {
|
|||
dispatch(followAccountFail(error, locked));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unfollowAccount(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -168,7 +168,7 @@ export function unfollowAccount(id) {
|
|||
dispatch(unfollowAccountFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function followAccountRequest(id, locked) {
|
||||
return {
|
||||
|
@ -177,7 +177,7 @@ export function followAccountRequest(id, locked) {
|
|||
locked,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function followAccountSuccess(relationship, alreadyFollowing) {
|
||||
return {
|
||||
|
@ -186,7 +186,7 @@ export function followAccountSuccess(relationship, alreadyFollowing) {
|
|||
alreadyFollowing,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function followAccountFail(error, locked) {
|
||||
return {
|
||||
|
@ -195,7 +195,7 @@ export function followAccountFail(error, locked) {
|
|||
locked,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unfollowAccountRequest(id) {
|
||||
return {
|
||||
|
@ -203,7 +203,7 @@ export function unfollowAccountRequest(id) {
|
|||
id,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unfollowAccountSuccess(relationship, statuses) {
|
||||
return {
|
||||
|
@ -212,7 +212,7 @@ export function unfollowAccountSuccess(relationship, statuses) {
|
|||
statuses,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unfollowAccountFail(error) {
|
||||
return {
|
||||
|
@ -220,7 +220,7 @@ export function unfollowAccountFail(error) {
|
|||
error,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function blockAccount(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -233,7 +233,7 @@ export function blockAccount(id) {
|
|||
dispatch(blockAccountFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unblockAccount(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -245,14 +245,14 @@ export function unblockAccount(id) {
|
|||
dispatch(unblockAccountFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function blockAccountRequest(id) {
|
||||
return {
|
||||
type: ACCOUNT_BLOCK_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function blockAccountSuccess(relationship, statuses) {
|
||||
return {
|
||||
|
@ -260,35 +260,35 @@ export function blockAccountSuccess(relationship, statuses) {
|
|||
relationship,
|
||||
statuses,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function blockAccountFail(error) {
|
||||
return {
|
||||
type: ACCOUNT_BLOCK_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unblockAccountRequest(id) {
|
||||
return {
|
||||
type: ACCOUNT_UNBLOCK_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unblockAccountSuccess(relationship) {
|
||||
return {
|
||||
type: ACCOUNT_UNBLOCK_SUCCESS,
|
||||
relationship,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unblockAccountFail(error) {
|
||||
return {
|
||||
type: ACCOUNT_UNBLOCK_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function muteAccount(id, notifications, duration=0) {
|
||||
|
@ -302,7 +302,7 @@ export function muteAccount(id, notifications, duration=0) {
|
|||
dispatch(muteAccountFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unmuteAccount(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -314,14 +314,14 @@ export function unmuteAccount(id) {
|
|||
dispatch(unmuteAccountFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function muteAccountRequest(id) {
|
||||
return {
|
||||
type: ACCOUNT_MUTE_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function muteAccountSuccess(relationship, statuses) {
|
||||
return {
|
||||
|
@ -329,35 +329,35 @@ export function muteAccountSuccess(relationship, statuses) {
|
|||
relationship,
|
||||
statuses,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function muteAccountFail(error) {
|
||||
return {
|
||||
type: ACCOUNT_MUTE_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unmuteAccountRequest(id) {
|
||||
return {
|
||||
type: ACCOUNT_UNMUTE_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unmuteAccountSuccess(relationship) {
|
||||
return {
|
||||
type: ACCOUNT_UNMUTE_SUCCESS,
|
||||
relationship,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unmuteAccountFail(error) {
|
||||
return {
|
||||
type: ACCOUNT_UNMUTE_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function fetchFollowers(id) {
|
||||
|
@ -374,14 +374,14 @@ export function fetchFollowers(id) {
|
|||
dispatch(fetchFollowersFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowersRequest(id) {
|
||||
return {
|
||||
type: FOLLOWERS_FETCH_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowersSuccess(id, accounts, next) {
|
||||
return {
|
||||
|
@ -390,7 +390,7 @@ export function fetchFollowersSuccess(id, accounts, next) {
|
|||
accounts,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowersFail(id, error) {
|
||||
return {
|
||||
|
@ -399,7 +399,7 @@ export function fetchFollowersFail(id, error) {
|
|||
error,
|
||||
skipNotFound: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowers(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -421,14 +421,14 @@ export function expandFollowers(id) {
|
|||
dispatch(expandFollowersFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowersRequest(id) {
|
||||
return {
|
||||
type: FOLLOWERS_EXPAND_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowersSuccess(id, accounts, next) {
|
||||
return {
|
||||
|
@ -437,7 +437,7 @@ export function expandFollowersSuccess(id, accounts, next) {
|
|||
accounts,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowersFail(id, error) {
|
||||
return {
|
||||
|
@ -445,7 +445,7 @@ export function expandFollowersFail(id, error) {
|
|||
id,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowing(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -461,14 +461,14 @@ export function fetchFollowing(id) {
|
|||
dispatch(fetchFollowingFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowingRequest(id) {
|
||||
return {
|
||||
type: FOLLOWING_FETCH_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowingSuccess(id, accounts, next) {
|
||||
return {
|
||||
|
@ -477,7 +477,7 @@ export function fetchFollowingSuccess(id, accounts, next) {
|
|||
accounts,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowingFail(id, error) {
|
||||
return {
|
||||
|
@ -486,7 +486,7 @@ export function fetchFollowingFail(id, error) {
|
|||
error,
|
||||
skipNotFound: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowing(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -508,14 +508,14 @@ export function expandFollowing(id) {
|
|||
dispatch(expandFollowingFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowingRequest(id) {
|
||||
return {
|
||||
type: FOLLOWING_EXPAND_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowingSuccess(id, accounts, next) {
|
||||
return {
|
||||
|
@ -524,7 +524,7 @@ export function expandFollowingSuccess(id, accounts, next) {
|
|||
accounts,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowingFail(id, error) {
|
||||
return {
|
||||
|
@ -532,7 +532,7 @@ export function expandFollowingFail(id, error) {
|
|||
id,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchRelationships(accountIds) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -553,7 +553,7 @@ export function fetchRelationships(accountIds) {
|
|||
dispatch(fetchRelationshipsFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchRelationshipsRequest(ids) {
|
||||
return {
|
||||
|
@ -561,7 +561,7 @@ export function fetchRelationshipsRequest(ids) {
|
|||
ids,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchRelationshipsSuccess(relationships) {
|
||||
return {
|
||||
|
@ -569,7 +569,7 @@ export function fetchRelationshipsSuccess(relationships) {
|
|||
relationships,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchRelationshipsFail(error) {
|
||||
return {
|
||||
|
@ -578,7 +578,7 @@ export function fetchRelationshipsFail(error) {
|
|||
skipLoading: true,
|
||||
skipNotFound: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowRequests() {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -590,13 +590,13 @@ export function fetchFollowRequests() {
|
|||
dispatch(fetchFollowRequestsSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => dispatch(fetchFollowRequestsFail(error)));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowRequestsRequest() {
|
||||
return {
|
||||
type: FOLLOW_REQUESTS_FETCH_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowRequestsSuccess(accounts, next) {
|
||||
return {
|
||||
|
@ -604,14 +604,14 @@ export function fetchFollowRequestsSuccess(accounts, next) {
|
|||
accounts,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowRequestsFail(error) {
|
||||
return {
|
||||
type: FOLLOW_REQUESTS_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowRequests() {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -629,13 +629,13 @@ export function expandFollowRequests() {
|
|||
dispatch(expandFollowRequestsSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => dispatch(expandFollowRequestsFail(error)));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowRequestsRequest() {
|
||||
return {
|
||||
type: FOLLOW_REQUESTS_EXPAND_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowRequestsSuccess(accounts, next) {
|
||||
return {
|
||||
|
@ -643,14 +643,14 @@ export function expandFollowRequestsSuccess(accounts, next) {
|
|||
accounts,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowRequestsFail(error) {
|
||||
return {
|
||||
type: FOLLOW_REQUESTS_EXPAND_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function authorizeFollowRequest(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -661,21 +661,21 @@ export function authorizeFollowRequest(id) {
|
|||
.then(() => dispatch(authorizeFollowRequestSuccess(id)))
|
||||
.catch(error => dispatch(authorizeFollowRequestFail(id, error)));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function authorizeFollowRequestRequest(id) {
|
||||
return {
|
||||
type: FOLLOW_REQUEST_AUTHORIZE_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function authorizeFollowRequestSuccess(id) {
|
||||
return {
|
||||
type: FOLLOW_REQUEST_AUTHORIZE_SUCCESS,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function authorizeFollowRequestFail(id, error) {
|
||||
return {
|
||||
|
@ -683,7 +683,7 @@ export function authorizeFollowRequestFail(id, error) {
|
|||
id,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function rejectFollowRequest(id) {
|
||||
|
@ -695,21 +695,21 @@ export function rejectFollowRequest(id) {
|
|||
.then(() => dispatch(rejectFollowRequestSuccess(id)))
|
||||
.catch(error => dispatch(rejectFollowRequestFail(id, error)));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function rejectFollowRequestRequest(id) {
|
||||
return {
|
||||
type: FOLLOW_REQUEST_REJECT_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function rejectFollowRequestSuccess(id) {
|
||||
return {
|
||||
type: FOLLOW_REQUEST_REJECT_SUCCESS,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function rejectFollowRequestFail(id, error) {
|
||||
return {
|
||||
|
@ -717,7 +717,7 @@ export function rejectFollowRequestFail(id, error) {
|
|||
id,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function pinAccount(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -729,7 +729,7 @@ export function pinAccount(id) {
|
|||
dispatch(pinAccountFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unpinAccount(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -741,49 +741,49 @@ export function unpinAccount(id) {
|
|||
dispatch(unpinAccountFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function pinAccountRequest(id) {
|
||||
return {
|
||||
type: ACCOUNT_PIN_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function pinAccountSuccess(relationship) {
|
||||
return {
|
||||
type: ACCOUNT_PIN_SUCCESS,
|
||||
relationship,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function pinAccountFail(error) {
|
||||
return {
|
||||
type: ACCOUNT_PIN_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unpinAccountRequest(id) {
|
||||
return {
|
||||
type: ACCOUNT_UNPIN_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unpinAccountSuccess(relationship) {
|
||||
return {
|
||||
type: ACCOUNT_UNPIN_SUCCESS,
|
||||
relationship,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unpinAccountFail(error) {
|
||||
return {
|
||||
type: ACCOUNT_UNPIN_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const revealAccount = id => ({
|
||||
type: ACCOUNT_REVEAL,
|
||||
|
|
|
@ -17,13 +17,13 @@ export function dismissAlert(alert) {
|
|||
type: ALERT_DISMISS,
|
||||
alert,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function clearAlert() {
|
||||
return {
|
||||
type: ALERT_CLEAR,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function showAlert(title = messages.unexpectedTitle, message = messages.unexpectedMessage, message_values = undefined) {
|
||||
return {
|
||||
|
@ -32,7 +32,7 @@ export function showAlert(title = messages.unexpectedTitle, message = messages.u
|
|||
message,
|
||||
message_values,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function showAlertForError(error, skipNotFound = false) {
|
||||
if (error.response) {
|
||||
|
|
|
@ -102,7 +102,7 @@ export const addReaction = (announcementId, name) => (dispatch, getState) => {
|
|||
dispatch(addReactionRequest(announcementId, name, alreadyAdded));
|
||||
}
|
||||
|
||||
api(getState).put(`/api/v1/announcements/${announcementId}/reactions/${name}`).then(() => {
|
||||
api(getState).put(`/api/v1/announcements/${announcementId}/reactions/${encodeURIComponent(name)}`).then(() => {
|
||||
dispatch(addReactionSuccess(announcementId, name, alreadyAdded));
|
||||
}).catch(err => {
|
||||
if (!alreadyAdded) {
|
||||
|
@ -136,7 +136,7 @@ export const addReactionFail = (announcementId, name, error) => ({
|
|||
export const removeReaction = (announcementId, name) => (dispatch, getState) => {
|
||||
dispatch(removeReactionRequest(announcementId, name));
|
||||
|
||||
api(getState).delete(`/api/v1/announcements/${announcementId}/reactions/${name}`).then(() => {
|
||||
api(getState).delete(`/api/v1/announcements/${announcementId}/reactions/${encodeURIComponent(name)}`).then(() => {
|
||||
dispatch(removeReactionSuccess(announcementId, name));
|
||||
}).catch(err => {
|
||||
dispatch(removeReactionFail(announcementId, name, err));
|
||||
|
|
|
@ -24,13 +24,13 @@ export function fetchBlocks() {
|
|||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => dispatch(fetchBlocksFail(error)));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchBlocksRequest() {
|
||||
return {
|
||||
type: BLOCKS_FETCH_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchBlocksSuccess(accounts, next) {
|
||||
return {
|
||||
|
@ -38,14 +38,14 @@ export function fetchBlocksSuccess(accounts, next) {
|
|||
accounts,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchBlocksFail(error) {
|
||||
return {
|
||||
type: BLOCKS_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandBlocks() {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -64,13 +64,13 @@ export function expandBlocks() {
|
|||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => dispatch(expandBlocksFail(error)));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandBlocksRequest() {
|
||||
return {
|
||||
type: BLOCKS_EXPAND_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandBlocksSuccess(accounts, next) {
|
||||
return {
|
||||
|
@ -78,14 +78,14 @@ export function expandBlocksSuccess(accounts, next) {
|
|||
accounts,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandBlocksFail(error) {
|
||||
return {
|
||||
type: BLOCKS_EXPAND_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function initBlockModal(account) {
|
||||
return dispatch => {
|
||||
|
|
|
@ -25,13 +25,13 @@ export function fetchBookmarkedStatuses() {
|
|||
dispatch(fetchBookmarkedStatusesFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchBookmarkedStatusesRequest() {
|
||||
return {
|
||||
type: BOOKMARKED_STATUSES_FETCH_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchBookmarkedStatusesSuccess(statuses, next) {
|
||||
return {
|
||||
|
@ -39,14 +39,14 @@ export function fetchBookmarkedStatusesSuccess(statuses, next) {
|
|||
statuses,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchBookmarkedStatusesFail(error) {
|
||||
return {
|
||||
type: BOOKMARKED_STATUSES_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandBookmarkedStatuses() {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -66,13 +66,13 @@ export function expandBookmarkedStatuses() {
|
|||
dispatch(expandBookmarkedStatusesFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandBookmarkedStatusesRequest() {
|
||||
return {
|
||||
type: BOOKMARKED_STATUSES_EXPAND_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandBookmarkedStatusesSuccess(statuses, next) {
|
||||
return {
|
||||
|
@ -80,11 +80,11 @@ export function expandBookmarkedStatusesSuccess(statuses, next) {
|
|||
statuses,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandBookmarkedStatusesFail(error) {
|
||||
return {
|
||||
type: BOOKMARKED_STATUSES_EXPAND_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ export function addColumn(id, params) {
|
|||
|
||||
dispatch(saveSettings());
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function removeColumn(uuid) {
|
||||
return dispatch => {
|
||||
|
@ -26,7 +26,7 @@ export function removeColumn(uuid) {
|
|||
|
||||
dispatch(saveSettings());
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function moveColumn(uuid, direction) {
|
||||
return dispatch => {
|
||||
|
@ -38,7 +38,7 @@ export function moveColumn(uuid, direction) {
|
|||
|
||||
dispatch(saveSettings());
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changeColumnParams(uuid, path, value) {
|
||||
return dispatch => {
|
||||
|
|
|
@ -94,14 +94,14 @@ export function setComposeToStatus(status, text, spoiler_text) {
|
|||
text,
|
||||
spoiler_text,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changeCompose(text) {
|
||||
return {
|
||||
type: COMPOSE_CHANGE,
|
||||
text: text,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function replyCompose(status, routerHistory) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -112,19 +112,19 @@ export function replyCompose(status, routerHistory) {
|
|||
|
||||
ensureComposeIsVisible(getState, routerHistory);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function cancelReplyCompose() {
|
||||
return {
|
||||
type: COMPOSE_REPLY_CANCEL,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function resetCompose() {
|
||||
return {
|
||||
type: COMPOSE_RESET,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function mentionCompose(account, routerHistory) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -135,7 +135,7 @@ export function mentionCompose(account, routerHistory) {
|
|||
|
||||
ensureComposeIsVisible(getState, routerHistory);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function directCompose(account, routerHistory) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -146,7 +146,7 @@ export function directCompose(account, routerHistory) {
|
|||
|
||||
ensureComposeIsVisible(getState, routerHistory);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function submitCompose(routerHistory) {
|
||||
return function (dispatch, getState) {
|
||||
|
@ -160,6 +160,18 @@ export function submitCompose(routerHistory) {
|
|||
|
||||
dispatch(submitComposeRequest());
|
||||
|
||||
// If we're editing a post with media attachments, those have not
|
||||
// necessarily been changed on the server. Do it now in the same
|
||||
// API call.
|
||||
let media_attributes;
|
||||
if (statusId !== null) {
|
||||
media_attributes = media.map(item => ({
|
||||
id: item.get('id'),
|
||||
description: item.get('description'),
|
||||
focus: item.get('focus'),
|
||||
}));
|
||||
}
|
||||
|
||||
api(getState).request({
|
||||
url: statusId === null ? '/api/v1/statuses' : `/api/v1/statuses/${statusId}`,
|
||||
method: statusId === null ? 'post' : 'put',
|
||||
|
@ -167,6 +179,7 @@ export function submitCompose(routerHistory) {
|
|||
status,
|
||||
in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
|
||||
media_ids: media.map(item => item.get('id')),
|
||||
media_attributes,
|
||||
sensitive: getState().getIn(['compose', 'sensitive']),
|
||||
spoiler_text: getState().getIn(['compose', 'spoiler']) ? getState().getIn(['compose', 'spoiler_text'], '') : '',
|
||||
visibility: getState().getIn(['compose', 'privacy']),
|
||||
|
@ -211,27 +224,27 @@ export function submitCompose(routerHistory) {
|
|||
dispatch(submitComposeFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function submitComposeRequest() {
|
||||
return {
|
||||
type: COMPOSE_SUBMIT_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function submitComposeSuccess(status) {
|
||||
return {
|
||||
type: COMPOSE_SUBMIT_SUCCESS,
|
||||
status: status,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function submitComposeFail(error) {
|
||||
return {
|
||||
type: COMPOSE_SUBMIT_FAIL,
|
||||
error: error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function uploadCompose(files) {
|
||||
return function (dispatch, getState) {
|
||||
|
@ -294,9 +307,9 @@ export function uploadCompose(files) {
|
|||
}
|
||||
});
|
||||
}).catch(error => dispatch(uploadComposeFail(error)));
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const uploadComposeProcessing = () => ({
|
||||
type: COMPOSE_UPLOAD_PROCESSING,
|
||||
|
@ -354,14 +367,14 @@ export function initMediaEditModal(id) {
|
|||
|
||||
dispatch(openModal('FOCAL_POINT', { id }));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function onChangeMediaDescription(description) {
|
||||
return {
|
||||
type: COMPOSE_CHANGE_MEDIA_DESCRIPTION,
|
||||
description,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function onChangeMediaFocus(focusX, focusY) {
|
||||
return {
|
||||
|
@ -369,34 +382,55 @@ export function onChangeMediaFocus(focusX, focusY) {
|
|||
focusX,
|
||||
focusY,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changeUploadCompose(id, params) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(changeUploadComposeRequest());
|
||||
|
||||
api(getState).put(`/api/v1/media/${id}`, params).then(response => {
|
||||
dispatch(changeUploadComposeSuccess(response.data));
|
||||
}).catch(error => {
|
||||
dispatch(changeUploadComposeFail(id, error));
|
||||
});
|
||||
let media = getState().getIn(['compose', 'media_attachments']).find((item) => item.get('id') === id);
|
||||
|
||||
// Editing already-attached media is deferred to editing the post itself.
|
||||
// For simplicity's sake, fake an API reply.
|
||||
if (media && !media.get('unattached')) {
|
||||
let { description, focus } = params;
|
||||
const data = media.toJS();
|
||||
|
||||
if (description) {
|
||||
data.description = description;
|
||||
}
|
||||
|
||||
if (focus) {
|
||||
focus = focus.split(',');
|
||||
data.meta = { focus: { x: parseFloat(focus[0]), y: parseFloat(focus[1]) } };
|
||||
}
|
||||
|
||||
dispatch(changeUploadComposeSuccess(data, true));
|
||||
} else {
|
||||
api(getState).put(`/api/v1/media/${id}`, params).then(response => {
|
||||
dispatch(changeUploadComposeSuccess(response.data, false));
|
||||
}).catch(error => {
|
||||
dispatch(changeUploadComposeFail(id, error));
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changeUploadComposeRequest() {
|
||||
return {
|
||||
type: COMPOSE_UPLOAD_CHANGE_REQUEST,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changeUploadComposeSuccess(media) {
|
||||
export function changeUploadComposeSuccess(media, attached) {
|
||||
return {
|
||||
type: COMPOSE_UPLOAD_CHANGE_SUCCESS,
|
||||
media: media,
|
||||
attached: attached,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changeUploadComposeFail(error) {
|
||||
return {
|
||||
|
@ -404,14 +438,14 @@ export function changeUploadComposeFail(error) {
|
|||
error: error,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function uploadComposeRequest() {
|
||||
return {
|
||||
type: COMPOSE_UPLOAD_REQUEST,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function uploadComposeProgress(loaded, total) {
|
||||
return {
|
||||
|
@ -419,7 +453,7 @@ export function uploadComposeProgress(loaded, total) {
|
|||
loaded: loaded,
|
||||
total: total,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function uploadComposeSuccess(media, file) {
|
||||
return {
|
||||
|
@ -428,7 +462,7 @@ export function uploadComposeSuccess(media, file) {
|
|||
file: file,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function uploadComposeFail(error) {
|
||||
return {
|
||||
|
@ -436,14 +470,14 @@ export function uploadComposeFail(error) {
|
|||
error: error,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function undoUploadCompose(media_id) {
|
||||
return {
|
||||
type: COMPOSE_UPLOAD_UNDO,
|
||||
media_id: media_id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function clearComposeSuggestions() {
|
||||
if (fetchComposeSuggestionsAccountsController) {
|
||||
|
@ -452,7 +486,7 @@ export function clearComposeSuggestions() {
|
|||
return {
|
||||
type: COMPOSE_SUGGESTIONS_CLEAR,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => {
|
||||
if (fetchComposeSuggestionsAccountsController) {
|
||||
|
@ -530,7 +564,7 @@ export function fetchComposeSuggestions(token) {
|
|||
break;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function readyComposeSuggestionsEmojis(token, emojis) {
|
||||
return {
|
||||
|
@ -538,7 +572,7 @@ export function readyComposeSuggestionsEmojis(token, emojis) {
|
|||
token,
|
||||
emojis,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function readyComposeSuggestionsAccounts(token, accounts) {
|
||||
return {
|
||||
|
@ -546,7 +580,7 @@ export function readyComposeSuggestionsAccounts(token, accounts) {
|
|||
token,
|
||||
accounts,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const readyComposeSuggestionsTags = (token, tags) => ({
|
||||
type: COMPOSE_SUGGESTIONS_READY,
|
||||
|
@ -591,7 +625,7 @@ export function selectComposeSuggestion(position, token, suggestion, path) {
|
|||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function updateSuggestionTags(token) {
|
||||
return {
|
||||
|
@ -652,19 +686,19 @@ export function mountCompose() {
|
|||
return {
|
||||
type: COMPOSE_MOUNT,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unmountCompose() {
|
||||
return {
|
||||
type: COMPOSE_UNMOUNT,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changeComposeSensitivity() {
|
||||
return {
|
||||
type: COMPOSE_SENSITIVITY_CHANGE,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const changeComposeLanguage = language => ({
|
||||
type: COMPOSE_LANGUAGE_CHANGE,
|
||||
|
@ -675,21 +709,21 @@ export function changeComposeSpoilerness() {
|
|||
return {
|
||||
type: COMPOSE_SPOILERNESS_CHANGE,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changeComposeSpoilerText(text) {
|
||||
return {
|
||||
type: COMPOSE_SPOILER_TEXT_CHANGE,
|
||||
text,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changeComposeVisibility(value) {
|
||||
return {
|
||||
type: COMPOSE_VISIBILITY_CHANGE,
|
||||
value,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function insertEmojiCompose(position, emoji, needsSpace) {
|
||||
return {
|
||||
|
@ -698,33 +732,33 @@ export function insertEmojiCompose(position, emoji, needsSpace) {
|
|||
emoji,
|
||||
needsSpace,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changeComposing(value) {
|
||||
return {
|
||||
type: COMPOSE_COMPOSING_CHANGE,
|
||||
value,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function addPoll() {
|
||||
return {
|
||||
type: COMPOSE_POLL_ADD,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function removePoll() {
|
||||
return {
|
||||
type: COMPOSE_POLL_REMOVE,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function addPollOption(title) {
|
||||
return {
|
||||
type: COMPOSE_POLL_OPTION_ADD,
|
||||
title,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changePollOption(index, title) {
|
||||
return {
|
||||
|
@ -732,14 +766,14 @@ export function changePollOption(index, title) {
|
|||
index,
|
||||
title,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function removePollOption(index) {
|
||||
return {
|
||||
type: COMPOSE_POLL_OPTION_REMOVE,
|
||||
index,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function changePollSettings(expiresIn, isMultiple) {
|
||||
return {
|
||||
|
@ -747,4 +781,4 @@ export function changePollSettings(expiresIn, isMultiple) {
|
|||
expiresIn,
|
||||
isMultiple,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@ export function fetchCustomEmojis() {
|
|||
dispatch(fetchCustomEmojisFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchCustomEmojisRequest() {
|
||||
return {
|
||||
type: CUSTOM_EMOJIS_FETCH_REQUEST,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchCustomEmojisSuccess(custom_emojis) {
|
||||
return {
|
||||
|
@ -29,7 +29,7 @@ export function fetchCustomEmojisSuccess(custom_emojis) {
|
|||
custom_emojis,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchCustomEmojisFail(error) {
|
||||
return {
|
||||
|
@ -37,4 +37,4 @@ export function fetchCustomEmojisFail(error) {
|
|||
error,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -29,14 +29,14 @@ export function blockDomain(domain) {
|
|||
dispatch(blockDomainFail(domain, err));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function blockDomainRequest(domain) {
|
||||
return {
|
||||
type: DOMAIN_BLOCK_REQUEST,
|
||||
domain,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function blockDomainSuccess(domain, accounts) {
|
||||
return {
|
||||
|
@ -44,7 +44,7 @@ export function blockDomainSuccess(domain, accounts) {
|
|||
domain,
|
||||
accounts,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function blockDomainFail(domain, error) {
|
||||
return {
|
||||
|
@ -52,7 +52,7 @@ export function blockDomainFail(domain, error) {
|
|||
domain,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unblockDomain(domain) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -66,14 +66,14 @@ export function unblockDomain(domain) {
|
|||
dispatch(unblockDomainFail(domain, err));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unblockDomainRequest(domain) {
|
||||
return {
|
||||
type: DOMAIN_UNBLOCK_REQUEST,
|
||||
domain,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unblockDomainSuccess(domain, accounts) {
|
||||
return {
|
||||
|
@ -81,7 +81,7 @@ export function unblockDomainSuccess(domain, accounts) {
|
|||
domain,
|
||||
accounts,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unblockDomainFail(domain, error) {
|
||||
return {
|
||||
|
@ -89,7 +89,7 @@ export function unblockDomainFail(domain, error) {
|
|||
domain,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchDomainBlocks() {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -102,13 +102,13 @@ export function fetchDomainBlocks() {
|
|||
dispatch(fetchDomainBlocksFail(err));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchDomainBlocksRequest() {
|
||||
return {
|
||||
type: DOMAIN_BLOCKS_FETCH_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchDomainBlocksSuccess(domains, next) {
|
||||
return {
|
||||
|
@ -116,14 +116,14 @@ export function fetchDomainBlocksSuccess(domains, next) {
|
|||
domains,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchDomainBlocksFail(error) {
|
||||
return {
|
||||
type: DOMAIN_BLOCKS_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandDomainBlocks() {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -142,13 +142,13 @@ export function expandDomainBlocks() {
|
|||
dispatch(expandDomainBlocksFail(err));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandDomainBlocksRequest() {
|
||||
return {
|
||||
type: DOMAIN_BLOCKS_EXPAND_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandDomainBlocksSuccess(domains, next) {
|
||||
return {
|
||||
|
@ -156,11 +156,11 @@ export function expandDomainBlocksSuccess(domains, next) {
|
|||
domains,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandDomainBlocksFail(error) {
|
||||
return {
|
||||
type: DOMAIN_BLOCKS_EXPAND_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
export const DROPDOWN_MENU_OPEN = 'DROPDOWN_MENU_OPEN';
|
||||
export const DROPDOWN_MENU_CLOSE = 'DROPDOWN_MENU_CLOSE';
|
||||
|
||||
export function openDropdownMenu(id, placement, keyboard, scroll_key) {
|
||||
return { type: DROPDOWN_MENU_OPEN, id, placement, keyboard, scroll_key };
|
||||
export function openDropdownMenu(id, keyboard, scroll_key) {
|
||||
return { type: DROPDOWN_MENU_OPEN, id, keyboard, scroll_key };
|
||||
}
|
||||
|
||||
export function closeDropdownMenu(id) {
|
||||
|
|
|
@ -11,4 +11,4 @@ export function useEmoji(emoji) {
|
|||
|
||||
dispatch(saveSettings());
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -25,14 +25,14 @@ export function fetchFavouritedStatuses() {
|
|||
dispatch(fetchFavouritedStatusesFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFavouritedStatusesRequest() {
|
||||
return {
|
||||
type: FAVOURITED_STATUSES_FETCH_REQUEST,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFavouritedStatusesSuccess(statuses, next) {
|
||||
return {
|
||||
|
@ -41,7 +41,7 @@ export function fetchFavouritedStatusesSuccess(statuses, next) {
|
|||
next,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFavouritedStatusesFail(error) {
|
||||
return {
|
||||
|
@ -49,7 +49,7 @@ export function fetchFavouritedStatusesFail(error) {
|
|||
error,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFavouritedStatuses() {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -69,13 +69,13 @@ export function expandFavouritedStatuses() {
|
|||
dispatch(expandFavouritedStatusesFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFavouritedStatusesRequest() {
|
||||
return {
|
||||
type: FAVOURITED_STATUSES_EXPAND_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFavouritedStatusesSuccess(statuses, next) {
|
||||
return {
|
||||
|
@ -83,11 +83,11 @@ export function expandFavouritedStatusesSuccess(statuses, next) {
|
|||
statuses,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFavouritedStatusesFail(error) {
|
||||
return {
|
||||
type: FAVOURITED_STATUSES_EXPAND_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@ export function setHeight (key, id, height) {
|
|||
id,
|
||||
height,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function clearHeight () {
|
||||
return {
|
||||
type: HEIGHT_CACHE_CLEAR,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ export function reblog(status, visibility) {
|
|||
dispatch(reblogFail(status, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblog(status) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -67,7 +67,7 @@ export function unreblog(status) {
|
|||
dispatch(unreblogFail(status, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function reblogRequest(status) {
|
||||
return {
|
||||
|
@ -75,7 +75,7 @@ export function reblogRequest(status) {
|
|||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function reblogSuccess(status) {
|
||||
return {
|
||||
|
@ -83,7 +83,7 @@ export function reblogSuccess(status) {
|
|||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function reblogFail(status, error) {
|
||||
return {
|
||||
|
@ -92,7 +92,7 @@ export function reblogFail(status, error) {
|
|||
error: error,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblogRequest(status) {
|
||||
return {
|
||||
|
@ -100,7 +100,7 @@ export function unreblogRequest(status) {
|
|||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblogSuccess(status) {
|
||||
return {
|
||||
|
@ -108,7 +108,7 @@ export function unreblogSuccess(status) {
|
|||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unreblogFail(status, error) {
|
||||
return {
|
||||
|
@ -117,7 +117,7 @@ export function unreblogFail(status, error) {
|
|||
error: error,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function favourite(status) {
|
||||
return function (dispatch, getState) {
|
||||
|
@ -130,7 +130,7 @@ export function favourite(status) {
|
|||
dispatch(favouriteFail(status, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unfavourite(status) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -143,7 +143,7 @@ export function unfavourite(status) {
|
|||
dispatch(unfavouriteFail(status, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function favouriteRequest(status) {
|
||||
return {
|
||||
|
@ -151,7 +151,7 @@ export function favouriteRequest(status) {
|
|||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function favouriteSuccess(status) {
|
||||
return {
|
||||
|
@ -159,7 +159,7 @@ export function favouriteSuccess(status) {
|
|||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function favouriteFail(status, error) {
|
||||
return {
|
||||
|
@ -168,7 +168,7 @@ export function favouriteFail(status, error) {
|
|||
error: error,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unfavouriteRequest(status) {
|
||||
return {
|
||||
|
@ -176,7 +176,7 @@ export function unfavouriteRequest(status) {
|
|||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unfavouriteSuccess(status) {
|
||||
return {
|
||||
|
@ -184,7 +184,7 @@ export function unfavouriteSuccess(status) {
|
|||
status: status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unfavouriteFail(status, error) {
|
||||
return {
|
||||
|
@ -193,7 +193,7 @@ export function unfavouriteFail(status, error) {
|
|||
error: error,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function bookmark(status) {
|
||||
return function (dispatch, getState) {
|
||||
|
@ -206,7 +206,7 @@ export function bookmark(status) {
|
|||
dispatch(bookmarkFail(status, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unbookmark(status) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -219,14 +219,14 @@ export function unbookmark(status) {
|
|||
dispatch(unbookmarkFail(status, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function bookmarkRequest(status) {
|
||||
return {
|
||||
type: BOOKMARK_REQUEST,
|
||||
status: status,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function bookmarkSuccess(status, response) {
|
||||
return {
|
||||
|
@ -234,7 +234,7 @@ export function bookmarkSuccess(status, response) {
|
|||
status: status,
|
||||
response: response,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function bookmarkFail(status, error) {
|
||||
return {
|
||||
|
@ -242,14 +242,14 @@ export function bookmarkFail(status, error) {
|
|||
status: status,
|
||||
error: error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unbookmarkRequest(status) {
|
||||
return {
|
||||
type: UNBOOKMARK_REQUEST,
|
||||
status: status,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unbookmarkSuccess(status, response) {
|
||||
return {
|
||||
|
@ -257,7 +257,7 @@ export function unbookmarkSuccess(status, response) {
|
|||
status: status,
|
||||
response: response,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unbookmarkFail(status, error) {
|
||||
return {
|
||||
|
@ -265,7 +265,7 @@ export function unbookmarkFail(status, error) {
|
|||
status: status,
|
||||
error: error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchReblogs(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -278,14 +278,14 @@ export function fetchReblogs(id) {
|
|||
dispatch(fetchReblogsFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchReblogsRequest(id) {
|
||||
return {
|
||||
type: REBLOGS_FETCH_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchReblogsSuccess(id, accounts) {
|
||||
return {
|
||||
|
@ -293,14 +293,14 @@ export function fetchReblogsSuccess(id, accounts) {
|
|||
id,
|
||||
accounts,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchReblogsFail(id, error) {
|
||||
return {
|
||||
type: REBLOGS_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFavourites(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -313,14 +313,14 @@ export function fetchFavourites(id) {
|
|||
dispatch(fetchFavouritesFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFavouritesRequest(id) {
|
||||
return {
|
||||
type: FAVOURITES_FETCH_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFavouritesSuccess(id, accounts) {
|
||||
return {
|
||||
|
@ -328,14 +328,14 @@ export function fetchFavouritesSuccess(id, accounts) {
|
|||
id,
|
||||
accounts,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFavouritesFail(id, error) {
|
||||
return {
|
||||
type: FAVOURITES_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function pin(status) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -348,7 +348,7 @@ export function pin(status) {
|
|||
dispatch(pinFail(status, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function pinRequest(status) {
|
||||
return {
|
||||
|
@ -356,7 +356,7 @@ export function pinRequest(status) {
|
|||
status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function pinSuccess(status) {
|
||||
return {
|
||||
|
@ -364,7 +364,7 @@ export function pinSuccess(status) {
|
|||
status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function pinFail(status, error) {
|
||||
return {
|
||||
|
@ -373,7 +373,7 @@ export function pinFail(status, error) {
|
|||
error,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unpin (status) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -386,7 +386,7 @@ export function unpin (status) {
|
|||
dispatch(unpinFail(status, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unpinRequest(status) {
|
||||
return {
|
||||
|
@ -394,7 +394,7 @@ export function unpinRequest(status) {
|
|||
status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unpinSuccess(status) {
|
||||
return {
|
||||
|
@ -402,7 +402,7 @@ export function unpinSuccess(status) {
|
|||
status,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unpinFail(status, error) {
|
||||
return {
|
||||
|
@ -411,4 +411,4 @@ export function unpinFail(status, error) {
|
|||
error,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ export function submitMarkersSuccess({ home, notifications }) {
|
|||
home: (home || {}).last_read_id,
|
||||
notifications: (notifications || {}).last_read_id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function submitMarkers(params = {}) {
|
||||
const result = (dispatch, getState) => debouncedSubmitMarkers(dispatch, getState);
|
||||
|
@ -111,7 +111,7 @@ export function submitMarkers(params = {}) {
|
|||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export const fetchMarkers = () => (dispatch, getState) => {
|
||||
const params = { timeline: ['notifications'] };
|
||||
|
@ -130,7 +130,7 @@ export function fetchMarkersRequest() {
|
|||
type: MARKERS_FETCH_REQUEST,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchMarkersSuccess(markers) {
|
||||
return {
|
||||
|
@ -138,7 +138,7 @@ export function fetchMarkersSuccess(markers) {
|
|||
markers,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchMarkersFail(error) {
|
||||
return {
|
||||
|
@ -147,4 +147,4 @@ export function fetchMarkersFail(error) {
|
|||
skipLoading: true,
|
||||
skipAlert: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ export function openModal(type, props) {
|
|||
modalType: type,
|
||||
modalProps: props,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function closeModal(type, options = { ignoreFocus: false }) {
|
||||
return {
|
||||
|
@ -15,4 +15,4 @@ export function closeModal(type, options = { ignoreFocus: false }) {
|
|||
modalType: type,
|
||||
ignoreFocus: options.ignoreFocus,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -26,13 +26,13 @@ export function fetchMutes() {
|
|||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => dispatch(fetchMutesFail(error)));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchMutesRequest() {
|
||||
return {
|
||||
type: MUTES_FETCH_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchMutesSuccess(accounts, next) {
|
||||
return {
|
||||
|
@ -40,14 +40,14 @@ export function fetchMutesSuccess(accounts, next) {
|
|||
accounts,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchMutesFail(error) {
|
||||
return {
|
||||
type: MUTES_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandMutes() {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -66,13 +66,13 @@ export function expandMutes() {
|
|||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||
}).catch(error => dispatch(expandMutesFail(error)));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandMutesRequest() {
|
||||
return {
|
||||
type: MUTES_EXPAND_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandMutesSuccess(accounts, next) {
|
||||
return {
|
||||
|
@ -80,14 +80,14 @@ export function expandMutesSuccess(accounts, next) {
|
|||
accounts,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandMutesFail(error) {
|
||||
return {
|
||||
type: MUTES_EXPAND_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function initMuteModal(account) {
|
||||
return dispatch => {
|
||||
|
|
|
@ -118,7 +118,7 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
|
|||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const excludeTypesFromSettings = state => state.getIn(['settings', 'notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS();
|
||||
|
||||
|
@ -197,14 +197,14 @@ export function expandNotifications({ maxId, forceLoad } = {}, done = noOp) {
|
|||
done();
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandNotificationsRequest(isLoadingMore) {
|
||||
return {
|
||||
type: NOTIFICATIONS_EXPAND_REQUEST,
|
||||
skipLoading: !isLoadingMore,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandNotificationsSuccess(notifications, next, isLoadingMore, isLoadingRecent, usePendingItems) {
|
||||
return {
|
||||
|
@ -215,7 +215,7 @@ export function expandNotificationsSuccess(notifications, next, isLoadingMore, i
|
|||
usePendingItems,
|
||||
skipLoading: !isLoadingMore,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandNotificationsFail(error, isLoadingMore) {
|
||||
return {
|
||||
|
@ -224,7 +224,7 @@ export function expandNotificationsFail(error, isLoadingMore) {
|
|||
skipLoading: !isLoadingMore,
|
||||
skipAlert: !isLoadingMore || error.name === 'AbortError',
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function clearNotifications() {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -234,14 +234,14 @@ export function clearNotifications() {
|
|||
|
||||
api(getState).post('/api/v1/notifications/clear');
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function scrollTopNotifications(top) {
|
||||
return {
|
||||
type: NOTIFICATIONS_SCROLL_TOP,
|
||||
top,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function setFilter (filterType) {
|
||||
return dispatch => {
|
||||
|
@ -253,7 +253,7 @@ export function setFilter (filterType) {
|
|||
dispatch(expandNotifications({ forceLoad: true }));
|
||||
dispatch(saveSettings());
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const mountNotifications = () => ({
|
||||
type: NOTIFICATIONS_MOUNT,
|
||||
|
@ -291,7 +291,7 @@ export function requestBrowserPermission(callback = noOp) {
|
|||
callback(permission);
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function setBrowserSupport (value) {
|
||||
return {
|
||||
|
|
|
@ -18,13 +18,13 @@ export function fetchPinnedStatuses() {
|
|||
dispatch(fetchPinnedStatusesFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPinnedStatusesRequest() {
|
||||
return {
|
||||
type: PINNED_STATUSES_FETCH_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPinnedStatusesSuccess(statuses, next) {
|
||||
return {
|
||||
|
@ -32,11 +32,11 @@ export function fetchPinnedStatusesSuccess(statuses, next) {
|
|||
statuses,
|
||||
next,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchPinnedStatusesFail(error) {
|
||||
return {
|
||||
type: PINNED_STATUSES_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,13 +19,13 @@ export function changeSearch(value) {
|
|||
type: SEARCH_CHANGE,
|
||||
value,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function clearSearch() {
|
||||
return {
|
||||
type: SEARCH_CLEAR,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function submitSearch() {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -60,13 +60,13 @@ export function submitSearch() {
|
|||
dispatch(fetchSearchFail(error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchSearchRequest() {
|
||||
return {
|
||||
type: SEARCH_FETCH_REQUEST,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchSearchSuccess(results, searchTerm) {
|
||||
return {
|
||||
|
@ -74,14 +74,14 @@ export function fetchSearchSuccess(results, searchTerm) {
|
|||
results,
|
||||
searchTerm,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchSearchFail(error) {
|
||||
return {
|
||||
type: SEARCH_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const expandSearch = type => (dispatch, getState) => {
|
||||
const value = getState().getIn(['search', 'value']);
|
||||
|
|
|
@ -15,7 +15,7 @@ export function changeSetting(path, value) {
|
|||
|
||||
dispatch(saveSettings());
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const debouncedSave = debounce((dispatch, getState) => {
|
||||
if (getState().getIn(['settings', 'saved'])) {
|
||||
|
@ -31,4 +31,4 @@ const debouncedSave = debounce((dispatch, getState) => {
|
|||
|
||||
export function saveSettings() {
|
||||
return (dispatch, getState) => debouncedSave(dispatch, getState);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ export function fetchStatusRequest(id, skipLoading) {
|
|||
id,
|
||||
skipLoading,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchStatus(id, forceFetch = false) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -66,14 +66,14 @@ export function fetchStatus(id, forceFetch = false) {
|
|||
dispatch(fetchStatusFail(id, error, skipLoading));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchStatusSuccess(skipLoading) {
|
||||
return {
|
||||
type: STATUS_FETCH_SUCCESS,
|
||||
skipLoading,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchStatusFail(id, error, skipLoading) {
|
||||
return {
|
||||
|
@ -83,7 +83,7 @@ export function fetchStatusFail(id, error, skipLoading) {
|
|||
skipLoading,
|
||||
skipAlert: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function redraft(status, raw_text) {
|
||||
return {
|
||||
|
@ -91,7 +91,7 @@ export function redraft(status, raw_text) {
|
|||
status,
|
||||
raw_text,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const editStatus = (id, routerHistory) => (dispatch, getState) => {
|
||||
let status = getState().getIn(['statuses', id]);
|
||||
|
@ -147,21 +147,21 @@ export function deleteStatus(id, routerHistory, withRedraft = false) {
|
|||
dispatch(deleteStatusFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteStatusRequest(id) {
|
||||
return {
|
||||
type: STATUS_DELETE_REQUEST,
|
||||
id: id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteStatusSuccess(id) {
|
||||
return {
|
||||
type: STATUS_DELETE_SUCCESS,
|
||||
id: id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteStatusFail(id, error) {
|
||||
return {
|
||||
|
@ -169,7 +169,7 @@ export function deleteStatusFail(id, error) {
|
|||
id: id,
|
||||
error: error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const updateStatus = status => dispatch =>
|
||||
dispatch(importFetchedStatus(status));
|
||||
|
@ -190,14 +190,14 @@ export function fetchContext(id) {
|
|||
dispatch(fetchContextFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchContextRequest(id) {
|
||||
return {
|
||||
type: CONTEXT_FETCH_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchContextSuccess(id, ancestors, descendants) {
|
||||
return {
|
||||
|
@ -207,7 +207,7 @@ export function fetchContextSuccess(id, ancestors, descendants) {
|
|||
descendants,
|
||||
statuses: ancestors.concat(descendants),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchContextFail(id, error) {
|
||||
return {
|
||||
|
@ -216,7 +216,7 @@ export function fetchContextFail(id, error) {
|
|||
error,
|
||||
skipAlert: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function muteStatus(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -228,21 +228,21 @@ export function muteStatus(id) {
|
|||
dispatch(muteStatusFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function muteStatusRequest(id) {
|
||||
return {
|
||||
type: STATUS_MUTE_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function muteStatusSuccess(id) {
|
||||
return {
|
||||
type: STATUS_MUTE_SUCCESS,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function muteStatusFail(id, error) {
|
||||
return {
|
||||
|
@ -250,7 +250,7 @@ export function muteStatusFail(id, error) {
|
|||
id,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unmuteStatus(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -262,21 +262,21 @@ export function unmuteStatus(id) {
|
|||
dispatch(unmuteStatusFail(id, error));
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unmuteStatusRequest(id) {
|
||||
return {
|
||||
type: STATUS_UNMUTE_REQUEST,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unmuteStatusSuccess(id) {
|
||||
return {
|
||||
type: STATUS_UNMUTE_SUCCESS,
|
||||
id,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function unmuteStatusFail(id, error) {
|
||||
return {
|
||||
|
@ -284,7 +284,7 @@ export function unmuteStatusFail(id, error) {
|
|||
id,
|
||||
error,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function hideStatus(ids) {
|
||||
if (!Array.isArray(ids)) {
|
||||
|
@ -295,7 +295,7 @@ export function hideStatus(ids) {
|
|||
type: STATUS_HIDE,
|
||||
ids,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function revealStatus(ids) {
|
||||
if (!Array.isArray(ids)) {
|
||||
|
@ -306,7 +306,7 @@ export function revealStatus(ids) {
|
|||
type: STATUS_REVEAL,
|
||||
ids,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function toggleStatusCollapse(id, isCollapsed) {
|
||||
return {
|
||||
|
@ -314,7 +314,7 @@ export function toggleStatusCollapse(id, isCollapsed) {
|
|||
id,
|
||||
isCollapsed,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const translateStatus = id => (dispatch, getState) => {
|
||||
dispatch(translateStatusRequest(id));
|
||||
|
|
|
@ -21,4 +21,4 @@ export function hydrateStore(rawState) {
|
|||
dispatch(hydrateCompose());
|
||||
dispatch(importFetchedAccounts(Object.values(rawState.accounts)));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -21,14 +21,14 @@ export function fetchSuggestions(withRelationships = false) {
|
|||
}
|
||||
}).catch(error => dispatch(fetchSuggestionsFail(error)));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchSuggestionsRequest() {
|
||||
return {
|
||||
type: SUGGESTIONS_FETCH_REQUEST,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchSuggestionsSuccess(suggestions) {
|
||||
return {
|
||||
|
@ -36,7 +36,7 @@ export function fetchSuggestionsSuccess(suggestions) {
|
|||
suggestions,
|
||||
skipLoading: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchSuggestionsFail(error) {
|
||||
return {
|
||||
|
@ -45,7 +45,7 @@ export function fetchSuggestionsFail(error) {
|
|||
skipLoading: true,
|
||||
skipAlert: true,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const dismissSuggestion = accountId => (dispatch, getState) => {
|
||||
dispatch({
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
import api from '../api';
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
export const HASHTAG_FETCH_REQUEST = 'HASHTAG_FETCH_REQUEST';
|
||||
export const HASHTAG_FETCH_SUCCESS = 'HASHTAG_FETCH_SUCCESS';
|
||||
export const HASHTAG_FETCH_FAIL = 'HASHTAG_FETCH_FAIL';
|
||||
|
||||
export const FOLLOWED_HASHTAGS_FETCH_REQUEST = 'FOLLOWED_HASHTAGS_FETCH_REQUEST';
|
||||
export const FOLLOWED_HASHTAGS_FETCH_SUCCESS = 'FOLLOWED_HASHTAGS_FETCH_SUCCESS';
|
||||
export const FOLLOWED_HASHTAGS_FETCH_FAIL = 'FOLLOWED_HASHTAGS_FETCH_FAIL';
|
||||
|
||||
export const FOLLOWED_HASHTAGS_EXPAND_REQUEST = 'FOLLOWED_HASHTAGS_EXPAND_REQUEST';
|
||||
export const FOLLOWED_HASHTAGS_EXPAND_SUCCESS = 'FOLLOWED_HASHTAGS_EXPAND_SUCCESS';
|
||||
export const FOLLOWED_HASHTAGS_EXPAND_FAIL = 'FOLLOWED_HASHTAGS_EXPAND_FAIL';
|
||||
|
||||
export const HASHTAG_FOLLOW_REQUEST = 'HASHTAG_FOLLOW_REQUEST';
|
||||
export const HASHTAG_FOLLOW_SUCCESS = 'HASHTAG_FOLLOW_SUCCESS';
|
||||
export const HASHTAG_FOLLOW_FAIL = 'HASHTAG_FOLLOW_FAIL';
|
||||
|
@ -37,6 +45,78 @@ export const fetchHashtagFail = error => ({
|
|||
error,
|
||||
});
|
||||
|
||||
export const fetchFollowedHashtags = () => (dispatch, getState) => {
|
||||
dispatch(fetchFollowedHashtagsRequest());
|
||||
|
||||
api(getState).get('/api/v1/followed_tags').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
dispatch(fetchFollowedHashtagsSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(err => {
|
||||
dispatch(fetchFollowedHashtagsFail(err));
|
||||
});
|
||||
};
|
||||
|
||||
export function fetchFollowedHashtagsRequest() {
|
||||
return {
|
||||
type: FOLLOWED_HASHTAGS_FETCH_REQUEST,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowedHashtagsSuccess(followed_tags, next) {
|
||||
return {
|
||||
type: FOLLOWED_HASHTAGS_FETCH_SUCCESS,
|
||||
followed_tags,
|
||||
next,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFollowedHashtagsFail(error) {
|
||||
return {
|
||||
type: FOLLOWED_HASHTAGS_FETCH_FAIL,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowedHashtags() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['followed_tags', 'next']);
|
||||
|
||||
if (url === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(expandFollowedHashtagsRequest());
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
dispatch(expandFollowedHashtagsSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(error => {
|
||||
dispatch(expandFollowedHashtagsFail(error));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowedHashtagsRequest() {
|
||||
return {
|
||||
type: FOLLOWED_HASHTAGS_EXPAND_REQUEST,
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowedHashtagsSuccess(followed_tags, next) {
|
||||
return {
|
||||
type: FOLLOWED_HASHTAGS_EXPAND_SUCCESS,
|
||||
followed_tags,
|
||||
next,
|
||||
};
|
||||
}
|
||||
|
||||
export function expandFollowedHashtagsFail(error) {
|
||||
return {
|
||||
type: FOLLOWED_HASHTAGS_EXPAND_FAIL,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export const followHashtag = name => (dispatch, getState) => {
|
||||
dispatch(followHashtagRequest(name));
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ export function updateTimeline(timeline, status, accept) {
|
|||
dispatch(submitMarkers());
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteFromTimelines(id) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -67,13 +67,13 @@ export function deleteFromTimelines(id) {
|
|||
reblogOf,
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function clearTimeline(timeline) {
|
||||
return (dispatch) => {
|
||||
dispatch({ type: TIMELINE_CLEAR, timeline });
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const noOp = () => {};
|
||||
|
||||
|
@ -122,7 +122,7 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
|||
done();
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function fillTimelineGaps(timelineId, path, params = {}, done = noOp) {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -168,7 +168,7 @@ export function expandTimelineRequest(timeline, isLoadingMore) {
|
|||
timeline,
|
||||
skipLoading: !isLoadingMore,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandTimelineSuccess(timeline, statuses, next, partial, isLoadingRecent, isLoadingMore, usePendingItems) {
|
||||
return {
|
||||
|
@ -181,7 +181,7 @@ export function expandTimelineSuccess(timeline, statuses, next, partial, isLoadi
|
|||
usePendingItems,
|
||||
skipLoading: !isLoadingMore,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function expandTimelineFail(timeline, error, isLoadingMore) {
|
||||
return {
|
||||
|
@ -191,7 +191,7 @@ export function expandTimelineFail(timeline, error, isLoadingMore) {
|
|||
skipLoading: !isLoadingMore,
|
||||
skipNotFound: timeline.startsWith('account:'),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function scrollTopTimeline(timeline, top) {
|
||||
return {
|
||||
|
@ -199,7 +199,7 @@ export function scrollTopTimeline(timeline, top) {
|
|||
timeline,
|
||||
top,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function connectTimeline(timeline) {
|
||||
return {
|
||||
|
@ -207,7 +207,7 @@ export function connectTimeline(timeline) {
|
|||
timeline,
|
||||
usePendingItems: preferPendingItems,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const disconnectTimeline = timeline => ({
|
||||
type: TIMELINE_DISCONNECT,
|
||||
|
|
|
@ -9,4 +9,4 @@ export function start() {
|
|||
} catch (e) {
|
||||
// If called twice
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,4 +8,4 @@ export default function compareId (id1, id2) {
|
|||
} else {
|
||||
return id1.length > id2.length ? 1 : -1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -47,27 +47,27 @@ class Account extends ImmutablePureComponent {
|
|||
|
||||
handleFollow = () => {
|
||||
this.props.onFollow(this.props.account);
|
||||
}
|
||||
};
|
||||
|
||||
handleBlock = () => {
|
||||
this.props.onBlock(this.props.account);
|
||||
}
|
||||
};
|
||||
|
||||
handleMute = () => {
|
||||
this.props.onMute(this.props.account);
|
||||
}
|
||||
};
|
||||
|
||||
handleMuteNotifications = () => {
|
||||
this.props.onMuteNotifications(this.props.account, true);
|
||||
}
|
||||
};
|
||||
|
||||
handleUnmuteNotifications = () => {
|
||||
this.props.onMuteNotifications(this.props.account, false);
|
||||
}
|
||||
};
|
||||
|
||||
handleAction = () => {
|
||||
this.props.onActionClick(this.props.account);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { account, intl, hidden, onActionClick, actionIcon, actionTitle, defaultAction, size } = this.props;
|
||||
|
|
|
@ -137,7 +137,7 @@ export default class Retention extends React.PureComponent {
|
|||
break;
|
||||
default:
|
||||
title = <FormattedMessage id='admin.dashboard.monthly_retention' defaultMessage='User retention rate by month after sign-up' />;
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='retention'>
|
||||
|
|
|
@ -50,7 +50,7 @@ export default class Trends extends React.PureComponent {
|
|||
<Hashtag
|
||||
key={hashtag.name}
|
||||
name={hashtag.name}
|
||||
to={`/admin/tags/${hashtag.id}`}
|
||||
to={hashtag.id === undefined ? undefined : `/admin/tags/${hashtag.id}`}
|
||||
people={hashtag.history[0].accounts * 1 + hashtag.history[1].accounts * 1}
|
||||
uses={hashtag.history[0].uses * 1 + hashtag.history[1].uses * 1}
|
||||
history={hashtag.history.reverse().map(day => day.uses)}
|
||||
|
|
|
@ -38,13 +38,13 @@ export default class AnimatedNumber extends React.PureComponent {
|
|||
const { direction } = this.state;
|
||||
|
||||
return { y: -1 * direction };
|
||||
}
|
||||
};
|
||||
|
||||
willLeave = () => {
|
||||
const { direction } = this.state;
|
||||
|
||||
return { y: spring(1 * direction, { damping: 35, stiffness: 400 }) };
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { value, obfuscate } = this.props;
|
||||
|
|
|
@ -50,6 +50,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
|||
id: PropTypes.string,
|
||||
searchTokens: PropTypes.arrayOf(PropTypes.string),
|
||||
maxLength: PropTypes.number,
|
||||
lang: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -77,7 +78,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
this.props.onChange(e);
|
||||
}
|
||||
};
|
||||
|
||||
onKeyDown = (e) => {
|
||||
const { suggestions, disabled } = this.props;
|
||||
|
@ -135,22 +136,22 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
this.props.onKeyDown(e);
|
||||
}
|
||||
};
|
||||
|
||||
onBlur = () => {
|
||||
this.setState({ suggestionsHidden: true, focused: false });
|
||||
}
|
||||
};
|
||||
|
||||
onFocus = () => {
|
||||
this.setState({ focused: true });
|
||||
}
|
||||
};
|
||||
|
||||
onSuggestionClick = (e) => {
|
||||
const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute('data-index'));
|
||||
e.preventDefault();
|
||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion);
|
||||
this.input.focus();
|
||||
}
|
||||
};
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
|
||||
|
@ -160,7 +161,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
|||
|
||||
setInput = (c) => {
|
||||
this.input = c;
|
||||
}
|
||||
};
|
||||
|
||||
renderSuggestion = (suggestion, i) => {
|
||||
const { selectedSuggestion } = this.state;
|
||||
|
@ -182,10 +183,10 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
|||
{inner}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, className, id, maxLength } = this.props;
|
||||
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, className, id, maxLength, lang } = this.props;
|
||||
const { suggestionsHidden } = this.state;
|
||||
|
||||
return (
|
||||
|
@ -210,6 +211,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
|||
id={id}
|
||||
className={className}
|
||||
maxLength={maxLength}
|
||||
lang={lang}
|
||||
/>
|
||||
</label>
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
|||
onKeyDown: PropTypes.func,
|
||||
onPaste: PropTypes.func.isRequired,
|
||||
autoFocus: PropTypes.bool,
|
||||
lang: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -74,7 +75,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
this.props.onChange(e);
|
||||
}
|
||||
};
|
||||
|
||||
onKeyDown = (e) => {
|
||||
const { suggestions, disabled } = this.props;
|
||||
|
@ -132,25 +133,25 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
this.props.onKeyDown(e);
|
||||
}
|
||||
};
|
||||
|
||||
onBlur = () => {
|
||||
this.setState({ suggestionsHidden: true, focused: false });
|
||||
}
|
||||
};
|
||||
|
||||
onFocus = (e) => {
|
||||
this.setState({ focused: true });
|
||||
if (this.props.onFocus) {
|
||||
this.props.onFocus(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onSuggestionClick = (e) => {
|
||||
const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute('data-index'));
|
||||
e.preventDefault();
|
||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion);
|
||||
this.textarea.focus();
|
||||
}
|
||||
};
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
|
||||
|
@ -160,14 +161,14 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
|||
|
||||
setTextarea = (c) => {
|
||||
this.textarea = c;
|
||||
}
|
||||
};
|
||||
|
||||
onPaste = (e) => {
|
||||
if (e.clipboardData && e.clipboardData.files.length === 1) {
|
||||
this.props.onPaste(e.clipboardData.files);
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
renderSuggestion = (suggestion, i) => {
|
||||
const { selectedSuggestion } = this.state;
|
||||
|
@ -189,10 +190,10 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
|||
{inner}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, children } = this.props;
|
||||
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, lang, children } = this.props;
|
||||
const { suggestionsHidden } = this.state;
|
||||
|
||||
return [
|
||||
|
@ -216,6 +217,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
|||
onPaste={this.onPaste}
|
||||
dir='auto'
|
||||
aria-autocomplete='list'
|
||||
lang={lang}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -27,12 +27,12 @@ export default class Avatar extends React.PureComponent {
|
|||
handleMouseEnter = () => {
|
||||
if (this.props.animate) return;
|
||||
this.setState({ hovering: true });
|
||||
}
|
||||
};
|
||||
|
||||
handleMouseLeave = () => {
|
||||
if (this.props.animate) return;
|
||||
this.setState({ hovering: false });
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { account, size, animate, inline } = this.props;
|
||||
|
|
|
@ -29,12 +29,12 @@ export default class AvatarOverlay extends React.PureComponent {
|
|||
handleMouseEnter = () => {
|
||||
if (this.props.animate) return;
|
||||
this.setState({ hovering: true });
|
||||
}
|
||||
};
|
||||
|
||||
handleMouseLeave = () => {
|
||||
if (this.props.animate) return;
|
||||
this.setState({ hovering: false });
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { account, friend, animate, size, baseSize, overlaySize } = this.props;
|
||||
|
|
|
@ -24,11 +24,11 @@ export default class Button extends React.PureComponent {
|
|||
if (!this.props.disabled && this.props.onClick) {
|
||||
this.props.onClick(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setRef = (c) => {
|
||||
this.node = c;
|
||||
}
|
||||
};
|
||||
|
||||
focus() {
|
||||
this.node.focus();
|
||||
|
|
|
@ -27,11 +27,11 @@ export default class Column extends React.PureComponent {
|
|||
}
|
||||
|
||||
this._interruptScrollAnimation();
|
||||
}
|
||||
};
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
if (this.props.bindToDocument) {
|
||||
|
|
|
@ -20,7 +20,7 @@ export default class ColumnBackButton extends React.PureComponent {
|
|||
} else {
|
||||
this.context.router.history.goBack();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { multiColumn } = this.props;
|
||||
|
|
|
@ -49,32 +49,32 @@ class ColumnHeader extends React.PureComponent {
|
|||
} else {
|
||||
this.context.router.history.goBack();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleToggleClick = (e) => {
|
||||
e.stopPropagation();
|
||||
this.setState({ collapsed: !this.state.collapsed, animating: true });
|
||||
}
|
||||
};
|
||||
|
||||
handleTitleClick = () => {
|
||||
this.props.onClick?.();
|
||||
}
|
||||
};
|
||||
|
||||
handleMoveLeft = () => {
|
||||
this.props.onMove(-1);
|
||||
}
|
||||
};
|
||||
|
||||
handleMoveRight = () => {
|
||||
this.props.onMove(1);
|
||||
}
|
||||
};
|
||||
|
||||
handleBackClick = () => {
|
||||
this.historyBack();
|
||||
}
|
||||
};
|
||||
|
||||
handleTransitionEnd = () => {
|
||||
this.setState({ animating: false });
|
||||
}
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
if (!this.props.pinned) {
|
||||
|
@ -82,7 +82,7 @@ class ColumnHeader extends React.PureComponent {
|
|||
}
|
||||
|
||||
this.props.onPin();
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { title, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues } = this.props;
|
||||
|
|
|
@ -24,7 +24,7 @@ class DismissableBanner extends React.PureComponent {
|
|||
handleDismiss = () => {
|
||||
const { id } = this.props;
|
||||
this.setState({ visible: false }, () => bannerSettings.set(id, true));
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { visible } = this.state;
|
||||
|
|
|
@ -23,7 +23,7 @@ export default class DisplayName extends React.PureComponent {
|
|||
let emoji = emojis[i];
|
||||
emoji.src = emoji.getAttribute('data-original');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleMouseLeave = ({ currentTarget }) => {
|
||||
if (autoPlayGif) {
|
||||
|
@ -36,7 +36,7 @@ export default class DisplayName extends React.PureComponent {
|
|||
let emoji = emojis[i];
|
||||
emoji.src = emoji.getAttribute('data-static');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { others, localDomain } = this.props;
|
||||
|
|
|
@ -19,7 +19,7 @@ class Account extends ImmutablePureComponent {
|
|||
|
||||
handleDomainUnblock = () => {
|
||||
this.props.onUnblockDomain(this.props.domain);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { domain, intl } = this.props;
|
||||
|
|
|
@ -2,9 +2,7 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import IconButton from './icon_button';
|
||||
import Overlay from 'react-overlays/lib/Overlay';
|
||||
import Motion from '../features/ui/util/optional_motion';
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import Overlay from 'react-overlays/Overlay';
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
import classNames from 'classnames';
|
||||
import { CircularProgress } from 'mastodon/components/loading_indicator';
|
||||
|
@ -24,9 +22,6 @@ class DropdownMenu extends React.PureComponent {
|
|||
scrollable: PropTypes.bool,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
style: PropTypes.object,
|
||||
placement: PropTypes.string,
|
||||
arrowOffsetLeft: PropTypes.string,
|
||||
arrowOffsetTop: PropTypes.string,
|
||||
openedViaKeyboard: PropTypes.bool,
|
||||
renderItem: PropTypes.func,
|
||||
renderHeader: PropTypes.func,
|
||||
|
@ -35,18 +30,13 @@ class DropdownMenu extends React.PureComponent {
|
|||
|
||||
static defaultProps = {
|
||||
style: {},
|
||||
placement: 'bottom',
|
||||
};
|
||||
|
||||
state = {
|
||||
mounted: false,
|
||||
};
|
||||
|
||||
handleDocumentClick = e => {
|
||||
if (this.node && !this.node.contains(e.target)) {
|
||||
this.props.onClose();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
document.addEventListener('click', this.handleDocumentClick, false);
|
||||
|
@ -56,8 +46,6 @@ class DropdownMenu extends React.PureComponent {
|
|||
if (this.focusedItem && this.props.openedViaKeyboard) {
|
||||
this.focusedItem.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
this.setState({ mounted: true });
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
|
@ -68,11 +56,11 @@ class DropdownMenu extends React.PureComponent {
|
|||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
}
|
||||
};
|
||||
|
||||
setFocusRef = c => {
|
||||
this.focusedItem = c;
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyDown = e => {
|
||||
const items = Array.from(this.node.querySelectorAll('a, button'));
|
||||
|
@ -109,18 +97,18 @@ class DropdownMenu extends React.PureComponent {
|
|||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleItemKeyPress = e => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
this.handleClick(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleClick = e => {
|
||||
const { onItemClick } = this.props;
|
||||
onItemClick(e);
|
||||
}
|
||||
};
|
||||
|
||||
renderItem = (option, i) => {
|
||||
if (option === null) {
|
||||
|
@ -136,43 +124,31 @@ class DropdownMenu extends React.PureComponent {
|
|||
</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { items, style, placement, arrowOffsetLeft, arrowOffsetTop, scrollable, renderHeader, loading } = this.props;
|
||||
const { mounted } = this.state;
|
||||
const { items, scrollable, renderHeader, loading } = this.props;
|
||||
|
||||
let renderItem = this.props.renderItem || this.renderItem;
|
||||
|
||||
return (
|
||||
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
|
||||
{({ opacity, scaleX, scaleY }) => (
|
||||
// It should not be transformed when mounting because the resulting
|
||||
// size will be used to determine the coordinate of the menu by
|
||||
// react-overlays
|
||||
<div className={`dropdown-menu ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} ref={this.setRef}>
|
||||
<div className={`dropdown-menu__arrow ${placement}`} style={{ left: arrowOffsetLeft, top: arrowOffsetTop }} />
|
||||
<div className={classNames('dropdown-menu__container', { 'dropdown-menu__container--loading': loading })} ref={this.setRef}>
|
||||
{loading && (
|
||||
<CircularProgress size={30} strokeWidth={3.5} />
|
||||
)}
|
||||
|
||||
<div className={classNames('dropdown-menu__container', { 'dropdown-menu__container--loading': loading })}>
|
||||
{loading && (
|
||||
<CircularProgress size={30} strokeWidth={3.5} />
|
||||
)}
|
||||
|
||||
{!loading && renderHeader && (
|
||||
<div className='dropdown-menu__container__header'>
|
||||
{renderHeader(items)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!loading && (
|
||||
<ul className={classNames('dropdown-menu__container__list', { 'dropdown-menu__container__list--scrollable': scrollable })}>
|
||||
{items.map((option, i) => renderItem(option, i, { onClick: this.handleClick, onKeyPress: this.handleItemKeyPress }))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
{!loading && renderHeader && (
|
||||
<div className='dropdown-menu__container__header'>
|
||||
{renderHeader(items)}
|
||||
</div>
|
||||
)}
|
||||
</Motion>
|
||||
|
||||
{!loading && (
|
||||
<ul className={classNames('dropdown-menu__container__list', { 'dropdown-menu__container__list--scrollable': scrollable })}>
|
||||
{items.map((option, i) => renderItem(option, i, { onClick: this.handleClick, onKeyPress: this.handleItemKeyPress }))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -197,7 +173,6 @@ export default class Dropdown extends React.PureComponent {
|
|||
isUserTouching: PropTypes.func,
|
||||
onOpen: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
dropdownPlacement: PropTypes.string,
|
||||
openDropdownId: PropTypes.number,
|
||||
openedViaKeyboard: PropTypes.bool,
|
||||
renderItem: PropTypes.func,
|
||||
|
@ -213,15 +188,13 @@ export default class Dropdown extends React.PureComponent {
|
|||
id: id++,
|
||||
};
|
||||
|
||||
handleClick = ({ target, type }) => {
|
||||
handleClick = ({ type }) => {
|
||||
if (this.state.id === this.props.openDropdownId) {
|
||||
this.handleClose();
|
||||
} else {
|
||||
const { top } = target.getBoundingClientRect();
|
||||
const placement = top * 2 < innerHeight ? 'bottom' : 'top';
|
||||
this.props.onOpen(this.state.id, this.handleItemClick, placement, type !== 'click');
|
||||
this.props.onOpen(this.state.id, this.handleItemClick, type !== 'click');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleClose = () => {
|
||||
if (this.activeElement) {
|
||||
|
@ -229,13 +202,13 @@ export default class Dropdown extends React.PureComponent {
|
|||
this.activeElement = null;
|
||||
}
|
||||
this.props.onClose(this.state.id);
|
||||
}
|
||||
};
|
||||
|
||||
handleMouseDown = () => {
|
||||
if (!this.state.open) {
|
||||
this.activeElement = document.activeElement;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleButtonKeyDown = (e) => {
|
||||
switch(e.key) {
|
||||
|
@ -244,7 +217,7 @@ export default class Dropdown extends React.PureComponent {
|
|||
this.handleMouseDown();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyPress = (e) => {
|
||||
switch(e.key) {
|
||||
|
@ -255,7 +228,7 @@ export default class Dropdown extends React.PureComponent {
|
|||
e.preventDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleItemClick = e => {
|
||||
const { onItemClick } = this.props;
|
||||
|
@ -274,25 +247,25 @@ export default class Dropdown extends React.PureComponent {
|
|||
e.preventDefault();
|
||||
this.context.router.history.push(item.to);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setTargetRef = c => {
|
||||
this.target = c;
|
||||
}
|
||||
};
|
||||
|
||||
findTarget = () => {
|
||||
return this.target;
|
||||
}
|
||||
};
|
||||
|
||||
componentWillUnmount = () => {
|
||||
if (this.state.id === this.props.openDropdownId) {
|
||||
this.handleClose();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
close = () => {
|
||||
this.handleClose();
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const {
|
||||
|
@ -303,7 +276,6 @@ export default class Dropdown extends React.PureComponent {
|
|||
disabled,
|
||||
loading,
|
||||
scrollable,
|
||||
dropdownPlacement,
|
||||
openDropdownId,
|
||||
openedViaKeyboard,
|
||||
children,
|
||||
|
@ -314,7 +286,6 @@ export default class Dropdown extends React.PureComponent {
|
|||
const open = this.state.id === openDropdownId;
|
||||
|
||||
const button = children ? React.cloneElement(React.Children.only(children), {
|
||||
ref: this.setTargetRef,
|
||||
onClick: this.handleClick,
|
||||
onMouseDown: this.handleMouseDown,
|
||||
onKeyDown: this.handleButtonKeyDown,
|
||||
|
@ -326,7 +297,6 @@ export default class Dropdown extends React.PureComponent {
|
|||
active={open}
|
||||
disabled={disabled}
|
||||
size={size}
|
||||
ref={this.setTargetRef}
|
||||
onClick={this.handleClick}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onKeyDown={this.handleButtonKeyDown}
|
||||
|
@ -336,19 +306,27 @@ export default class Dropdown extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{button}
|
||||
|
||||
<Overlay show={open} placement={dropdownPlacement} target={this.findTarget}>
|
||||
<DropdownMenu
|
||||
items={items}
|
||||
loading={loading}
|
||||
scrollable={scrollable}
|
||||
onClose={this.handleClose}
|
||||
openedViaKeyboard={openedViaKeyboard}
|
||||
renderItem={renderItem}
|
||||
renderHeader={renderHeader}
|
||||
onItemClick={this.handleItemClick}
|
||||
/>
|
||||
<span ref={this.setTargetRef}>
|
||||
{button}
|
||||
</span>
|
||||
<Overlay show={open} offset={[5, 5]} placement={'bottom'} flip target={this.findTarget} popperConfig={{ strategy: 'fixed' }}>
|
||||
{({ props, arrowProps, placement }) => (
|
||||
<div {...props}>
|
||||
<div className={`dropdown-animation dropdown-menu ${placement}`}>
|
||||
<div className={`dropdown-menu__arrow ${placement}`} {...arrowProps} />
|
||||
<DropdownMenu
|
||||
items={items}
|
||||
loading={loading}
|
||||
scrollable={scrollable}
|
||||
onClose={this.handleClose}
|
||||
openedViaKeyboard={openedViaKeyboard}
|
||||
renderItem={renderItem}
|
||||
renderHeader={renderHeader}
|
||||
onItemClick={this.handleItemClick}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Overlay>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
|
|
@ -4,7 +4,6 @@ import { fetchHistory } from 'mastodon/actions/history';
|
|||
import DropdownMenu from 'mastodon/components/dropdown_menu';
|
||||
|
||||
const mapStateToProps = (state, { statusId }) => ({
|
||||
dropdownPlacement: state.getIn(['dropdown_menu', 'placement']),
|
||||
openDropdownId: state.getIn(['dropdown_menu', 'openId']),
|
||||
openedViaKeyboard: state.getIn(['dropdown_menu', 'keyboard']),
|
||||
items: state.getIn(['history', statusId, 'items']),
|
||||
|
@ -13,9 +12,9 @@ const mapStateToProps = (state, { statusId }) => ({
|
|||
|
||||
const mapDispatchToProps = (dispatch, { statusId }) => ({
|
||||
|
||||
onOpen (id, onItemClick, dropdownPlacement, keyboard) {
|
||||
onOpen (id, onItemClick, keyboard) {
|
||||
dispatch(fetchHistory(statusId));
|
||||
dispatch(openDropdownMenu(id, dropdownPlacement, keyboard));
|
||||
dispatch(openDropdownMenu(id, keyboard));
|
||||
},
|
||||
|
||||
onClose (id) {
|
||||
|
|
|
@ -36,7 +36,7 @@ class EditedTimestamp extends React.PureComponent {
|
|||
return (
|
||||
<FormattedMessage id='status.edited_x_times' defaultMessage='Edited {count, plural, one {{count} time} other {{count} times}}' values={{ count: items.size - 1 }} />
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
renderItem = (item, index, { onClick, onKeyPress }) => {
|
||||
const formattedDate = <RelativeTimestamp timestamp={item.get('created_at')} short={false} />;
|
||||
|
@ -53,7 +53,7 @@ class EditedTimestamp extends React.PureComponent {
|
|||
<button data-index={index} onClick={onClick} onKeyPress={onKeyPress}>{label}</button>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { timestamp, intl, statusId } = this.props;
|
||||
|
|
|
@ -64,7 +64,7 @@ export default class ErrorBoundary extends React.PureComponent {
|
|||
|
||||
this.setState({ copied: true });
|
||||
setTimeout(() => this.setState({ copied: false }), 700);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { hasError, copied, errorMessage } = this.state;
|
||||
|
|
|
@ -17,7 +17,7 @@ export default class GIFV extends React.PureComponent {
|
|||
|
||||
handleLoadedData = () => {
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
};
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.src !== this.props.src) {
|
||||
|
@ -32,7 +32,7 @@ export default class GIFV extends React.PureComponent {
|
|||
e.stopPropagation();
|
||||
onClick();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { src, width, height, alt } = this.props;
|
||||
|
|
|
@ -27,6 +27,7 @@ export default class IconButton extends React.PureComponent {
|
|||
counter: PropTypes.number,
|
||||
obfuscateCount: PropTypes.bool,
|
||||
href: PropTypes.string,
|
||||
ariaHidden: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -36,12 +37,13 @@ export default class IconButton extends React.PureComponent {
|
|||
animate: false,
|
||||
overlay: false,
|
||||
tabIndex: '0',
|
||||
ariaHidden: false,
|
||||
};
|
||||
|
||||
state = {
|
||||
activate: false,
|
||||
deactivate: false,
|
||||
}
|
||||
};
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (!nextProps.animate) return;
|
||||
|
@ -59,25 +61,25 @@ export default class IconButton extends React.PureComponent {
|
|||
if (!this.props.disabled) {
|
||||
this.props.onClick(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyPress = (e) => {
|
||||
if (this.props.onKeyPress && !this.props.disabled) {
|
||||
this.props.onKeyPress(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleMouseDown = (e) => {
|
||||
if (!this.props.disabled && this.props.onMouseDown) {
|
||||
this.props.onMouseDown(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyDown = (e) => {
|
||||
if (!this.props.disabled && this.props.onKeyDown) {
|
||||
this.props.onKeyDown(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const style = {
|
||||
|
@ -102,6 +104,7 @@ export default class IconButton extends React.PureComponent {
|
|||
counter,
|
||||
obfuscateCount,
|
||||
href,
|
||||
ariaHidden,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
|
@ -142,6 +145,7 @@ export default class IconButton extends React.PureComponent {
|
|||
type='button'
|
||||
aria-label={title}
|
||||
aria-expanded={expanded}
|
||||
aria-hidden={ariaHidden}
|
||||
title={title}
|
||||
className={classes}
|
||||
onClick={this.handleClick}
|
||||
|
|
|
@ -21,7 +21,7 @@ export default class IntersectionObserverArticle extends React.Component {
|
|||
|
||||
state = {
|
||||
isHidden: false, // set to true in requestIdleCallback to trigger un-render
|
||||
}
|
||||
};
|
||||
|
||||
shouldComponentUpdate (nextProps, nextState) {
|
||||
const isUnrendered = !this.state.isIntersecting && (this.state.isHidden || this.props.cachedHeight);
|
||||
|
@ -62,7 +62,7 @@ export default class IntersectionObserverArticle extends React.Component {
|
|||
|
||||
scheduleIdleTask(this.calculateHeight);
|
||||
this.setState(this.updateStateAfterIntersection);
|
||||
}
|
||||
};
|
||||
|
||||
updateStateAfterIntersection = (prevState) => {
|
||||
if (prevState.isIntersecting !== false && !this.entry.isIntersecting) {
|
||||
|
@ -72,7 +72,7 @@ export default class IntersectionObserverArticle extends React.Component {
|
|||
isIntersecting: this.entry.isIntersecting,
|
||||
isHidden: false,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
calculateHeight = () => {
|
||||
const { onHeightChange, saveHeightKey, id } = this.props;
|
||||
|
@ -83,7 +83,7 @@ export default class IntersectionObserverArticle extends React.Component {
|
|||
if (onHeightChange && saveHeightKey) {
|
||||
onHeightChange(saveHeightKey, id, this.height);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
hideIfNotIntersecting = () => {
|
||||
if (!this.componentMounted) {
|
||||
|
@ -95,11 +95,11 @@ export default class IntersectionObserverArticle extends React.Component {
|
|||
// this is to save DOM nodes and avoid using up too much memory.
|
||||
// See: https://github.com/mastodon/mastodon/issues/2900
|
||||
this.setState((prevState) => ({ isHidden: !prevState.isIntersecting }));
|
||||
}
|
||||
};
|
||||
|
||||
handleRef = (node) => {
|
||||
this.node = node;
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { children, id, index, listLength, cachedHeight } = this.props;
|
||||
|
|
|
@ -19,7 +19,7 @@ class LoadGap extends React.PureComponent {
|
|||
|
||||
handleClick = () => {
|
||||
this.props.onClick(this.props.maxId);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { disabled, intl } = this.props;
|
||||
|
|
|
@ -8,11 +8,11 @@ export default class LoadMore extends React.PureComponent {
|
|||
onClick: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
visible: PropTypes.bool,
|
||||
}
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
visible: true,
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { disabled, visible } = this.props;
|
||||
|
|
|
@ -7,7 +7,7 @@ export default class LoadPending extends React.PureComponent {
|
|||
static propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
count: PropTypes.number,
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { count } = this.props;
|
||||
|
|
|
@ -29,7 +29,7 @@ export default class MediaAttachments extends ImmutablePureComponent {
|
|||
return (
|
||||
<div className='media-gallery' style={{ height, width }} />
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
renderLoadingVideoPlayer = () => {
|
||||
const { height, width } = this.props;
|
||||
|
@ -37,7 +37,7 @@ export default class MediaAttachments extends ImmutablePureComponent {
|
|||
return (
|
||||
<div className='video-player' style={{ height, width }} />
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
renderLoadingAudioPlayer = () => {
|
||||
const { height, width } = this.props;
|
||||
|
@ -45,7 +45,7 @@ export default class MediaAttachments extends ImmutablePureComponent {
|
|||
return (
|
||||
<div className='audio-player' style={{ height, width }} />
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { status, width, height } = this.props;
|
||||
|
|
|
@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
|
|||
import { is } from 'immutable';
|
||||
import IconButton from './icon_button';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { isIOS } from '../is_mobile';
|
||||
import classNames from 'classnames';
|
||||
import { autoPlayGif, cropImages, displayMedia, useBlurhash } from '../initial_state';
|
||||
import { debounce } from 'lodash';
|
||||
|
@ -41,14 +40,14 @@ class Item extends React.PureComponent {
|
|||
if (this.hoverToPlay()) {
|
||||
e.target.play();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleMouseLeave = (e) => {
|
||||
if (this.hoverToPlay()) {
|
||||
e.target.pause();
|
||||
e.target.currentTime = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getAutoPlay() {
|
||||
return this.props.autoplay || autoPlayGif;
|
||||
|
@ -72,11 +71,11 @@ class Item extends React.PureComponent {
|
|||
}
|
||||
|
||||
e.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
handleImageLoad = () => {
|
||||
this.setState({ loaded: true });
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { attachment, index, size, standalone, displayWidth, visible } = this.props;
|
||||
|
@ -181,7 +180,7 @@ class Item extends React.PureComponent {
|
|||
</a>
|
||||
);
|
||||
} else if (attachment.get('type') === 'gifv') {
|
||||
const autoPlay = !isIOS() && this.getAutoPlay();
|
||||
const autoPlay = this.getAutoPlay();
|
||||
|
||||
thumbnail = (
|
||||
<div className={classNames('media-gallery__gifv', { autoplay: autoPlay })}>
|
||||
|
@ -195,6 +194,7 @@ class Item extends React.PureComponent {
|
|||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
autoPlay={autoPlay}
|
||||
playsInline
|
||||
loop
|
||||
muted
|
||||
/>
|
||||
|
@ -277,11 +277,11 @@ class MediaGallery extends React.PureComponent {
|
|||
} else {
|
||||
this.setState({ visible: !this.state.visible });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleClick = (index) => {
|
||||
this.props.onOpenMedia(this.props.media, index);
|
||||
}
|
||||
};
|
||||
|
||||
handleRef = c => {
|
||||
this.node = c;
|
||||
|
@ -289,7 +289,7 @@ class MediaGallery extends React.PureComponent {
|
|||
if (this.node) {
|
||||
this._setDimensions();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_setDimensions () {
|
||||
const width = this.node.offsetWidth;
|
||||
|
@ -345,7 +345,7 @@ class MediaGallery extends React.PureComponent {
|
|||
</button>
|
||||
);
|
||||
} else if (visible) {
|
||||
spoilerButton = <IconButton title={intl.formatMessage(messages.toggle_visible, { number: size })} icon='eye-slash' overlay onClick={this.handleOpen} />;
|
||||
spoilerButton = <IconButton title={intl.formatMessage(messages.toggle_visible, { number: size })} icon='eye-slash' overlay onClick={this.handleOpen} ariaHidden />;
|
||||
} else {
|
||||
spoilerButton = (
|
||||
<button type='button' onClick={this.handleOpen} className='spoiler-button__overlay'>
|
||||
|
|
|
@ -28,7 +28,7 @@ export default class ModalRoot extends React.PureComponent {
|
|||
&& !!this.props.children) {
|
||||
this.props.onClose();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyDown = (e) => {
|
||||
if (e.key === 'Tab') {
|
||||
|
@ -49,7 +49,7 @@ export default class ModalRoot extends React.PureComponent {
|
|||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
window.addEventListener('keyup', this.handleKeyUp, false);
|
||||
|
@ -122,11 +122,11 @@ export default class ModalRoot extends React.PureComponent {
|
|||
|
||||
getSiblings = () => {
|
||||
return Array(...this.node.parentElement.childNodes).filter(node => node !== this.node);
|
||||
}
|
||||
};
|
||||
|
||||
setRef = ref => {
|
||||
this.node = ref;
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { children, onClose } = this.props;
|
||||
|
|
|
@ -22,7 +22,7 @@ class PictureInPicturePlaceholder extends React.PureComponent {
|
|||
handleClick = () => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(removePictureInPicture());
|
||||
}
|
||||
};
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
|
@ -30,7 +30,7 @@ class PictureInPicturePlaceholder extends React.PureComponent {
|
|||
if (this.node) {
|
||||
this._setDimensions();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_setDimensions () {
|
||||
const width = this.node.offsetWidth;
|
||||
|
|
|
@ -95,7 +95,7 @@ class Poll extends ImmutablePureComponent {
|
|||
tmp[value] = true;
|
||||
this.setState({ selected: tmp });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleOptionChange = ({ target: { value } }) => {
|
||||
this._toggleOption(value);
|
||||
|
@ -107,7 +107,7 @@ class Poll extends ImmutablePureComponent {
|
|||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleVote = () => {
|
||||
if (this.props.disabled) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue