Module: ApplicationHelper

Class Method Summary collapse

Instance Method Summary collapse

Methods included from GlobalPath

#cdn_path, #cdn_relative_path, #full_cdn_url, #path, #upload_cdn_path

Methods included from ConfigurableUrls

#faq_path, #privacy_policy_url, #tos_url

Methods included from CanonicalURL::Helpers

#canonical_link_tag

Methods included from CurrentUser

#clear_current_user, #current_user, has_auth_cookie?, #is_api?, #is_user_api?, #log_off_user, #log_on_user, lookup_from_env, #refresh_session

Class Method Details

.all_connectorsObject



506
507
508
# File 'app/helpers/application_helper.rb', line 506

def self.all_connectors
  @all_connectors = Dir.glob("plugins/*/app/views/connectors/**/*.html.erb")
end

.extra_body_classesObject



12
13
14
# File 'app/helpers/application_helper.rb', line 12

def self.extra_body_classes
  @extra_body_classes ||= Set.new
end

Instance Method Details

#add_resource_preload_list(resource_url, type) ⇒ Object



167
168
169
170
171
# File 'app/helpers/application_helper.rb', line 167

def add_resource_preload_list(resource_url, type)
  if !@links_to_preload.nil?
    @links_to_preload << %Q(<#{resource_url}>; rel="preload"; as="#{type}")
  end
end

#admin?Boolean

Returns:

  • (Boolean)


255
256
257
# File 'app/helpers/application_helper.rb', line 255

def admin?
  current_user.try(:admin?)
end

#age_words(secs) ⇒ Object



239
240
241
# File 'app/helpers/application_helper.rb', line 239

def age_words(secs)
  AgeWords.age_words(secs)
end

#allow_plugins?Boolean

Returns:

  • (Boolean)


477
478
479
# File 'app/helpers/application_helper.rb', line 477

def allow_plugins?
  !request.env[ApplicationController::NO_PLUGINS]
end

#allow_third_party_plugins?Boolean

Returns:

  • (Boolean)


481
482
483
# File 'app/helpers/application_helper.rb', line 481

def allow_third_party_plugins?
  allow_plugins? && !request.env[ApplicationController::NO_UNOFFICIAL_PLUGINS]
end

#application_logo_dark_urlObject



410
411
412
413
414
415
416
417
418
419
420
421
# File 'app/helpers/application_helper.rb', line 410

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
        end
      end
    end
end

#application_logo_urlObject



391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
# File 'app/helpers/application_helper.rb', line 391

def application_logo_url
  @application_logo_url ||=
    begin
      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
        else
          SiteSetting.site_logo_url
        end
      end
    end
end

#authentication_dataObject



758
759
760
761
762
763
764
765
766
767
# File 'app/helpers/application_helper.rb', line 758

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

#body_classesObject



191
192
193
194
195
196
197
198
199
200
201
202
# File 'app/helpers/application_helper.rb', line 191

def body_classes
  result = ApplicationHelper.extra_body_classes.to_a

  result << "category-#{@category.slug_path.join("-")}" if @category && @category.url.present?

  if current_user.present? && current_user.primary_group_id &&
       primary_group_name = Group.where(id: current_user.primary_group_id).pick(:name)
    result << "primary-group-#{primary_group_name.downcase}"
  end

  result.join(" ")
end

#build_plugin_html(name) ⇒ Object



568
569
570
571
# File 'app/helpers/application_helper.rb', line 568

def build_plugin_html(name)
  return "" unless allow_plugins?
  DiscoursePluginRegistry.build_html(name, controller) || ""
end

#can_sign_up?Boolean

Returns:

  • (Boolean)


749
750
751
752
# File 'app/helpers/application_helper.rb', line 749

def can_sign_up?
  SiteSetting.allow_new_registrations && !SiteSetting.invite_only &&
    !SiteSetting.enable_discourse_connect
end

#category_badge(category, opts = nil) ⇒ Object



502
503
504
# File 'app/helpers/application_helper.rb', line 502

def category_badge(category, opts = nil)
  CategoryBadge.html_for(category, opts).html_safe
end

#client_side_setup_dataObject



690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
# File 'app/helpers/application_helper.rb', line 690

def client_side_setup_data
  setup_data = {
    cdn: Rails.configuration.action_controller.asset_host,
    base_url: Discourse.base_url,
    base_uri: Discourse.base_path,
    environment: Rails.env,
    letter_avatar_version: LetterAvatar.version,
    markdown_it_url: script_asset_path("markdown-it-bundle"),
    service_worker_url: "service-worker.js",
    default_locale: SiteSetting.default_locale,
    asset_version: Discourse.assets_digest,
    disable_custom_css: loading_admin?,
    highlight_js_path: HighlightJs.path,
    svg_sprite_path: SvgSprite.path(theme_id),
    enable_js_error_reporting: GlobalSetting.enable_js_error_reporting,
    color_scheme_is_dark: dark_color_scheme?,
    user_color_scheme_id: scheme_id,
    user_dark_scheme_id: dark_scheme_id,
  }

  if Rails.env.development?
    setup_data[:svg_icon_list] = SvgSprite.all_icons(theme_id)

    setup_data[:debug_preloaded_app_data] = true if ENV["DEBUG_PRELOADED_APP_DATA"]
    setup_data[:mb_last_file_change_id] = MessageBus.last_id("/file-change")
  end

  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

#crawlable_meta_data(opts = nil) ⇒ Object

Creates open graph and twitter card meta data



276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'app/helpers/application_helper.rb', line 276

def (opts = nil)
  opts ||= {}
  opts[:url] ||= "#{Discourse.base_url_no_prefix}#{request.fullpath}"

  # 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

  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

    opts[:image] = SiteSetting.site_opengraph_image_url
  end

  # 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?

  result = []
  result << tag(:meta, property: "og:site_name", content: SiteSetting.title)
  result << tag(:meta, property: "og:type", content: "website")

  (result, opts)

  result << tag(:meta, property: "og:image", content: opts[:image]) if opts[:image].present?

  %i[url title description].each do |property|
    if opts[property].present?
      content = (property == :url ? opts[property] : gsub_emoji_to_unicode(opts[property]))
      result << tag(:meta, { property: "og:#{property}", content: content }, nil, true)
      result << tag(:meta, { name: "twitter:#{property}", content: content }, nil, true)
    end
  end
  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) }

  if opts[:read_time] && opts[:read_time] > 0 && opts[:like_count] && opts[:like_count] > 0
    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"))
    result << tag(:meta, name: "twitter:data2", value: "#{opts[:like_count]}")
  end

  if opts[:published_time]
    result << tag(:meta, property: "article:published_time", content: opts[:published_time])
  end

  result << tag(:meta, property: "og:ignore_canonical", content: true) if opts[:ignore_canonical]

  result.join("\n")
end

#crawler_layout?Boolean

Returns:

  • (Boolean)


435
436
437
# File 'app/helpers/application_helper.rb', line 435

def crawler_layout?
  controller&.use_crawler_layout?
end

#current_homepageObject



564
565
566
# File 'app/helpers/application_helper.rb', line 564

def current_homepage
  current_user&.user_option&.homepage || SiteSetting.anonymous_homepage
end

#customization_disabled?Boolean

Returns:

  • (Boolean)


455
456
457
# File 'app/helpers/application_helper.rb', line 455

def customization_disabled?
  request.env[ApplicationController::NO_THEMES]
end

#dark_color_scheme?Boolean

Returns:

  • (Boolean)


680
681
682
683
# File 'app/helpers/application_helper.rb', line 680

def dark_color_scheme?
  return false if scheme_id.blank?
  ColorScheme.find_by_id(scheme_id)&.is_dark?
end

#dark_scheme_idObject



559
560
561
562
# File 'app/helpers/application_helper.rb', line 559

def dark_scheme_id
  cookies[:dark_scheme_id] || current_user&.user_option&.dark_scheme_id ||
    SiteSetting.default_dark_mode_color_scheme_id
end

#discourse_color_scheme_stylesheetsObject



646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
# File 'app/helpers/application_helper.rb', line 646

def discourse_color_scheme_stylesheets
  result = +""
  result << stylesheet_manager.color_scheme_stylesheet_link_tag(
    scheme_id,
    "all",
    self.method(:add_resource_preload_list),
  )

  if dark_scheme_id != -1
    result << stylesheet_manager.color_scheme_stylesheet_link_tag(
      dark_scheme_id,
      "(prefers-color-scheme: dark)",
      self.method(:add_resource_preload_list),
    )
  end

  result.html_safe
end

#discourse_config_environment(testing: false) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'app/helpers/application_helper.rb', line 16

def discourse_config_environment(testing: false)
  # TODO: Can this come from Ember CLI somehow?
  config = {
    modulePrefix: "discourse",
    environment: Rails.env,
    rootURL: Discourse.base_path,
    locationType: "history",
    historySupportMiddleware: false,
    EmberENV: {
      FEATURES: {
      },
      EXTEND_PROTOTYPES: {
        Date: false,
      },
      _APPLICATION_TEMPLATE_WRAPPER: false,
      _DEFAULT_ASYNC_OBSERVERS: true,
      _JQUERY_INTEGRATION: true,
    },
    APP: {
      name: "discourse",
      version: "#{Discourse::VERSION::STRING} #{Discourse.git_version}",
      exportApplicationGlobal: true,
    },
  }

  if testing
    config[:environment] = "test"
    config[:locationType] = "none"
    config[:APP][:autoboot] = false
    config[:APP][:rootElement] = "#ember-testing"
  end

  config.to_json
end

#discourse_csrf_tagsObject



173
174
175
176
177
178
# File 'app/helpers/application_helper.rb', line 173

def discourse_csrf_tags
  # anon can not have a CSRF token cause these are all pages
  # that may be cached, causing a mismatch between session CSRF
  # and CSRF on page and horrible impossible to debug login issues
  csrf_meta_tags if current_user
end

#discourse_preload_color_scheme_stylesheetsObject



632
633
634
635
636
637
638
639
640
641
642
643
644
# File 'app/helpers/application_helper.rb', line 632

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


621
622
623
624
625
626
627
628
629
630
# File 'app/helpers/application_helper.rb', line 621

def discourse_stylesheet_link_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_link_tag(name, "all", self.method(:add_resource_preload_list))
end

#discourse_stylesheet_preload_tag(name, opts = {}) ⇒ Object



610
611
612
613
614
615
616
617
618
619
# File 'app/helpers/application_helper.rb', line 610

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

#discourse_theme_color_meta_tagsObject



665
666
667
668
669
670
671
672
673
674
675
676
677
678
# File 'app/helpers/application_helper.rb', line 665

def discourse_theme_color_meta_tags
  result = +""
  if dark_scheme_id != -1
    result << <<~HTML
      <meta name="theme-color" media="(prefers-color-scheme: light)" content="##{ColorScheme.hex_for_name("header_background", scheme_id)}">
      <meta name="theme-color" media="(prefers-color-scheme: dark)" content="##{ColorScheme.hex_for_name("header_background", dark_scheme_id)}">
    HTML
  else
    result << <<~HTML
      <meta name="theme-color" media="all" content="##{ColorScheme.hex_for_name("header_background", scheme_id)}">
    HTML
  end
  result.html_safe
end

#escape_unicode(javascript) ⇒ Object



216
217
218
219
220
221
222
223
224
225
# File 'app/helpers/application_helper.rb', line 216

def escape_unicode(javascript)
  if javascript
    javascript = javascript.scrub
    javascript.gsub!(/\342\200\250/u, "&#x2028;")
    javascript.gsub!(%r{(</)}u, '\u003C/')
    javascript
  else
    ""
  end
end

#format_topic_title(title) ⇒ Object



227
228
229
# File 'app/helpers/application_helper.rb', line 227

def format_topic_title(title)
  PrettyText.unescape_emoji strip_tags(title)
end

#ga_universal_jsonObject



59
60
61
# File 'app/helpers/application_helper.rb', line 59

def ga_universal_json
  google_universal_analytics_json(SiteSetting.ga_universal_domain_name)
end

#get_absolute_image_url(link) ⇒ Object



729
730
731
732
733
734
735
736
737
738
739
740
# File 'app/helpers/application_helper.rb', line 729

def get_absolute_image_url(link)
  absolute_url = link
  if link.start_with?("//")
    uri = URI(Discourse.base_url)
    absolute_url = "#{uri.scheme}:#{link}"
  elsif link.start_with?("/uploads/", "/images/", "/user_avatar/")
    absolute_url = "#{Discourse.base_url}#{link}"
  elsif GlobalSetting.relative_url_root && link.start_with?(GlobalSetting.relative_url_root)
    absolute_url = "#{Discourse.base_url_no_prefix}#{link}"
  end
  absolute_url
end

#google_tag_manager_jsonObject



63
64
65
# File 'app/helpers/application_helper.rb', line 63

def google_tag_manager_json
  google_universal_analytics_json
end

#google_tag_manager_nonce_placeholderObject



67
68
69
70
71
# File 'app/helpers/application_helper.rb', line 67

def google_tag_manager_nonce_placeholder
  placeholder = "[[csp_nonce_placeholder_#{SecureRandom.hex}]]"
  response.headers["Discourse-GTM-Nonce-Placeholder"] = placeholder
  placeholder
end

#google_universal_analytics_json(ua_domain_name = nil) ⇒ Object



51
52
53
54
55
56
57
# File 'app/helpers/application_helper.rb', line 51

def google_universal_analytics_json(ua_domain_name = nil)
  result = {}
  result[:cookieDomain] = ua_domain_name.gsub(%r{\Ahttp(s)?://}, "") if ua_domain_name
  result[:userId] = current_user.id if current_user.present?
  result[:allowLinker] = true if SiteSetting.ga_universal_auto_link_domains.present?
  result.to_json
end

#gsub_emoji_to_unicode(str) ⇒ Object



387
388
389
# File 'app/helpers/application_helper.rb', line 387

def gsub_emoji_to_unicode(str)
  Emoji.gsub_emoji_to_unicode(str)
end

#guardianObject



251
252
253
# File 'app/helpers/application_helper.rb', line 251

def guardian
  @guardian ||= Guardian.new(current_user)
end

#html_classesObject



180
181
182
183
184
185
186
187
188
189
# File 'app/helpers/application_helper.rb', line 180

def html_classes
  list = []
  list << (mobile_view? ? "mobile-view" : "desktop-view")
  list << (mobile_device? ? "mobile-device" : "not-mobile-device")
  list << "ios-device" if ios_device?
  list << "rtl" if rtl?
  list << text_size_class
  list << "anon" unless current_user
  list.join(" ")
end

#html_langObject



271
272
273
# File 'app/helpers/application_helper.rb', line 271

def html_lang
  (request ? I18n.locale.to_s : SiteSetting.default_locale).sub("_", "-")
end

#include_crawler_content?Boolean

Returns:

  • (Boolean)


439
440
441
# File 'app/helpers/application_helper.rb', line 439

def include_crawler_content?
  crawler_layout? || !mobile_view? || !modern_mobile_device?
end

#include_ios_native_app_banner?Boolean

Returns:

  • (Boolean)


459
460
461
# File 'app/helpers/application_helper.rb', line 459

def include_ios_native_app_banner?
  current_user && current_user.trust_level >= 1 && SiteSetting.native_app_install_banner_ios
end

#include_splash_screen?Boolean

Returns:

  • (Boolean)


472
473
474
475
# File 'app/helpers/application_helper.rb', line 472

def include_splash_screen?
  # A bit basic for now but will be expanded later
  SiteSetting.splash_screen
end

#ios_app_argumentObject



463
464
465
466
467
468
469
470
# File 'app/helpers/application_helper.rb', line 463

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}"
  else
    ""
  end
end

#ios_device?Boolean

Returns:

  • (Boolean)


451
452
453
# File 'app/helpers/application_helper.rb', line 451

def ios_device?
  MobileDetection.ios_device?(request.user_agent)
end

#is_brotli_req?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'app/helpers/application_helper.rb', line 84

def is_brotli_req?
  request.env["HTTP_ACCEPT_ENCODING"] =~ /br/
end

#is_gzip_req?Boolean

Returns:

  • (Boolean)


88
89
90
# File 'app/helpers/application_helper.rb', line 88

def is_gzip_req?
  request.env["HTTP_ACCEPT_ENCODING"] =~ /gzip/
end

#loading_admin?Boolean

Returns:

  • (Boolean)


495
496
497
498
499
500
# File 'app/helpers/application_helper.rb', line 495

def loading_admin?
  return false unless defined?(controller)
  return false if controller.class.name.blank?

  controller.class.name.split("::").first == "Admin"
end

#login_pathObject



427
428
429
# File 'app/helpers/application_helper.rb', line 427

def 
  "#{Discourse.base_path}/login"
end

#manifest_urlObject



742
743
744
745
746
747
# File 'app/helpers/application_helper.rb', line 742

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

#mobile_device?Boolean

Returns:

  • (Boolean)


447
448
449
# File 'app/helpers/application_helper.rb', line 447

def mobile_device?
  MobileDetection.mobile_device?(request.user_agent)
end

#mobile_view?Boolean

Returns:

  • (Boolean)


431
432
433
# File 'app/helpers/application_helper.rb', line 431

def mobile_view?
  MobileDetection.resolve_mobile_view!(request.user_agent, params, session)
end

#moderator?Boolean

Returns:

  • (Boolean)


259
260
261
# File 'app/helpers/application_helper.rb', line 259

def moderator?
  current_user.try(:moderator?)
end

#modern_mobile_device?Boolean

Returns:

  • (Boolean)


443
444
445
# File 'app/helpers/application_helper.rb', line 443

def modern_mobile_device?
  MobileDetection.modern_mobile_device?(request.user_agent)
end

#normalized_safe_modeObject



485
486
487
488
489
490
491
492
493
# File 'app/helpers/application_helper.rb', line 485

def normalized_safe_mode
  safe_mode = []

  safe_mode << ApplicationController::NO_THEMES if customization_disabled?
  safe_mode << ApplicationController::NO_PLUGINS if !allow_plugins?
  safe_mode << ApplicationController::NO_UNOFFICIAL_PLUGINS if !allow_third_party_plugins?

  safe_mode.join(",")
end

#preload_script(script) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'app/helpers/application_helper.rb', line 135

def preload_script(script)
  scripts = []

  if chunks = EmberCli.script_chunks[script]
    scripts.push(*chunks)
  else
    scripts.push(script)
  end

  scripts
    .map do |name|
      path = script_asset_path(name)
      preload_script_url(path)
    end
    .join("\n")
    .html_safe
end

#preload_script_url(url) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'app/helpers/application_helper.rb', line 153

def preload_script_url(url)
  add_resource_preload_list(url, "script")
  if GlobalSetting.preload_link_header
    <<~HTML.html_safe
      <script defer src="#{url}"></script>
    HTML
  else
    <<~HTML.html_safe
      <link rel="preload" href="#{url}" as="script">
      <script defer src="#{url}"></script>
    HTML
  end
end

#preloaded_jsonObject



685
686
687
688
# File 'app/helpers/application_helper.rb', line 685

def preloaded_json
  return "{}" if @preloaded.blank?
  @preloaded.transform_values { |value| escape_unicode(value) }.to_json
end


370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'app/helpers/application_helper.rb', line 370

def render_sitelinks_search_tag
  if current_page?("/") || current_page?(Discourse.base_path)
    json = {
      "@context" => "http://schema.org",
      "@type" => "WebSite",
      :url => Discourse.base_url,
      :name => SiteSetting.title,
      :potentialAction => {
        "@type" => "SearchAction",
        :target => "#{Discourse.base_url}/search?q={search_term_string}",
        "query-input" => "required name=search_term_string",
      },
    }
    (:script, MultiJson.dump(json).html_safe, type: "application/ld+json")
  end
end

#replace_plugin_html(name) ⇒ Object

If there is plugin HTML return that, otherwise yield to the template



574
575
576
577
578
579
580
581
# File 'app/helpers/application_helper.rb', line 574

def replace_plugin_html(name)
  if (html = build_plugin_html(name)).present?
    html
  else
    yield
    nil
  end
end

#rss_creator(user) ⇒ Object



754
755
756
# File 'app/helpers/application_helper.rb', line 754

def rss_creator(user)
  user&.display_name
end

#rtl?Boolean

Returns:

  • (Boolean)


267
268
269
# File 'app/helpers/application_helper.rb', line 267

def rtl?
  %w[ar ur fa_IR he].include? I18n.locale.to_s
end

#scheme_idObject



546
547
548
549
550
551
552
553
554
555
556
557
# File 'app/helpers/application_helper.rb', line 546

def scheme_id
  return @scheme_id if defined?(@scheme_id)

  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

  return if theme_id.blank?

  @scheme_id = Theme.where(id: theme_id).pick(:color_scheme_id)
end

#script_asset_path(script) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'app/helpers/application_helper.rb', line 92

def script_asset_path(script)
  path = ActionController::Base.helpers.asset_path("#{script}.js")

  if GlobalSetting.use_s3? && GlobalSetting.s3_cdn_url
    resolved_s3_asset_cdn_url =
      GlobalSetting.s3_asset_cdn_url.presence || GlobalSetting.s3_cdn_url
    if GlobalSetting.cdn_url
      folder = ActionController::Base.config.relative_url_root || "/"
      path =
        path.gsub(
          File.join(GlobalSetting.cdn_url, folder, "/"),
          File.join(resolved_s3_asset_cdn_url, "/"),
        )
    else
      # 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

      path = "#{resolved_s3_asset_cdn_url}#{path}"
    end

    # 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?
        path = path.gsub(/\.([^.]+)\z/, '.br.\1')
      elsif is_gzip_req?
        path = path.gsub(/\.([^.]+)\z/, '.gz.\1')
      end
    end
  elsif GlobalSetting.cdn_url&.start_with?("https") && is_brotli_req? &&
        Rails.env != "development"
    path = path.gsub("#{GlobalSetting.cdn_url}/assets/", "#{GlobalSetting.cdn_url}/brotli_asset/")
  end

  path
end

#server_plugin_outlet(name, locals: {}) ⇒ Object



510
511
512
513
514
515
516
517
518
519
520
# File 'app/helpers/application_helper.rb', line 510

def server_plugin_outlet(name, locals: {})
  return "" if !GlobalSetting.load_plugins?

  matcher = Regexp.new("/connectors/#{name}/.*\.html\.erb$")
  erbs = ApplicationHelper.all_connectors.select { |c| c =~ matcher }
  return "" if erbs.blank?

  result = +""
  erbs.each { |erb| result << render(inline: File.read(erb), locals: locals) }
  result.html_safe
end

#shared_session_keyObject



73
74
75
76
77
78
79
80
81
82
# File 'app/helpers/application_helper.rb', line 73

def shared_session_key
  if SiteSetting.long_polling_base_url != "/" && current_user
    sk = "shared_session_key"
    return request.env[sk] if request.env[sk]

    request.env[sk] = key = (session[sk] ||= SecureRandom.hex)
    Discourse.redis.setex "#{sk}_#{key}", 7.days, current_user.id.to_s
    key
  end
end

#short_date(dt) ⇒ Object



243
244
245
246
247
248
249
# File 'app/helpers/application_helper.rb', line 243

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

#staff?Boolean

Returns:

  • (Boolean)


263
264
265
# File 'app/helpers/application_helper.rb', line 263

def staff?
  current_user.try(:staff?)
end

#stylesheet_managerObject



541
542
543
544
# File 'app/helpers/application_helper.rb', line 541

def stylesheet_manager
  return @stylesheet_manager if defined?(@stylesheet_manager)
  @stylesheet_manager = Stylesheet::Manager.new(theme_id: theme_id)
end

#text_size_classObject



204
205
206
207
208
209
210
211
212
213
214
# File 'app/helpers/application_helper.rb', line 204

def text_size_class
  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

  size = cookie_size || current_user&.user_option&.text_size || SiteSetting.default_text_size
  "text-size-#{size}"
end

#theme_idObject



533
534
535
536
537
538
539
# File 'app/helpers/application_helper.rb', line 533

def theme_id
  if customization_disabled?
    nil
  else
    request.env[:resolved_theme_id]
  end
end

#theme_js_lookupObject



601
602
603
604
605
606
607
608
# File 'app/helpers/application_helper.rb', line 601

def theme_js_lookup
  Theme.lookup_field(
    theme_id,
    :extra_js,
    nil,
    skip_transformation: request.env[:skip_theme_ids_transformation].present?,
  )
end

#theme_lookup(name) ⇒ Object



583
584
585
586
587
588
589
590
# File 'app/helpers/application_helper.rb', line 583

def theme_lookup(name)
  Theme.lookup_field(
    theme_id,
    mobile_view? ? :mobile : :desktop,
    name,
    skip_transformation: request.env[:skip_theme_ids_transformation].present?,
  )
end

#theme_translations_lookupObject



592
593
594
595
596
597
598
599
# File 'app/helpers/application_helper.rb', line 592

def theme_translations_lookup
  Theme.lookup_field(
    theme_id,
    :translations,
    I18n.locale,
    skip_transformation: request.env[:skip_theme_ids_transformation].present?,
  )
end


522
523
524
525
526
527
528
529
530
531
# File 'app/helpers/application_helper.rb', line 522

def topic_featured_link_domain(link)
  begin
    uri = UrlHelper.encode_and_parse(link)
    uri = URI.parse("http://#{uri}") if uri.scheme.nil?
    host = uri.host.downcase
    host.start_with?("www.") ? host[4..-1] : host
  rescue StandardError
    ""
  end
end

#waving_hand_urlObject



423
424
425
# File 'app/helpers/application_helper.rb', line 423

def waving_hand_url
  UrlHelper.cook_url(Emoji.url_for(":wave:t#{rand(2..6)}:"))
end

#with_format(format, &block) ⇒ Object



231
232
233
234
235
236
237
# File 'app/helpers/application_helper.rb', line 231

def with_format(format, &block)
  old_formats = formats
  self.formats = [format]
  block.call
  self.formats = old_formats
  nil
end