mirror of
https://github.com/discourse/discourse.git
synced 2026-08-08 17:53:55 +08:00
Related: https://meta.discourse.org/t/multi-language-preferences-for-displaying-localized-content/381116 Allow anon and logged in users to set more than one language that they understand, when content localization is enabled. ### User preferences In user preferences, we now include a Content Languages section when the site has Content Localization enabled. ### Topic menu In topics where there are any languages that's not the user's language, the option will appear to set their preferred content languages. This appears for anon and logged in users, but anon users will be asked to logged in to set the languages. __________ These preferences apply only to topic titles and posts. They do not affect navigational features like categories, tags, or sidebar content. The per-post option to show the original remains independent of the user's preferences. This PR temporarily retains `show_original_content` as a compatibility field computed from `automatically_translate`, keeping cached clients and rolling deployments safe. A follow-up PR will remove the legacy API and frontend compatibility code, then retire the old database column through the staged column-removal process.
520 lines
15 KiB
Ruby
Vendored
520 lines
15 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
module PageObjects
|
|
module Pages
|
|
class Topic < PageObjects::Pages::Base
|
|
def initialize
|
|
@composer_component = PageObjects::Components::Composer.new
|
|
@fast_edit_component = PageObjects::Components::FastEditor.new
|
|
@topic_map_component = PageObjects::Components::TopicMap.new
|
|
@private_message_map_component = PageObjects::Components::PrivateMessageMap.new
|
|
end
|
|
|
|
def visit_topic(topic, post_number: nil)
|
|
visit(topic.url(post_number))
|
|
self
|
|
end
|
|
|
|
def open_new_topic
|
|
visit "/new-topic"
|
|
self
|
|
end
|
|
|
|
def open_new_message
|
|
visit "/new-message"
|
|
self
|
|
end
|
|
|
|
def visit_topic_and_open_composer(topic)
|
|
visit_topic(topic)
|
|
click_reply_button
|
|
self
|
|
end
|
|
|
|
def current_topic_id
|
|
find("h1[data-topic-id]")["data-topic-id"]
|
|
end
|
|
|
|
def current_topic
|
|
::Topic.find(current_topic_id)
|
|
end
|
|
|
|
def topic_title
|
|
find("#topic-title .fancy-title")
|
|
end
|
|
|
|
def has_topic_title?(text)
|
|
has_css?("h1 .fancy-title", text: text)
|
|
end
|
|
|
|
def has_topic_title_editor?
|
|
has_css?("#topic-title input#edit-title")
|
|
end
|
|
|
|
def has_no_topic_title_editor?
|
|
has_no_css?("#topic-title input#edit-title")
|
|
end
|
|
|
|
def has_post_content?(post_number:, content:)
|
|
find(post_by_number_selector(post_number)).has_content?(content)
|
|
end
|
|
|
|
def has_deleted_post?(post)
|
|
has_css?(".topic-post.deleted:has(#post_#{post.post_number})")
|
|
end
|
|
|
|
def has_no_deleted_post?(post)
|
|
has_no_css?(".topic-post.deleted:has(#post_#{post.post_number})")
|
|
end
|
|
|
|
def has_post_number?(number)
|
|
has_css?("#post_#{number}")
|
|
end
|
|
|
|
def has_replies_expanded?(post)
|
|
within_post(post) { has_css?(".embedded-posts") }
|
|
end
|
|
|
|
def has_replies_collapsed?(post)
|
|
within_post(post) { has_no_css?(".embedded-posts") }
|
|
end
|
|
|
|
def post_by_number(post_or_number, wait: Capybara.default_max_wait_time)
|
|
post_or_number = post_or_number.is_a?(Post) ? post_or_number.post_number : post_or_number
|
|
find(".topic-post:not(.staged) #post_#{post_or_number}", wait: wait)
|
|
end
|
|
|
|
def post_by_number_selector(post_number)
|
|
".topic-post:not(.staged) #post_#{post_number}"
|
|
end
|
|
|
|
def has_no_post_more_actions?(post)
|
|
within_post(post) { has_no_css?(".show-more-actions") }
|
|
end
|
|
|
|
def has_post_more_actions?(post)
|
|
within_post(post) { has_css?(".show-more-actions") }
|
|
end
|
|
|
|
def has_post_bookmarked?(post, with_reminder: false)
|
|
is_post_bookmarked(post, bookmarked: true, with_reminder: with_reminder)
|
|
end
|
|
|
|
def has_no_post_bookmarked?(post, with_reminder: false)
|
|
is_post_bookmarked(post, bookmarked: false, with_reminder: with_reminder)
|
|
end
|
|
|
|
def expand_post_actions(post)
|
|
post_by_number(post).find(".show-more-actions").click
|
|
end
|
|
|
|
def click_post_author_avatar(post)
|
|
within_post(post) { find(".main-avatar[data-user-card='#{post.user.username}']").click }
|
|
end
|
|
|
|
def click_post_action_button(post, button)
|
|
find_post_action_button(post, button).click
|
|
end
|
|
|
|
def open_post_translations(post)
|
|
click_post_action_button(post, :show_more)
|
|
click_post_action_button(post, :add_translation)
|
|
find(".post-action-menu__view-translation").click
|
|
self
|
|
end
|
|
|
|
def find_post_action_buttons(post)
|
|
within_post(post) { find(".post-controls .actions") }
|
|
end
|
|
|
|
def find_post_action_button(post, button)
|
|
button_selector = selector_for_post_action_button(button)
|
|
within_post(post) { find(button_selector) }
|
|
end
|
|
|
|
def has_post_action_button?(post, button)
|
|
button_selector = selector_for_post_action_button(button)
|
|
within_post(post) { has_css?(button_selector) }
|
|
end
|
|
|
|
def has_no_post_action_button?(post, button)
|
|
button_selector = selector_for_post_action_button(button)
|
|
within_post(post) { has_no_css?(button_selector) }
|
|
end
|
|
|
|
def has_who_liked_on_post?(post, count: nil)
|
|
return has_css?(".users-popup .users-popup__item", count: count) if count
|
|
|
|
has_css?(".users-popup")
|
|
end
|
|
|
|
def has_no_who_liked_on_post?(post)
|
|
has_no_css?(".users-popup")
|
|
end
|
|
|
|
def has_who_read_on_post?(post, count: nil)
|
|
if count
|
|
return(
|
|
within_post(post) { has_css?(".who-read.--expanded a.trigger-user-card", count: count) }
|
|
)
|
|
end
|
|
|
|
within_post(post) { has_css?(".who-read.--expanded") }
|
|
end
|
|
|
|
def has_no_who_read_on_post?(post)
|
|
within_post(post) { has_no_css?(".who-read.--expanded") }
|
|
end
|
|
|
|
def expand_post_admin_actions(post)
|
|
click_post_action_button(post, :admin)
|
|
end
|
|
|
|
def has_post_admin_menu?()
|
|
has_css?("[data-content][data-identifier='admin-post-menu']")
|
|
end
|
|
|
|
def has_no_post_admin_menu?()
|
|
has_no_css?("[data-content][data-identifier='admin-post-menu']")
|
|
end
|
|
|
|
def click_post_admin_action_button(post, button)
|
|
element_klass = "[data-content][data-identifier='admin-post-menu']"
|
|
case button
|
|
when :grant_badge
|
|
element_klass += " .grant-badge"
|
|
when :change_owner
|
|
element_klass += " .change-owner"
|
|
when :permanently_delete
|
|
element_klass += " .permanently-delete"
|
|
end
|
|
|
|
find(element_klass).click
|
|
end
|
|
|
|
def permanently_delete_post(post)
|
|
expand_post_actions(post)
|
|
expand_post_admin_actions(post)
|
|
click_post_admin_action_button(post, :permanently_delete)
|
|
end
|
|
|
|
def open_post_history(post)
|
|
post_by_number(post).find(".post-info.edits").click
|
|
end
|
|
|
|
def click_topic_bookmark_button
|
|
within_topic_footer_buttons { find(".bookmark-menu-trigger").click }
|
|
end
|
|
|
|
def click_topic_edit_title
|
|
find("#topic-title .fancy-title").click
|
|
end
|
|
|
|
def click_topic_title_submit_edit
|
|
find("#topic-title .submit-edit").click
|
|
end
|
|
|
|
def click_topic_title_cancel_edit
|
|
find("#topic-title .cancel-edit").click
|
|
end
|
|
|
|
def has_editing_localization_indicator?
|
|
has_css?("#topic-title .editing-localization-indicator")
|
|
end
|
|
|
|
def has_no_editing_localization_indicator?
|
|
has_no_css?("#topic-title .editing-localization-indicator")
|
|
end
|
|
|
|
def has_topic_bookmarked?(topic)
|
|
within_topic_footer_buttons do
|
|
has_css?(".bookmark-menu-trigger.bookmarked", text: "Edit bookmark")
|
|
end
|
|
end
|
|
|
|
def has_no_bookmarks?(topic)
|
|
within_topic_footer_buttons { has_no_css?(".bookmark-menu-trigger.bookmarked") }
|
|
end
|
|
|
|
def has_topic_status_bookmark?
|
|
has_css?("#topic-title .topic-status.--bookmarked")
|
|
end
|
|
|
|
def has_no_topic_status_bookmark?
|
|
has_no_css?("#topic-title .topic-status.--bookmarked")
|
|
end
|
|
|
|
def click_reply_button
|
|
within_topic_footer_buttons { find(".create").click }
|
|
has_expanded_composer?
|
|
end
|
|
|
|
def click_floating_reply_button
|
|
find(".embed-floating-reply-button").click
|
|
end
|
|
|
|
def has_floating_reply_button?
|
|
has_css?(".embed-floating-reply-button")
|
|
end
|
|
|
|
def has_no_floating_reply_button?
|
|
has_no_css?(".embed-floating-reply-button")
|
|
end
|
|
|
|
def click_floating_timeline_button
|
|
find(".embed-floating-timeline-button").click
|
|
end
|
|
|
|
def has_floating_timeline_button?
|
|
has_css?(".embed-floating-timeline-button")
|
|
end
|
|
|
|
def has_no_floating_timeline_button?
|
|
has_no_css?(".embed-floating-timeline-button")
|
|
end
|
|
|
|
def has_docked_composer?
|
|
has_css?(".embed-mode-composer .docked-composer")
|
|
end
|
|
|
|
def has_no_docked_composer?
|
|
has_no_css?(".embed-mode-composer .docked-composer")
|
|
end
|
|
|
|
def click_embed_reply_button
|
|
within_topic_footer_buttons { find(".create").click }
|
|
self
|
|
end
|
|
|
|
def has_expanded_composer?
|
|
has_css?("#reply-control.open")
|
|
end
|
|
|
|
def composer
|
|
@composer_component
|
|
end
|
|
|
|
def type_in_composer(input)
|
|
@composer_component.type_content(input)
|
|
end
|
|
|
|
def fill_in_composer(input)
|
|
@composer_component.fill_content(input)
|
|
end
|
|
|
|
def clear_composer
|
|
@composer_component.clear_content
|
|
end
|
|
|
|
def has_composer_content?(content)
|
|
@composer_component.has_content?(content)
|
|
end
|
|
|
|
def has_composer_popup_content?(content)
|
|
@composer_component.has_popup_content?(content)
|
|
end
|
|
|
|
def send_reply(content = nil)
|
|
fill_in_composer(content) if content
|
|
find("#reply-control .save-or-cancel .create").click
|
|
end
|
|
|
|
def fill_in_composer_title(title)
|
|
@composer_component.fill_title(title)
|
|
end
|
|
|
|
def fast_edit_button
|
|
find(".quote-button .quote-edit-label")
|
|
end
|
|
|
|
def click_fast_edit_button
|
|
find(".quote-button .quote-edit-label").click
|
|
end
|
|
|
|
def fast_edit_input
|
|
@fast_edit_component.fast_edit_input
|
|
end
|
|
|
|
def copy_quote_button_selector
|
|
".quote-button .copy-quote"
|
|
end
|
|
|
|
def copy_quote_button
|
|
find(copy_quote_button_selector)
|
|
end
|
|
|
|
def click_mention(post, mention)
|
|
within_post(post) { find("a.mention-group", text: mention).click }
|
|
end
|
|
|
|
def click_footer_reply
|
|
button = find("#topic-footer-buttons .btn-primary", text: "Reply")
|
|
page.execute_script("arguments[0].scrollIntoView();", button)
|
|
button.click
|
|
self
|
|
end
|
|
|
|
def click_like_reaction_for(post)
|
|
post_container = post_container_for(post)
|
|
|
|
if post_container.has_css?(".discourse-reactions-reaction-button", wait: 0)
|
|
post_container.find(".discourse-reactions-reaction-button").click
|
|
else
|
|
post_container.find(".post-action-menu__like").click
|
|
end
|
|
end
|
|
|
|
def has_like_count_for?(post, count)
|
|
post_container_for(post).has_css?(
|
|
".post-action-menu__like-count, .reactions-counter",
|
|
text: count.to_s,
|
|
)
|
|
end
|
|
|
|
def post_container_for(post)
|
|
post_number = post.is_a?(Post) ? post.post_number : post
|
|
post_by_number(post_number).ancestor(".topic-post")
|
|
end
|
|
|
|
def has_topic_map?
|
|
@topic_map_component.is_visible?
|
|
end
|
|
|
|
def has_no_topic_map?
|
|
@topic_map_component.is_not_visible?
|
|
end
|
|
|
|
def has_private_message_map?
|
|
@private_message_map_component.is_visible?
|
|
end
|
|
|
|
def click_notifications_button
|
|
find(".topic-notifications-button .notifications-tracking-trigger").click
|
|
end
|
|
|
|
def click_admin_menu_button
|
|
within_topic_footer_buttons { find(".toggle-admin-menu").click }
|
|
PageObjects::Components::TopicAdminMenu.new
|
|
end
|
|
|
|
def watch_topic
|
|
click_notifications_button
|
|
find('.notifications-tracking-btn[data-level-name="watching"]').click
|
|
end
|
|
|
|
def close_topic
|
|
click_admin_menu_button
|
|
find(".topic-admin-popup-menu ul.topic-admin-menu-topic li.topic-admin-close").click
|
|
end
|
|
|
|
def has_read_post?(post)
|
|
post_by_number(post).has_css?(".read-state.read", visible: :all, wait: 3)
|
|
end
|
|
|
|
def has_suggested_topic?(topic)
|
|
page.has_css?("#suggested-topics .topic-list-item[data-topic-id='#{topic.id}']")
|
|
end
|
|
|
|
def move_to_public_category(category)
|
|
click_admin_menu_button
|
|
find(".topic-admin-menu-content li.topic-admin-convert").click
|
|
move_to_public_modal.find(".category-chooser").click
|
|
find(".category-row[data-value=\"#{category.id}\"]").click
|
|
move_to_public_modal.find(".btn-primary").click
|
|
end
|
|
|
|
def move_to_public_modal
|
|
find(".d-modal.convert-to-public-topic")
|
|
end
|
|
|
|
def has_no_flag_button?
|
|
has_no_css?(".post-action-menu__flag.create-flag")
|
|
end
|
|
|
|
def open_flag_topic_modal
|
|
expect(page).to have_css(".flag-topic", wait: Capybara.default_max_wait_time * 3)
|
|
find(".flag-topic").click
|
|
end
|
|
|
|
def within_post(post)
|
|
within(post_by_number(post)) { yield }
|
|
end
|
|
|
|
def has_filtered_notice_text?(text)
|
|
find(".posts-filtered-notice").has_text?(text, exact: false)
|
|
end
|
|
|
|
def topic_tags
|
|
tags_selector = ".title-wrapper .topic-category .list-tags .discourse-tags .discourse-tag"
|
|
all(tags_selector).map(&:text)
|
|
end
|
|
|
|
def has_topic_tag?(name)
|
|
has_css?(".title-wrapper .discourse-tag", text: name)
|
|
end
|
|
|
|
def has_content_language_preferences_launcher?
|
|
has_css?(".topic-content-language-preferences")
|
|
end
|
|
|
|
def has_no_topic_admin_menu?
|
|
has_no_css?(".topic-admin-menu-trigger")
|
|
end
|
|
|
|
def open_content_language_preferences
|
|
find(".topic-content-language-preferences").click
|
|
PageObjects::Modals::ContentLanguagePreferences.new
|
|
end
|
|
|
|
private
|
|
|
|
def within_topic_footer_buttons
|
|
within("#topic-footer-buttons") { yield }
|
|
end
|
|
|
|
def selector_for_post_action_button(button)
|
|
case button
|
|
when :add_translation
|
|
".post-controls .post-action-menu-edit-translations-trigger"
|
|
when :admin
|
|
".post-controls .post-action-menu__admin"
|
|
when :bookmark
|
|
".post-controls .post-action-menu__bookmark"
|
|
when :copy_link, :copyLink
|
|
".post-controls .post-action-menu__copy-link"
|
|
when :delete
|
|
".post-controls .post-action-menu__delete"
|
|
when :edit
|
|
".post-controls .post-action-menu__edit"
|
|
when :flag
|
|
".post-controls .post-action-menu__flag"
|
|
when :like
|
|
".post-controls .post-action-menu__like"
|
|
when :like_count
|
|
".post-controls .post-action-menu__like-count"
|
|
when :read
|
|
".post-controls .post-action-menu__read"
|
|
when :recover
|
|
".post-controls .post-action-menu__recover"
|
|
when :replies
|
|
".post-controls .post-action-menu__show-replies"
|
|
when :reply
|
|
".post-controls .post-action-menu__reply"
|
|
when :share
|
|
".post-controls .post-action-menu__share"
|
|
when :show_more
|
|
".post-controls .post-action-menu__show-more"
|
|
else
|
|
raise "Unknown post menu button type: #{button}"
|
|
end
|
|
end
|
|
|
|
def is_post_bookmarked(post, bookmarked:, with_reminder: false)
|
|
within_post(post) do
|
|
css_class = ".bookmark.bookmarked#{with_reminder ? ".with-reminder" : ""}"
|
|
page.public_send(bookmarked ? :has_css? : :has_no_css?, css_class)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|