2019-06-18 02:51:17 +08:00
|
|
|
# coding: utf-8
|
2018-06-05 15:29:17 +08:00
|
|
|
# frozen_string_literal: true
|
2013-02-06 03:16:51 +08:00
|
|
|
require "current_user"
|
2013-02-13 19:04:43 +08:00
|
|
|
require "canonical_url"
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
module ApplicationHelper
|
|
|
|
include CurrentUser
|
2013-02-13 19:04:43 +08:00
|
|
|
include CanonicalURL::Helpers
|
2013-05-01 23:48:42 +08:00
|
|
|
include ConfigurableUrls
|
2015-03-10 03:24:16 +08:00
|
|
|
include GlobalPath
|
2017-09-29 01:16:51 +08:00
|
|
|
|
2017-09-29 23:04:05 +08:00
|
|
|
def self.extra_body_classes
|
|
|
|
@extra_body_classes ||= Set.new
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2022-01-14 04:16:34 +08:00
|
|
|
def discourse_config_environment(testing: false)
|
2021-05-05 21:02:48 +08:00
|
|
|
# TODO: Can this come from Ember CLI somehow?
|
2022-01-14 04:16:34 +08:00
|
|
|
config = {
|
|
|
|
modulePrefix: "discourse",
|
2021-05-05 21:02:48 +08:00
|
|
|
environment: Rails.env,
|
|
|
|
rootURL: Discourse.base_path,
|
2022-06-20 21:41:53 +08:00
|
|
|
locationType: "history",
|
2021-05-05 21:02:48 +08:00
|
|
|
historySupportMiddleware: false,
|
|
|
|
EmberENV: {
|
|
|
|
FEATURES: {
|
|
|
|
},
|
|
|
|
EXTEND_PROTOTYPES: {
|
|
|
|
Date: false,
|
2023-10-26 18:16:57 +08:00
|
|
|
String: false,
|
2023-01-09 20:20:10 +08:00
|
|
|
},
|
2021-05-05 21:02:48 +08:00
|
|
|
_APPLICATION_TEMPLATE_WRAPPER: false,
|
|
|
|
_DEFAULT_ASYNC_OBSERVERS: true,
|
|
|
|
_JQUERY_INTEGRATION: true,
|
|
|
|
},
|
|
|
|
APP: {
|
|
|
|
name: "discourse",
|
|
|
|
version: "#{Discourse::VERSION::STRING} #{Discourse.git_version}",
|
|
|
|
exportApplicationGlobal: true,
|
|
|
|
},
|
2022-01-14 04:16:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if testing
|
|
|
|
config[:environment] = "test"
|
|
|
|
config[:locationType] = "none"
|
|
|
|
config[:APP][:autoboot] = false
|
|
|
|
config[:APP][:rootElement] = "#ember-testing"
|
|
|
|
end
|
|
|
|
|
|
|
|
config.to_json
|
2021-05-05 21:02:48 +08:00
|
|
|
end
|
|
|
|
|
2016-08-03 02:54:06 +08:00
|
|
|
def google_universal_analytics_json(ua_domain_name = nil)
|
|
|
|
result = {}
|
2023-01-21 02:52:49 +08:00
|
|
|
result[:cookieDomain] = ua_domain_name.gsub(%r{\Ahttp(s)?://}, "") if ua_domain_name
|
2015-04-08 01:09:49 +08:00
|
|
|
result[:userId] = current_user.id if current_user.present?
|
2017-07-14 03:21:44 +08:00
|
|
|
result[:allowLinker] = true if SiteSetting.ga_universal_auto_link_domains.present?
|
2018-09-10 14:10:20 +08:00
|
|
|
result.to_json
|
2015-04-08 01:09:49 +08:00
|
|
|
end
|
|
|
|
|
2016-07-15 01:52:37 +08:00
|
|
|
def ga_universal_json
|
|
|
|
google_universal_analytics_json(SiteSetting.ga_universal_domain_name)
|
|
|
|
end
|
|
|
|
|
|
|
|
def google_tag_manager_json
|
2016-08-03 02:54:06 +08:00
|
|
|
google_universal_analytics_json
|
2016-07-15 01:52:37 +08:00
|
|
|
end
|
|
|
|
|
2024-02-16 19:16:54 +08:00
|
|
|
def csp_nonce_placeholder
|
2024-03-06 21:01:32 +08:00
|
|
|
ContentSecurityPolicy.nonce_placeholder(response.headers)
|
2021-03-26 23:19:31 +08:00
|
|
|
end
|
|
|
|
|
2014-10-24 10:38:00 +08:00
|
|
|
def shared_session_key
|
2020-04-30 14:48:34 +08:00
|
|
|
if SiteSetting.long_polling_base_url != "/" && current_user
|
2014-10-24 10:38:00 +08:00
|
|
|
sk = "shared_session_key"
|
|
|
|
return request.env[sk] if request.env[sk]
|
|
|
|
|
|
|
|
request.env[sk] = key = (session[sk] ||= SecureRandom.hex)
|
2019-12-03 17:05:53 +08:00
|
|
|
Discourse.redis.setex "#{sk}_#{key}", 7.days, current_user.id.to_s
|
2014-10-24 10:38:00 +08:00
|
|
|
key
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-10-06 13:20:01 +08:00
|
|
|
def is_brotli_req?
|
|
|
|
request.env["HTTP_ACCEPT_ENCODING"] =~ /br/
|
|
|
|
end
|
|
|
|
|
2019-07-16 22:05:37 +08:00
|
|
|
def is_gzip_req?
|
|
|
|
request.env["HTTP_ACCEPT_ENCODING"] =~ /gzip/
|
|
|
|
end
|
|
|
|
|
2018-11-16 05:13:18 +08:00
|
|
|
def script_asset_path(script)
|
2020-09-05 03:23:01 +08:00
|
|
|
path = ActionController::Base.helpers.asset_path("#{script}.js")
|
2017-04-17 23:52:43 +08:00
|
|
|
|
2017-10-06 13:20:01 +08:00
|
|
|
if GlobalSetting.use_s3? && GlobalSetting.s3_cdn_url
|
2022-12-08 18:36:20 +08:00
|
|
|
resolved_s3_asset_cdn_url =
|
|
|
|
GlobalSetting.s3_asset_cdn_url.presence || GlobalSetting.s3_cdn_url
|
2017-10-06 13:20:01 +08:00
|
|
|
if GlobalSetting.cdn_url
|
2019-06-18 02:51:17 +08:00
|
|
|
folder = ActionController::Base.config.relative_url_root || "/"
|
2022-12-08 18:36:20 +08:00
|
|
|
path =
|
|
|
|
path.gsub(
|
|
|
|
File.join(GlobalSetting.cdn_url, folder, "/"),
|
|
|
|
File.join(resolved_s3_asset_cdn_url, "/"),
|
|
|
|
)
|
2017-10-06 13:20:01 +08:00
|
|
|
else
|
2018-08-22 10:31:13 +08:00
|
|
|
# we must remove the subfolder path here, assets are uploaded to s3
|
|
|
|
# without it getting involved
|
|
|
|
if ActionController::Base.config.relative_url_root
|
|
|
|
path = path.sub(ActionController::Base.config.relative_url_root, "")
|
|
|
|
end
|
|
|
|
|
2022-12-08 18:36:20 +08:00
|
|
|
path = "#{resolved_s3_asset_cdn_url}#{path}"
|
2017-10-06 13:20:01 +08:00
|
|
|
end
|
|
|
|
|
2021-07-15 03:52:35 +08:00
|
|
|
# assets needed for theme testing are not compressed because they take a fair
|
|
|
|
# amount of time to compress (+30 seconds) during rebuilds/deploys when the
|
|
|
|
# vast majority of sites will never need them, so it makes more sense to serve
|
|
|
|
# them uncompressed instead of making everyone's rebuild/deploy take +30 more
|
|
|
|
# seconds.
|
|
|
|
if !script.start_with?("discourse/tests/")
|
|
|
|
if is_brotli_req?
|
2023-01-21 02:52:49 +08:00
|
|
|
path = path.gsub(/\.([^.]+)\z/, '.br.\1')
|
2021-07-15 03:52:35 +08:00
|
|
|
elsif is_gzip_req?
|
2023-01-21 02:52:49 +08:00
|
|
|
path = path.gsub(/\.([^.]+)\z/, '.gz.\1')
|
2021-07-15 03:52:35 +08:00
|
|
|
end
|
2017-10-06 13:20:01 +08:00
|
|
|
end
|
2014-05-19 06:46:09 +08:00
|
|
|
end
|
2017-10-06 13:20:01 +08:00
|
|
|
|
2018-11-16 05:13:18 +08:00
|
|
|
path
|
|
|
|
end
|
|
|
|
|
DEV: Allow Ember CLI assets to be used by development Rails app (#16511)
Previously, accessing the Rails app directly in development mode would give you assets from our 'legacy' Ember asset pipeline. The only way to run with Ember CLI assets was to run ember-cli as a proxy. This was quite limiting when working on things which are bypassed when using the ember-cli proxy (e.g. changes to `application.html.erb`). Also, since `ember-auto-import` introduced chunking, visiting `/theme-qunit` under Ember CLI was failing to include all necessary chunks.
This commit teaches Sprockets about our Ember CLI assets so that they can be used in development mode, and are automatically collected up under `/public/assets` during `assets:precompile`. As a bonus, this allows us to remove all the custom manifest modification from `assets:precompile`.
The key changes are:
- Introduce a shared `EmberCli.enabled?` helper
- When ember-cli is enabled, add ember-cli `/dist/assets` as the top-priority Rails asset directory
- Have ember-cli output a `chunks.json` manifest, and teach `preload_script` to read it and append the correct chunks to their associated `afterFile`
- Remove most custom ember-cli logic from the `assets:precompile` step. Instead, rely on Rails to take care of pulling the 'precompiled' assets into the `public/assets` directory. Move the 'renaming' logic to runtime, so it can be used in development mode as well.
- Remove fingerprinting from `ember-cli-build`, and allow Rails to take care of things
Long-term, we may want to replace Sprockets with the lighter-weight Propshaft. The changes made in this commit have been made with that long-term goal in mind.
tldr: when you visit the rails app directly, you'll now be served the current ember-cli assets. To keep these up-to-date make sure either `ember serve`, or `ember build --watch` is running. If you really want to load the old non-ember-cli assets, then you should start the server with `EMBER_CLI_PROD_ASSETS=0`. (the legacy asset pipeline will be removed very soon)
2022-04-21 23:26:34 +08:00
|
|
|
def preload_script(script)
|
2023-09-04 20:56:34 +08:00
|
|
|
scripts = []
|
DEV: Allow Ember CLI assets to be used by development Rails app (#16511)
Previously, accessing the Rails app directly in development mode would give you assets from our 'legacy' Ember asset pipeline. The only way to run with Ember CLI assets was to run ember-cli as a proxy. This was quite limiting when working on things which are bypassed when using the ember-cli proxy (e.g. changes to `application.html.erb`). Also, since `ember-auto-import` introduced chunking, visiting `/theme-qunit` under Ember CLI was failing to include all necessary chunks.
This commit teaches Sprockets about our Ember CLI assets so that they can be used in development mode, and are automatically collected up under `/public/assets` during `assets:precompile`. As a bonus, this allows us to remove all the custom manifest modification from `assets:precompile`.
The key changes are:
- Introduce a shared `EmberCli.enabled?` helper
- When ember-cli is enabled, add ember-cli `/dist/assets` as the top-priority Rails asset directory
- Have ember-cli output a `chunks.json` manifest, and teach `preload_script` to read it and append the correct chunks to their associated `afterFile`
- Remove most custom ember-cli logic from the `assets:precompile` step. Instead, rely on Rails to take care of pulling the 'precompiled' assets into the `public/assets` directory. Move the 'renaming' logic to runtime, so it can be used in development mode as well.
- Remove fingerprinting from `ember-cli-build`, and allow Rails to take care of things
Long-term, we may want to replace Sprockets with the lighter-weight Propshaft. The changes made in this commit have been made with that long-term goal in mind.
tldr: when you visit the rails app directly, you'll now be served the current ember-cli assets. To keep these up-to-date make sure either `ember serve`, or `ember build --watch` is running. If you really want to load the old non-ember-cli assets, then you should start the server with `EMBER_CLI_PROD_ASSETS=0`. (the legacy asset pipeline will be removed very soon)
2022-04-21 23:26:34 +08:00
|
|
|
|
2022-06-20 22:33:05 +08:00
|
|
|
if chunks = EmberCli.script_chunks[script]
|
DEV: Allow Ember CLI assets to be used by development Rails app (#16511)
Previously, accessing the Rails app directly in development mode would give you assets from our 'legacy' Ember asset pipeline. The only way to run with Ember CLI assets was to run ember-cli as a proxy. This was quite limiting when working on things which are bypassed when using the ember-cli proxy (e.g. changes to `application.html.erb`). Also, since `ember-auto-import` introduced chunking, visiting `/theme-qunit` under Ember CLI was failing to include all necessary chunks.
This commit teaches Sprockets about our Ember CLI assets so that they can be used in development mode, and are automatically collected up under `/public/assets` during `assets:precompile`. As a bonus, this allows us to remove all the custom manifest modification from `assets:precompile`.
The key changes are:
- Introduce a shared `EmberCli.enabled?` helper
- When ember-cli is enabled, add ember-cli `/dist/assets` as the top-priority Rails asset directory
- Have ember-cli output a `chunks.json` manifest, and teach `preload_script` to read it and append the correct chunks to their associated `afterFile`
- Remove most custom ember-cli logic from the `assets:precompile` step. Instead, rely on Rails to take care of pulling the 'precompiled' assets into the `public/assets` directory. Move the 'renaming' logic to runtime, so it can be used in development mode as well.
- Remove fingerprinting from `ember-cli-build`, and allow Rails to take care of things
Long-term, we may want to replace Sprockets with the lighter-weight Propshaft. The changes made in this commit have been made with that long-term goal in mind.
tldr: when you visit the rails app directly, you'll now be served the current ember-cli assets. To keep these up-to-date make sure either `ember serve`, or `ember build --watch` is running. If you really want to load the old non-ember-cli assets, then you should start the server with `EMBER_CLI_PROD_ASSETS=0`. (the legacy asset pipeline will be removed very soon)
2022-04-21 23:26:34 +08:00
|
|
|
scripts.push(*chunks)
|
2023-09-04 20:56:34 +08:00
|
|
|
else
|
|
|
|
scripts.push(script)
|
2022-02-14 19:21:39 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
scripts
|
|
|
|
.map do |name|
|
DEV: Allow Ember CLI assets to be used by development Rails app (#16511)
Previously, accessing the Rails app directly in development mode would give you assets from our 'legacy' Ember asset pipeline. The only way to run with Ember CLI assets was to run ember-cli as a proxy. This was quite limiting when working on things which are bypassed when using the ember-cli proxy (e.g. changes to `application.html.erb`). Also, since `ember-auto-import` introduced chunking, visiting `/theme-qunit` under Ember CLI was failing to include all necessary chunks.
This commit teaches Sprockets about our Ember CLI assets so that they can be used in development mode, and are automatically collected up under `/public/assets` during `assets:precompile`. As a bonus, this allows us to remove all the custom manifest modification from `assets:precompile`.
The key changes are:
- Introduce a shared `EmberCli.enabled?` helper
- When ember-cli is enabled, add ember-cli `/dist/assets` as the top-priority Rails asset directory
- Have ember-cli output a `chunks.json` manifest, and teach `preload_script` to read it and append the correct chunks to their associated `afterFile`
- Remove most custom ember-cli logic from the `assets:precompile` step. Instead, rely on Rails to take care of pulling the 'precompiled' assets into the `public/assets` directory. Move the 'renaming' logic to runtime, so it can be used in development mode as well.
- Remove fingerprinting from `ember-cli-build`, and allow Rails to take care of things
Long-term, we may want to replace Sprockets with the lighter-weight Propshaft. The changes made in this commit have been made with that long-term goal in mind.
tldr: when you visit the rails app directly, you'll now be served the current ember-cli assets. To keep these up-to-date make sure either `ember serve`, or `ember build --watch` is running. If you really want to load the old non-ember-cli assets, then you should start the server with `EMBER_CLI_PROD_ASSETS=0`. (the legacy asset pipeline will be removed very soon)
2022-04-21 23:26:34 +08:00
|
|
|
path = script_asset_path(name)
|
2023-11-10 19:16:06 +08:00
|
|
|
preload_script_url(path, entrypoint: script)
|
2022-02-14 19:21:39 +08:00
|
|
|
end
|
|
|
|
.join("\n")
|
|
|
|
.html_safe
|
|
|
|
end
|
|
|
|
|
2023-11-10 19:16:06 +08:00
|
|
|
def preload_script_url(url, entrypoint: nil)
|
|
|
|
entrypoint_attribute = entrypoint ? "data-discourse-entrypoint=\"#{entrypoint}\"" : ""
|
2024-02-16 19:16:54 +08:00
|
|
|
nonce_attribute = "nonce=\"#{csp_nonce_placeholder}\""
|
2023-11-10 19:16:06 +08:00
|
|
|
|
2022-10-12 07:11:44 +08:00
|
|
|
add_resource_preload_list(url, "script")
|
2024-03-18 20:07:29 +08:00
|
|
|
|
|
|
|
<<~HTML.html_safe
|
|
|
|
<script defer src="#{url}" #{entrypoint_attribute} #{nonce_attribute}></script>
|
|
|
|
HTML
|
2022-10-12 07:11:44 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def add_resource_preload_list(resource_url, type)
|
2024-04-04 21:37:44 +08:00
|
|
|
links =
|
|
|
|
controller.instance_variable_get(:@asset_preload_links) ||
|
|
|
|
controller.instance_variable_set(:@asset_preload_links, [])
|
|
|
|
links << %Q(<#{resource_url}>; rel="preload"; as="#{type}")
|
2014-05-15 10:59:26 +08:00
|
|
|
end
|
|
|
|
|
2013-05-03 14:43:11 +08:00
|
|
|
def discourse_csrf_tags
|
|
|
|
# anon can not have a CSRF token cause these are all pages
|
2013-06-06 06:23:43 +08:00
|
|
|
# that may be cached, causing a mismatch between session CSRF
|
2013-05-03 14:43:11 +08:00
|
|
|
# and CSRF on page and horrible impossible to debug login issues
|
|
|
|
csrf_meta_tags if current_user
|
|
|
|
end
|
|
|
|
|
2013-12-19 03:47:22 +08:00
|
|
|
def html_classes
|
2019-01-14 21:21:46 +08:00
|
|
|
list = []
|
|
|
|
list << (mobile_view? ? "mobile-view" : "desktop-view")
|
|
|
|
list << (mobile_device? ? "mobile-device" : "not-mobile-device")
|
2019-05-07 22:44:43 +08:00
|
|
|
list << "ios-device" if ios_device?
|
2019-01-14 21:21:46 +08:00
|
|
|
list << "rtl" if rtl?
|
|
|
|
list << text_size_class
|
2019-01-23 12:43:36 +08:00
|
|
|
list << "anon" unless current_user
|
2019-01-14 21:21:46 +08:00
|
|
|
list.join(" ")
|
2014-08-27 19:38:03 +08:00
|
|
|
end
|
|
|
|
|
2016-07-05 00:10:52 +08:00
|
|
|
def body_classes
|
2017-09-29 01:16:51 +08:00
|
|
|
result = ApplicationHelper.extra_body_classes.to_a
|
2017-06-16 02:20:04 +08:00
|
|
|
|
2022-06-02 01:18:20 +08:00
|
|
|
result << "category-#{@category.slug_path.join("-")}" if @category && @category.url.present?
|
2017-06-16 02:20:04 +08:00
|
|
|
|
2019-03-26 14:59:05 +08:00
|
|
|
if current_user.present? && current_user.primary_group_id &&
|
2023-02-13 12:39:45 +08:00
|
|
|
primary_group_name = Group.where(id: current_user.primary_group_id).pick(:name)
|
2017-06-16 02:20:04 +08:00
|
|
|
result << "primary-group-#{primary_group_name.downcase}"
|
2016-07-05 00:10:52 +08:00
|
|
|
end
|
2017-06-16 02:20:04 +08:00
|
|
|
|
|
|
|
result.join(" ")
|
2016-07-05 00:10:52 +08:00
|
|
|
end
|
|
|
|
|
2019-01-14 21:21:46 +08:00
|
|
|
def text_size_class
|
2019-01-28 19:19:50 +08:00
|
|
|
requested_cookie_size, cookie_seq = cookies[:text_size]&.split("|")
|
|
|
|
server_seq = current_user&.user_option&.text_size_seq
|
|
|
|
if cookie_seq && server_seq && cookie_seq.to_i >= server_seq &&
|
|
|
|
UserOption.text_sizes.keys.include?(requested_cookie_size&.to_sym)
|
|
|
|
cookie_size = requested_cookie_size
|
|
|
|
end
|
|
|
|
|
2019-01-25 23:06:06 +08:00
|
|
|
size = cookie_size || current_user&.user_option&.text_size || SiteSetting.default_text_size
|
2019-01-14 21:21:46 +08:00
|
|
|
"text-size-#{size}"
|
2013-12-19 03:47:22 +08:00
|
|
|
end
|
|
|
|
|
2013-07-03 08:43:52 +08:00
|
|
|
def escape_unicode(javascript)
|
|
|
|
if javascript
|
2013-12-30 11:05:25 +08:00
|
|
|
javascript = javascript.scrub
|
2013-09-10 14:01:36 +08:00
|
|
|
javascript.gsub!(/\342\200\250/u, "
")
|
|
|
|
javascript.gsub!(%r{(</)}u, '\u003C/')
|
2018-09-17 16:31:46 +08:00
|
|
|
javascript
|
2013-07-03 08:43:52 +08:00
|
|
|
else
|
2023-01-09 20:20:10 +08:00
|
|
|
""
|
2013-07-03 08:43:52 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-08 22:38:23 +08:00
|
|
|
def format_topic_title(title)
|
2016-11-23 01:37:22 +08:00
|
|
|
PrettyText.unescape_emoji strip_tags(title)
|
2015-10-15 15:59:29 +08:00
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
def with_format(format, &block)
|
|
|
|
old_formats = formats
|
|
|
|
self.formats = [format]
|
|
|
|
block.call
|
|
|
|
self.formats = old_formats
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
|
|
|
def age_words(secs)
|
|
|
|
AgeWords.age_words(secs)
|
|
|
|
end
|
|
|
|
|
2016-11-11 07:16:24 +08:00
|
|
|
def short_date(dt)
|
|
|
|
if dt.year == Time.now.year
|
|
|
|
I18n.l(dt, format: :short_no_year)
|
|
|
|
else
|
|
|
|
I18n.l(dt, format: :date_only)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
def guardian
|
|
|
|
@guardian ||= Guardian.new(current_user)
|
|
|
|
end
|
|
|
|
|
|
|
|
def admin?
|
|
|
|
current_user.try(:admin?)
|
|
|
|
end
|
|
|
|
|
2013-05-02 13:15:17 +08:00
|
|
|
def moderator?
|
|
|
|
current_user.try(:moderator?)
|
|
|
|
end
|
|
|
|
|
2013-05-02 15:22:27 +08:00
|
|
|
def staff?
|
|
|
|
current_user.try(:staff?)
|
|
|
|
end
|
|
|
|
|
2015-05-20 13:56:54 +08:00
|
|
|
def rtl?
|
2016-12-11 07:57:48 +08:00
|
|
|
%w[ar ur fa_IR he].include? I18n.locale.to_s
|
2015-05-20 13:56:54 +08:00
|
|
|
end
|
|
|
|
|
2018-08-20 19:55:58 +08:00
|
|
|
def html_lang
|
2021-02-10 23:12:09 +08:00
|
|
|
(request ? I18n.locale.to_s : SiteSetting.default_locale).sub("_", "-")
|
2015-05-20 13:56:54 +08:00
|
|
|
end
|
|
|
|
|
2013-03-09 04:04:37 +08:00
|
|
|
# Creates open graph and twitter card meta data
|
|
|
|
def crawlable_meta_data(opts = nil)
|
|
|
|
opts ||= {}
|
2015-10-02 00:24:07 +08:00
|
|
|
opts[:url] ||= "#{Discourse.base_url_no_prefix}#{request.fullpath}"
|
2013-03-08 06:31:06 +08:00
|
|
|
|
2022-07-29 14:27:52 +08:00
|
|
|
# if slug generation method is encoded, non encoded urls can sneak in
|
|
|
|
# via bots
|
|
|
|
url = opts[:url]
|
|
|
|
if url.encoding.name != "UTF-8" || !url.valid_encoding?
|
|
|
|
opts[:url] = url.dup.force_encoding("UTF-8").scrub!
|
|
|
|
end
|
|
|
|
|
2019-02-01 03:44:20 +08:00
|
|
|
if opts[:image].blank?
|
|
|
|
twitter_summary_large_image_url = SiteSetting.site_twitter_summary_large_image_url
|
|
|
|
|
|
|
|
if twitter_summary_large_image_url.present?
|
|
|
|
opts[:twitter_summary_large_image] = twitter_summary_large_image_url
|
|
|
|
end
|
|
|
|
|
2019-05-01 21:44:45 +08:00
|
|
|
opts[:image] = SiteSetting.site_opengraph_image_url
|
2016-08-22 17:28:46 +08:00
|
|
|
end
|
|
|
|
|
2019-01-08 13:47:05 +08:00
|
|
|
# Use the correct scheme for opengraph/twitter image
|
|
|
|
opts[:image] = get_absolute_image_url(opts[:image]) if opts[:image].present?
|
|
|
|
opts[:twitter_summary_large_image] = get_absolute_image_url(
|
|
|
|
opts[:twitter_summary_large_image],
|
|
|
|
) if opts[:twitter_summary_large_image].present?
|
2014-08-08 00:58:26 +08:00
|
|
|
|
2015-10-15 17:00:47 +08:00
|
|
|
result = []
|
2024-01-23 01:57:52 +08:00
|
|
|
result << tag(:meta, property: "og:site_name", content: opts[:site_name] || SiteSetting.title)
|
2021-06-15 02:13:55 +08:00
|
|
|
result << tag(:meta, property: "og:type", content: "website")
|
2014-08-08 00:58:26 +08:00
|
|
|
|
2022-07-29 14:27:52 +08:00
|
|
|
generate_twitter_card_metadata(result, opts)
|
|
|
|
|
2016-09-19 19:41:12 +08:00
|
|
|
result << tag(:meta, property: "og:image", content: opts[:image]) if opts[:image].present?
|
|
|
|
|
|
|
|
%i[url title description].each do |property|
|
2013-03-09 04:04:37 +08:00
|
|
|
if opts[property].present?
|
2017-02-23 05:24:05 +08:00
|
|
|
content = (property == :url ? opts[property] : gsub_emoji_to_unicode(opts[property]))
|
2017-11-28 19:27:43 +08:00
|
|
|
result << tag(:meta, { property: "og:#{property}", content: content }, nil, true)
|
|
|
|
result << tag(:meta, { name: "twitter:#{property}", content: content }, nil, true)
|
2013-03-09 04:04:37 +08:00
|
|
|
end
|
|
|
|
end
|
2022-11-24 23:28:21 +08:00
|
|
|
Array
|
|
|
|
.wrap(opts[:breadcrumbs])
|
|
|
|
.each do |breadcrumb|
|
|
|
|
result << tag(:meta, property: "og:article:section", content: breadcrumb[:name])
|
|
|
|
result << tag(:meta, property: "og:article:section:color", content: breadcrumb[:color])
|
|
|
|
end
|
|
|
|
Array
|
|
|
|
.wrap(opts[:tags])
|
|
|
|
.each { |tag_name| result << tag(:meta, property: "og:article:tag", content: tag_name) }
|
2013-03-08 06:31:06 +08:00
|
|
|
|
2016-01-07 19:18:05 +08:00
|
|
|
if opts[:read_time] && opts[:read_time] > 0 && opts[:like_count] && opts[:like_count] > 0
|
2015-12-28 20:52:31 +08:00
|
|
|
result << tag(:meta, name: "twitter:label1", value: I18n.t("reading_time"))
|
|
|
|
result << tag(:meta, name: "twitter:data1", value: "#{opts[:read_time]} mins 🕑")
|
|
|
|
result << tag(:meta, name: "twitter:label2", value: I18n.t("likes"))
|
2015-12-29 06:36:02 +08:00
|
|
|
result << tag(:meta, name: "twitter:data2", value: "#{opts[:like_count]} ❤")
|
2015-12-28 20:52:31 +08:00
|
|
|
end
|
|
|
|
|
2018-07-30 18:52:51 +08:00
|
|
|
if opts[:published_time]
|
|
|
|
result << tag(:meta, property: "article:published_time", content: opts[:published_time])
|
|
|
|
end
|
|
|
|
|
2017-08-15 21:53:03 +08:00
|
|
|
result << tag(:meta, property: "og:ignore_canonical", content: true) if opts[:ignore_canonical]
|
|
|
|
|
2015-10-15 17:00:47 +08:00
|
|
|
result.join("\n")
|
2013-03-08 06:31:06 +08:00
|
|
|
end
|
|
|
|
|
2022-07-29 14:27:52 +08:00
|
|
|
private def generate_twitter_card_metadata(result, opts)
|
2022-06-03 07:02:57 +08:00
|
|
|
img_url =
|
2023-01-09 20:20:10 +08:00
|
|
|
(
|
2022-06-03 07:02:57 +08:00
|
|
|
if opts[:twitter_summary_large_image].present?
|
|
|
|
opts[:twitter_summary_large_image]
|
2023-01-09 20:20:10 +08:00
|
|
|
else
|
2022-06-03 07:02:57 +08:00
|
|
|
opts[:image]
|
2023-01-09 20:20:10 +08:00
|
|
|
end
|
|
|
|
)
|
2022-06-03 07:02:57 +08:00
|
|
|
|
|
|
|
# Twitter does not allow SVGs, see https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/markup
|
|
|
|
if img_url.ends_with?(".svg")
|
|
|
|
img_url = SiteSetting.site_logo_url.ends_with?(".svg") ? nil : SiteSetting.site_logo_url
|
|
|
|
end
|
|
|
|
|
|
|
|
if opts[:twitter_summary_large_image].present? && img_url.present?
|
|
|
|
result << tag(:meta, name: "twitter:card", content: "summary_large_image")
|
|
|
|
result << tag(:meta, name: "twitter:image", content: img_url)
|
|
|
|
elsif opts[:image].present? && img_url.present?
|
|
|
|
result << tag(:meta, name: "twitter:card", content: "summary")
|
|
|
|
result << tag(:meta, name: "twitter:image", content: img_url)
|
|
|
|
else
|
|
|
|
result << tag(:meta, name: "twitter:card", content: "summary")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-02-14 02:29:53 +08:00
|
|
|
def render_sitelinks_search_tag
|
2022-09-23 15:05:53 +08:00
|
|
|
if current_page?("/") || current_page?(Discourse.base_path)
|
|
|
|
json = {
|
|
|
|
"@context" => "http://schema.org",
|
|
|
|
"@type" => "WebSite",
|
|
|
|
:url => Discourse.base_url,
|
2023-08-24 22:07:45 +08:00
|
|
|
:name => SiteSetting.title,
|
2022-09-23 15:05:53 +08:00
|
|
|
:potentialAction => {
|
|
|
|
"@type" => "SearchAction",
|
|
|
|
:target => "#{Discourse.base_url}/search?q={search_term_string}",
|
|
|
|
"query-input" => "required name=search_term_string",
|
|
|
|
},
|
2016-02-14 02:29:53 +08:00
|
|
|
}
|
2022-09-23 15:05:53 +08:00
|
|
|
content_tag(:script, MultiJson.dump(json).html_safe, type: "application/ld+json")
|
|
|
|
end
|
2016-02-14 02:29:53 +08:00
|
|
|
end
|
|
|
|
|
2017-02-23 05:24:05 +08:00
|
|
|
def gsub_emoji_to_unicode(str)
|
2017-07-22 02:24:28 +08:00
|
|
|
Emoji.gsub_emoji_to_unicode(str)
|
2017-02-23 05:24:05 +08:00
|
|
|
end
|
|
|
|
|
2015-02-26 00:35:47 +08:00
|
|
|
def application_logo_url
|
2019-01-18 13:03:38 +08:00
|
|
|
@application_logo_url ||=
|
|
|
|
begin
|
2020-11-13 02:50:55 +08:00
|
|
|
if mobile_view?
|
|
|
|
if dark_color_scheme? && SiteSetting.site_mobile_logo_dark_url.present?
|
|
|
|
SiteSetting.site_mobile_logo_dark_url
|
|
|
|
elsif SiteSetting.site_mobile_logo_url.present?
|
|
|
|
SiteSetting.site_mobile_logo_url
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if dark_color_scheme? && SiteSetting.site_logo_dark_url.present?
|
|
|
|
SiteSetting.site_logo_dark_url
|
2023-01-09 20:20:10 +08:00
|
|
|
else
|
2021-09-17 05:47:51 +08:00
|
|
|
SiteSetting.site_logo_url
|
2023-01-09 20:20:10 +08:00
|
|
|
end
|
2020-11-13 02:50:55 +08:00
|
|
|
end
|
2019-01-18 13:03:38 +08:00
|
|
|
end
|
2015-02-26 00:35:47 +08:00
|
|
|
end
|
|
|
|
|
2021-09-17 05:47:51 +08:00
|
|
|
def application_logo_dark_url
|
|
|
|
@application_logo_dark_url ||=
|
|
|
|
begin
|
|
|
|
if dark_scheme_id != -1
|
|
|
|
if mobile_view? && SiteSetting.site_mobile_logo_dark_url != application_logo_url
|
|
|
|
SiteSetting.site_mobile_logo_dark_url
|
|
|
|
elsif !mobile_view? && SiteSetting.site_logo_dark_url != application_logo_url
|
|
|
|
SiteSetting.site_logo_dark_url
|
2023-01-09 20:20:10 +08:00
|
|
|
end
|
2021-09-17 05:47:51 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-28 20:09:44 +08:00
|
|
|
def waving_hand_url
|
|
|
|
UrlHelper.cook_url(Emoji.url_for(":wave:t#{rand(2..6)}:"))
|
|
|
|
end
|
|
|
|
|
2013-03-20 00:15:14 +08:00
|
|
|
def login_path
|
2020-10-09 19:51:24 +08:00
|
|
|
"#{Discourse.base_path}/login"
|
2013-03-20 00:15:14 +08:00
|
|
|
end
|
2013-08-28 02:57:42 +08:00
|
|
|
|
2013-12-19 03:47:22 +08:00
|
|
|
def mobile_view?
|
2014-01-09 11:08:42 +08:00
|
|
|
MobileDetection.resolve_mobile_view!(request.user_agent, params, session)
|
2013-12-19 03:47:22 +08:00
|
|
|
end
|
|
|
|
|
2016-04-07 22:28:31 +08:00
|
|
|
def crawler_layout?
|
2017-09-08 13:07:22 +08:00
|
|
|
controller&.use_crawler_layout?
|
2016-04-07 22:28:31 +08:00
|
|
|
end
|
|
|
|
|
2016-03-17 02:35:58 +08:00
|
|
|
def include_crawler_content?
|
2024-04-26 05:41:57 +08:00
|
|
|
if current_user && !crawler_layout?
|
2024-04-02 05:27:16 +08:00
|
|
|
params.key?(:print)
|
|
|
|
else
|
|
|
|
crawler_layout? || !mobile_view? || !modern_mobile_device?
|
|
|
|
end
|
2022-04-06 18:09:12 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def modern_mobile_device?
|
|
|
|
MobileDetection.modern_mobile_device?(request.user_agent)
|
2016-03-17 02:35:58 +08:00
|
|
|
end
|
|
|
|
|
2013-12-19 03:47:22 +08:00
|
|
|
def mobile_device?
|
2014-01-09 11:08:42 +08:00
|
|
|
MobileDetection.mobile_device?(request.user_agent)
|
2013-08-30 03:19:28 +08:00
|
|
|
end
|
2013-11-14 23:41:16 +08:00
|
|
|
|
2019-05-07 22:44:43 +08:00
|
|
|
def ios_device?
|
|
|
|
MobileDetection.ios_device?(request.user_agent)
|
|
|
|
end
|
|
|
|
|
2013-11-14 23:41:16 +08:00
|
|
|
def customization_disabled?
|
2022-08-15 22:15:15 +08:00
|
|
|
request.env[ApplicationController::NO_THEMES]
|
2016-11-21 13:46:02 +08:00
|
|
|
end
|
|
|
|
|
2019-04-18 00:25:13 +08:00
|
|
|
def include_ios_native_app_banner?
|
|
|
|
current_user && current_user.trust_level >= 1 && SiteSetting.native_app_install_banner_ios
|
|
|
|
end
|
|
|
|
|
2019-08-27 22:23:57 +08:00
|
|
|
def ios_app_argument
|
|
|
|
# argument only makes sense for DiscourseHub app
|
|
|
|
if SiteSetting.ios_app_id == "1173672076"
|
|
|
|
", app-argument=discourse://new?siteUrl=#{Discourse.base_url}"
|
2023-01-09 20:20:10 +08:00
|
|
|
else
|
2019-08-27 22:23:57 +08:00
|
|
|
""
|
2023-01-09 20:20:10 +08:00
|
|
|
end
|
2019-08-27 22:23:57 +08:00
|
|
|
end
|
|
|
|
|
2022-06-22 04:35:46 +08:00
|
|
|
def include_splash_screen?
|
|
|
|
# A bit basic for now but will be expanded later
|
|
|
|
SiteSetting.splash_screen
|
|
|
|
end
|
|
|
|
|
2016-11-21 13:46:02 +08:00
|
|
|
def allow_plugins?
|
2017-04-15 01:35:12 +08:00
|
|
|
!request.env[ApplicationController::NO_PLUGINS]
|
2016-11-21 13:46:02 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def allow_third_party_plugins?
|
2022-08-15 22:15:15 +08:00
|
|
|
allow_plugins? && !request.env[ApplicationController::NO_UNOFFICIAL_PLUGINS]
|
2016-12-19 07:11:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def normalized_safe_mode
|
2018-10-02 12:29:04 +08:00
|
|
|
safe_mode = []
|
|
|
|
|
2022-08-15 22:15:15 +08:00
|
|
|
safe_mode << ApplicationController::NO_THEMES if customization_disabled?
|
2018-10-02 12:29:04 +08:00
|
|
|
safe_mode << ApplicationController::NO_PLUGINS if !allow_plugins?
|
2022-08-15 22:15:15 +08:00
|
|
|
safe_mode << ApplicationController::NO_UNOFFICIAL_PLUGINS if !allow_third_party_plugins?
|
2018-10-02 12:29:04 +08:00
|
|
|
|
|
|
|
safe_mode.join(",")
|
2013-11-14 23:41:16 +08:00
|
|
|
end
|
|
|
|
|
2015-03-03 06:31:04 +08:00
|
|
|
def loading_admin?
|
2020-06-04 02:45:23 +08:00
|
|
|
return false unless defined?(controller)
|
2021-04-21 17:36:32 +08:00
|
|
|
return false if controller.class.name.blank?
|
|
|
|
|
2015-03-03 06:31:04 +08:00
|
|
|
controller.class.name.split("::").first == "Admin"
|
|
|
|
end
|
|
|
|
|
2015-01-29 03:56:18 +08:00
|
|
|
def category_badge(category, opts = nil)
|
|
|
|
CategoryBadge.html_for(category, opts).html_safe
|
|
|
|
end
|
2014-01-09 11:08:42 +08:00
|
|
|
|
2015-06-03 02:27:52 +08:00
|
|
|
def self.all_connectors
|
|
|
|
@all_connectors = Dir.glob("plugins/*/app/views/connectors/**/*.html.erb")
|
|
|
|
end
|
|
|
|
|
2022-05-20 16:04:43 +08:00
|
|
|
def server_plugin_outlet(name, locals: {})
|
2022-05-20 19:44:55 +08:00
|
|
|
return "" if !GlobalSetting.load_plugins?
|
2022-05-20 16:31:14 +08:00
|
|
|
|
2015-06-03 02:27:52 +08:00
|
|
|
matcher = Regexp.new("/connectors/#{name}/.*\.html\.erb$")
|
|
|
|
erbs = ApplicationHelper.all_connectors.select { |c| c =~ matcher }
|
|
|
|
return "" if erbs.blank?
|
|
|
|
|
2018-06-07 13:44:20 +08:00
|
|
|
result = +""
|
2022-05-20 12:30:24 +08:00
|
|
|
erbs.each { |erb| result << render(inline: File.read(erb), locals: locals) }
|
2015-06-03 02:27:52 +08:00
|
|
|
result.html_safe
|
|
|
|
end
|
|
|
|
|
2016-12-05 20:31:43 +08:00
|
|
|
def topic_featured_link_domain(link)
|
|
|
|
begin
|
2019-12-12 10:49:21 +08:00
|
|
|
uri = UrlHelper.encode_and_parse(link)
|
2016-12-05 20:31:43 +08:00
|
|
|
uri = URI.parse("http://#{uri}") if uri.scheme.nil?
|
|
|
|
host = uri.host.downcase
|
|
|
|
host.start_with?("www.") ? host[4..-1] : host
|
|
|
|
rescue StandardError
|
2023-01-09 20:20:10 +08:00
|
|
|
""
|
2016-12-05 20:31:43 +08:00
|
|
|
end
|
|
|
|
end
|
2017-04-12 22:52:52 +08:00
|
|
|
|
2021-06-15 14:57:17 +08:00
|
|
|
def theme_id
|
2017-04-12 22:52:52 +08:00
|
|
|
if customization_disabled?
|
2021-06-15 14:57:17 +08:00
|
|
|
nil
|
2017-04-12 22:52:52 +08:00
|
|
|
else
|
2021-06-15 14:57:17 +08:00
|
|
|
request.env[:resolved_theme_id]
|
2017-04-12 22:52:52 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-06-15 14:57:17 +08:00
|
|
|
def stylesheet_manager
|
|
|
|
return @stylesheet_manager if defined?(@stylesheet_manager)
|
|
|
|
@stylesheet_manager = Stylesheet::Manager.new(theme_id: theme_id)
|
|
|
|
end
|
|
|
|
|
2018-09-12 09:04:58 +08:00
|
|
|
def scheme_id
|
2020-09-09 15:15:15 +08:00
|
|
|
return @scheme_id if defined?(@scheme_id)
|
|
|
|
|
2020-08-28 22:36:52 +08:00
|
|
|
custom_user_scheme_id = cookies[:color_scheme_id] || current_user&.user_option&.color_scheme_id
|
|
|
|
if custom_user_scheme_id && ColorScheme.find_by_id(custom_user_scheme_id)
|
|
|
|
return custom_user_scheme_id
|
|
|
|
end
|
|
|
|
|
2021-06-15 14:57:17 +08:00
|
|
|
return if theme_id.blank?
|
2020-09-09 15:15:15 +08:00
|
|
|
|
2023-02-13 12:39:45 +08:00
|
|
|
@scheme_id = Theme.where(id: theme_id).pick(:color_scheme_id)
|
2018-09-12 09:04:58 +08:00
|
|
|
end
|
|
|
|
|
2020-08-28 22:36:52 +08:00
|
|
|
def dark_scheme_id
|
|
|
|
cookies[:dark_scheme_id] || current_user&.user_option&.dark_scheme_id ||
|
|
|
|
SiteSetting.default_dark_mode_color_scheme_id
|
|
|
|
end
|
|
|
|
|
2017-11-10 03:45:19 +08:00
|
|
|
def current_homepage
|
2024-04-02 23:05:08 +08:00
|
|
|
current_user&.user_option&.homepage || HomepageHelper.resolve(request, current_user)
|
2017-11-10 03:45:19 +08:00
|
|
|
end
|
|
|
|
|
2017-04-18 03:47:21 +08:00
|
|
|
def build_plugin_html(name)
|
|
|
|
return "" unless allow_plugins?
|
2017-04-19 00:35:19 +08:00
|
|
|
DiscoursePluginRegistry.build_html(name, controller) || ""
|
2017-04-18 03:47:21 +08:00
|
|
|
end
|
|
|
|
|
2017-11-15 05:31:44 +08:00
|
|
|
# If there is plugin HTML return that, otherwise yield to the template
|
|
|
|
def replace_plugin_html(name)
|
2017-12-08 07:30:00 +08:00
|
|
|
if (html = build_plugin_html(name)).present?
|
|
|
|
html
|
|
|
|
else
|
|
|
|
yield
|
|
|
|
nil
|
|
|
|
end
|
2017-11-15 05:31:44 +08:00
|
|
|
end
|
|
|
|
|
2017-04-12 22:52:52 +08:00
|
|
|
def theme_lookup(name)
|
2021-04-12 20:02:58 +08:00
|
|
|
Theme.lookup_field(
|
2021-06-15 14:57:17 +08:00
|
|
|
theme_id,
|
2021-04-12 20:02:58 +08:00
|
|
|
mobile_view? ? :mobile : :desktop,
|
|
|
|
name,
|
|
|
|
skip_transformation: request.env[:skip_theme_ids_transformation].present?,
|
2024-02-16 19:16:54 +08:00
|
|
|
csp_nonce: csp_nonce_placeholder,
|
2021-04-12 20:02:58 +08:00
|
|
|
)
|
2019-01-17 19:46:11 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def theme_translations_lookup
|
2021-04-12 20:02:58 +08:00
|
|
|
Theme.lookup_field(
|
2021-06-15 14:57:17 +08:00
|
|
|
theme_id,
|
2021-04-12 20:02:58 +08:00
|
|
|
:translations,
|
|
|
|
I18n.locale,
|
|
|
|
skip_transformation: request.env[:skip_theme_ids_transformation].present?,
|
2024-02-16 19:16:54 +08:00
|
|
|
csp_nonce: csp_nonce_placeholder,
|
2021-04-12 20:02:58 +08:00
|
|
|
)
|
2017-04-12 22:52:52 +08:00
|
|
|
end
|
|
|
|
|
2019-06-03 17:41:00 +08:00
|
|
|
def theme_js_lookup
|
2021-04-12 20:02:58 +08:00
|
|
|
Theme.lookup_field(
|
2021-06-15 14:57:17 +08:00
|
|
|
theme_id,
|
2021-04-12 20:02:58 +08:00
|
|
|
:extra_js,
|
|
|
|
nil,
|
|
|
|
skip_transformation: request.env[:skip_theme_ids_transformation].present?,
|
2024-02-16 19:16:54 +08:00
|
|
|
csp_nonce: csp_nonce_placeholder,
|
2021-04-12 20:02:58 +08:00
|
|
|
)
|
2019-06-03 17:41:00 +08:00
|
|
|
end
|
|
|
|
|
2022-07-05 00:23:09 +08:00
|
|
|
def discourse_stylesheet_preload_tag(name, opts = {})
|
|
|
|
manager =
|
|
|
|
if opts.key?(:theme_id)
|
|
|
|
Stylesheet::Manager.new(theme_id: customization_disabled? ? nil : opts[:theme_id])
|
|
|
|
else
|
|
|
|
stylesheet_manager
|
|
|
|
end
|
|
|
|
|
|
|
|
manager.stylesheet_preload_tag(name, "all")
|
|
|
|
end
|
|
|
|
|
2017-04-12 22:52:52 +08:00
|
|
|
def discourse_stylesheet_link_tag(name, opts = {})
|
2021-06-15 14:57:17 +08:00
|
|
|
manager =
|
|
|
|
if opts.key?(:theme_id)
|
|
|
|
Stylesheet::Manager.new(theme_id: customization_disabled? ? nil : opts[:theme_id])
|
|
|
|
else
|
|
|
|
stylesheet_manager
|
|
|
|
end
|
2017-04-12 22:52:52 +08:00
|
|
|
|
2022-10-12 07:11:44 +08:00
|
|
|
manager.stylesheet_link_tag(name, "all", self.method(:add_resource_preload_list))
|
2017-04-12 22:52:52 +08:00
|
|
|
end
|
2018-09-17 16:31:46 +08:00
|
|
|
|
2022-07-05 00:23:09 +08:00
|
|
|
def discourse_preload_color_scheme_stylesheets
|
|
|
|
result = +""
|
|
|
|
result << stylesheet_manager.color_scheme_stylesheet_preload_tag(scheme_id, "all")
|
|
|
|
|
|
|
|
if dark_scheme_id != -1
|
|
|
|
result << stylesheet_manager.color_scheme_stylesheet_preload_tag(
|
|
|
|
dark_scheme_id,
|
|
|
|
"(prefers-color-scheme: dark)",
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
result.html_safe
|
|
|
|
end
|
|
|
|
|
2020-08-04 10:57:10 +08:00
|
|
|
def discourse_color_scheme_stylesheets
|
|
|
|
result = +""
|
2022-10-12 07:11:44 +08:00
|
|
|
result << stylesheet_manager.color_scheme_stylesheet_link_tag(
|
|
|
|
scheme_id,
|
|
|
|
"all",
|
|
|
|
self.method(:add_resource_preload_list),
|
|
|
|
)
|
2020-08-04 10:57:10 +08:00
|
|
|
|
|
|
|
if dark_scheme_id != -1
|
2022-10-12 07:11:44 +08:00
|
|
|
result << stylesheet_manager.color_scheme_stylesheet_link_tag(
|
|
|
|
dark_scheme_id,
|
|
|
|
"(prefers-color-scheme: dark)",
|
|
|
|
self.method(:add_resource_preload_list),
|
|
|
|
)
|
2020-08-04 10:57:10 +08:00
|
|
|
end
|
2021-06-15 14:57:17 +08:00
|
|
|
|
2020-08-04 10:57:10 +08:00
|
|
|
result.html_safe
|
|
|
|
end
|
|
|
|
|
2022-10-26 12:18:05 +08:00
|
|
|
def discourse_theme_color_meta_tags
|
2022-11-07 15:06:26 +08:00
|
|
|
result = +""
|
2022-10-26 12:18:05 +08:00
|
|
|
if dark_scheme_id != -1
|
|
|
|
result << <<~HTML
|
2022-11-07 15:06:26 +08:00
|
|
|
<meta name="theme-color" media="(prefers-color-scheme: light)" content="##{ColorScheme.hex_for_name("header_background", scheme_id)}">
|
2022-10-26 12:18:05 +08:00
|
|
|
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="##{ColorScheme.hex_for_name("header_background", dark_scheme_id)}">
|
|
|
|
HTML
|
2022-11-07 15:06:26 +08:00
|
|
|
else
|
|
|
|
result << <<~HTML
|
|
|
|
<meta name="theme-color" media="all" content="##{ColorScheme.hex_for_name("header_background", scheme_id)}">
|
|
|
|
HTML
|
2022-10-26 12:18:05 +08:00
|
|
|
end
|
|
|
|
result.html_safe
|
|
|
|
end
|
|
|
|
|
2020-08-21 02:23:18 +08:00
|
|
|
def dark_color_scheme?
|
2020-09-09 15:18:52 +08:00
|
|
|
return false if scheme_id.blank?
|
2020-08-21 02:23:18 +08:00
|
|
|
ColorScheme.find_by_id(scheme_id)&.is_dark?
|
|
|
|
end
|
|
|
|
|
2018-09-17 16:31:46 +08:00
|
|
|
def preloaded_json
|
|
|
|
return "{}" if @preloaded.blank?
|
|
|
|
@preloaded.transform_values { |value| escape_unicode(value) }.to_json
|
|
|
|
end
|
2018-10-02 12:29:04 +08:00
|
|
|
|
|
|
|
def client_side_setup_data
|
|
|
|
setup_data = {
|
|
|
|
cdn: Rails.configuration.action_controller.asset_host,
|
2019-05-07 12:36:40 +08:00
|
|
|
base_url: Discourse.base_url,
|
2020-10-09 19:51:24 +08:00
|
|
|
base_uri: Discourse.base_path,
|
2018-10-02 12:29:04 +08:00
|
|
|
environment: Rails.env,
|
|
|
|
letter_avatar_version: LetterAvatar.version,
|
2021-05-26 06:39:31 +08:00
|
|
|
service_worker_url: "service-worker.js",
|
2018-10-02 12:29:04 +08:00
|
|
|
default_locale: SiteSetting.default_locale,
|
|
|
|
asset_version: Discourse.assets_digest,
|
|
|
|
disable_custom_css: loading_admin?,
|
2020-07-15 20:52:35 +08:00
|
|
|
highlight_js_path: HighlightJs.path,
|
2021-06-15 14:57:17 +08:00
|
|
|
svg_sprite_path: SvgSprite.path(theme_id),
|
2019-08-20 09:29:11 +08:00
|
|
|
enable_js_error_reporting: GlobalSetting.enable_js_error_reporting,
|
2020-08-28 22:36:52 +08:00
|
|
|
color_scheme_is_dark: dark_color_scheme?,
|
|
|
|
user_color_scheme_id: scheme_id,
|
|
|
|
user_dark_scheme_id: dark_scheme_id,
|
2018-10-02 12:29:04 +08:00
|
|
|
}
|
|
|
|
|
2018-11-27 05:49:57 +08:00
|
|
|
if Rails.env.development?
|
2021-06-15 14:57:17 +08:00
|
|
|
setup_data[:svg_icon_list] = SvgSprite.all_icons(theme_id)
|
2020-02-06 11:14:33 +08:00
|
|
|
|
|
|
|
setup_data[:debug_preloaded_app_data] = true if ENV["DEBUG_PRELOADED_APP_DATA"]
|
2021-05-15 00:36:53 +08:00
|
|
|
setup_data[:mb_last_file_change_id] = MessageBus.last_id("/file-change")
|
2018-11-27 05:49:57 +08:00
|
|
|
end
|
|
|
|
|
2018-10-02 12:29:04 +08:00
|
|
|
if guardian.can_enable_safe_mode? && params["safe_mode"]
|
|
|
|
setup_data[:safe_mode] = normalized_safe_mode
|
|
|
|
end
|
|
|
|
|
|
|
|
if SiteSetting.Upload.enable_s3_uploads
|
|
|
|
setup_data[:s3_cdn] = SiteSetting.Upload.s3_cdn_url.presence
|
|
|
|
setup_data[:s3_base_url] = SiteSetting.Upload.s3_base_url
|
|
|
|
end
|
|
|
|
|
|
|
|
setup_data
|
|
|
|
end
|
2019-01-08 13:47:05 +08:00
|
|
|
|
|
|
|
def get_absolute_image_url(link)
|
|
|
|
absolute_url = link
|
2020-04-22 14:55:59 +08:00
|
|
|
if link.start_with?("//")
|
2019-01-08 13:47:05 +08:00
|
|
|
uri = URI(Discourse.base_url)
|
|
|
|
absolute_url = "#{uri.scheme}:#{link}"
|
2020-04-22 14:55:59 +08:00
|
|
|
elsif link.start_with?("/uploads/", "/images/", "/user_avatar/")
|
2020-04-22 14:38:59 +08:00
|
|
|
absolute_url = "#{Discourse.base_url}#{link}"
|
2019-01-08 13:47:05 +08:00
|
|
|
elsif GlobalSetting.relative_url_root && link.start_with?(GlobalSetting.relative_url_root)
|
|
|
|
absolute_url = "#{Discourse.base_url_no_prefix}#{link}"
|
|
|
|
end
|
|
|
|
absolute_url
|
|
|
|
end
|
2019-07-09 07:21:19 +08:00
|
|
|
|
2024-01-17 19:30:27 +08:00
|
|
|
def escape_noscript(&block)
|
|
|
|
raw capture(&block).gsub(%r{<(/\s*noscript)}i, '<\1')
|
|
|
|
end
|
|
|
|
|
2021-10-07 04:41:52 +08:00
|
|
|
def manifest_url
|
|
|
|
# If you want the `manifest_url` to be different for a specific action,
|
|
|
|
# in the action set @manifest_url = X. Originally added for chat to add a
|
|
|
|
# separate manifest
|
|
|
|
@manifest_url || "#{Discourse.base_path}/manifest.webmanifest"
|
|
|
|
end
|
|
|
|
|
2019-07-09 07:21:19 +08:00
|
|
|
def can_sign_up?
|
|
|
|
SiteSetting.allow_new_registrations && !SiteSetting.invite_only &&
|
2021-02-08 18:04:33 +08:00
|
|
|
!SiteSetting.enable_discourse_connect
|
2019-07-09 07:21:19 +08:00
|
|
|
end
|
2020-04-20 14:08:24 +08:00
|
|
|
|
|
|
|
def rss_creator(user)
|
2022-04-13 21:52:56 +08:00
|
|
|
user&.display_name
|
2020-04-20 14:08:24 +08:00
|
|
|
end
|
2021-01-25 21:47:44 +08:00
|
|
|
|
2024-04-02 23:05:08 +08:00
|
|
|
def anonymous_top_menu_items
|
|
|
|
Discourse.anonymous_top_menu_items.map(&:to_s)
|
|
|
|
end
|
|
|
|
|
2021-01-25 21:47:44 +08:00
|
|
|
def authentication_data
|
|
|
|
return @authentication_data if defined?(@authentication_data)
|
|
|
|
|
|
|
|
@authentication_data =
|
|
|
|
begin
|
|
|
|
value = cookies[:authentication_data]
|
|
|
|
cookies.delete(:authentication_data, path: Discourse.base_path("/")) if value
|
|
|
|
current_user ? nil : value
|
|
|
|
end
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|