discourse/lib/discourse_plugin_registry.rb

232 lines
7.1 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
2013-02-05 13:16:51 -06:00
#
# A class that handles interaction between a plugin and the Discourse App.
#
class DiscoursePluginRegistry
# Shortcut to create new register in the plugin registry
# - Register is created in a class variable using the specified name/type
# - Defines singleton method to access the register
# - Defines instance method as a shortcut to the singleton method
# - Automatically deletes the register on ::clear!
def self.define_register(register_name, type)
@@register_names ||= Set.new
@@register_names << register_name
define_singleton_method(register_name) do
instance_variable_get(:"@#{register_name}") ||
instance_variable_set(:"@#{register_name}", type.new)
end
define_method(register_name) do
self.class.public_send(register_name)
end
end
# Create a new register (see `define_register`) with some additions:
# - Register is created in a class variable using the specified name/type
# - Defines singleton method to access the register
# - Defines instance method as a shortcut to the singleton method
# - Automatically deletes the register on ::clear!
def self.define_filtered_register(register_name)
define_register(register_name, Array)
singleton_class.alias_method :"_raw_#{register_name}", :"#{register_name}"
define_singleton_method(register_name) do
unfiltered = public_send(:"_raw_#{register_name}")
unfiltered
.filter { |v| v[:plugin].enabled? }
.map { |v| v[:value] }
.uniq
end
define_singleton_method("register_#{register_name.to_s.singularize}") do |value, plugin|
public_send(:"_raw_#{register_name}") << { plugin: plugin, value: value }
end
end
define_register :javascripts, Set
define_register :auth_providers, Set
define_register :service_workers, Set
define_register :admin_javascripts, Set
define_register :stylesheets, Hash
define_register :mobile_stylesheets, Hash
define_register :desktop_stylesheets, Hash
define_register :color_definition_stylesheets, Hash
define_register :sass_variables, Set
define_register :handlebars, Set
define_register :serialized_current_user_fields, Set
define_register :seed_data, HashWithIndifferentAccess
define_register :locales, HashWithIndifferentAccess
define_register :svg_icons, Set
define_register :custom_html, Hash
define_register :asset_globs, Set
define_register :html_builders, Hash
define_register :seed_path_builders, Set
define_register :vendored_pretty_text, Set
define_register :vendored_core_pretty_text, Set
define_register :seedfu_filter, Set
define_filtered_register :staff_user_custom_fields
define_filtered_register :public_user_custom_fields
define_filtered_register :self_editable_user_custom_fields
define_filtered_register :staff_editable_user_custom_fields
define_filtered_register :editable_group_custom_fields
define_filtered_register :topic_thumbnail_sizes
define_filtered_register :api_parameter_routes
define_filtered_register :api_key_scope_mappings
define_filtered_register :user_api_key_scope_mappings
define_filtered_register :permitted_bulk_action_parameters
def self.register_auth_provider(auth_provider)
self.auth_providers << auth_provider
end
2017-07-27 20:20:09 -05:00
def register_js(filename, options = {})
2013-02-05 13:16:51 -06:00
# If we have a server side option, add that too.
self.class.javascripts << filename
end
def self.register_service_worker(filename, options = {})
self.service_workers << filename
end
Upgrade to FontAwesome 5 (take two) (#6673) * Add missing icons to set * Revert FA5 revert This reverts commit 42572ff * use new SVG syntax in locales * Noscript page changes (remove login button, center "powered by" footer text) * Cast wider net for SVG icons in settings - include any _icon setting for SVG registry (offers better support for plugin settings) - let themes store multiple pipe-delimited icons in a setting - also replaces broken onebox image icon with SVG reference in cooked post processor * interpolate icons in locales * Fix composer whisper icon alignment * Add support for stacked icons * SECURITY: enforce hostname to match discourse hostname This ensures that the hostname rails uses for various helpers always matches the Discourse hostname * load SVG sprite with pre-initializers * FIX: enable caching on SVG sprites * PERF: use JSONP for SVG sprites so they are served from CDN This avoids needing to deal with CORS for loading of the SVG Note, added the svg- prefix to the filename so we can quickly tell in dev tools what the file is * Add missing SVG sprite JSONP script to CSP * Upgrade to FA 5.5.0 * Add support for all FA4.7 icons - adds complete frontend and backend for renamed FA4.7 icons - improves performance of SvgSprite.bundle and SvgSprite.all_icons * Fix group avatar flair preview - adds an endpoint at /svg-sprites/search/:keyword - adds frontend ajax call that pulls icon in avatar flair preview even when it is not in subset * Remove FA 4.7 font files
2018-11-26 15:49:57 -06:00
def self.register_svg_icon(icon)
self.svg_icons << icon
end
def register_css(filename, plugin_directory_name)
self.class.stylesheets[plugin_directory_name] ||= Set.new
self.class.stylesheets[plugin_directory_name] << filename
2013-02-05 13:16:51 -06:00
end
def self.register_locale(locale, options = {})
self.locales[locale] = options
end
2017-07-27 20:20:09 -05:00
def register_archetype(name, options = {})
2013-02-05 13:16:51 -06:00
Archetype.register(name, options)
end
2017-07-27 20:20:09 -05:00
def self.register_glob(root, extension, options = nil)
self.asset_globs << [root, extension, options || {}]
end
2017-07-27 20:20:09 -05:00
def self.each_globbed_asset(each_options = nil)
each_options ||= {}
self.asset_globs.each do |g|
root, ext, options = *g
if options[:admin]
next unless each_options[:admin]
else
next if each_options[:admin]
2015-08-18 20:24:09 -05:00
end
Dir.glob("#{root}/**/*") do |f|
yield f, ext
end
end
end
JS_REGEX = /\.js$|\.js\.erb$|\.js\.es6$/
HANDLEBARS_REGEX = /\.(hb[rs]|js\.handlebars)$/
def self.register_asset(asset, opts = nil, plugin_directory_name = nil)
if asset =~ JS_REGEX
if opts == :admin
self.admin_javascripts << asset
elsif opts == :vendored_pretty_text
self.vendored_pretty_text << asset
elsif opts == :vendored_core_pretty_text
self.vendored_core_pretty_text << asset
else
self.javascripts << asset
end
elsif asset =~ /\.css$|\.scss$/
if opts == :mobile
self.mobile_stylesheets[plugin_directory_name] ||= Set.new
self.mobile_stylesheets[plugin_directory_name] << asset
elsif opts == :desktop
self.desktop_stylesheets[plugin_directory_name] ||= Set.new
self.desktop_stylesheets[plugin_directory_name] << asset
elsif opts == :color_definitions
self.color_definition_stylesheets[plugin_directory_name] = asset
elsif opts == :variables
self.sass_variables << asset
else
self.stylesheets[plugin_directory_name] ||= Set.new
self.stylesheets[plugin_directory_name] << asset
end
elsif asset =~ HANDLEBARS_REGEX
self.handlebars << asset
end
end
def self.stylesheets_exists?(plugin_directory_name, target = nil)
case target
when :desktop
self.desktop_stylesheets[plugin_directory_name].present?
when :mobile
self.mobile_stylesheets[plugin_directory_name].present?
else
self.stylesheets[plugin_directory_name].present?
end
end
def self.register_seed_data(key, value)
self.seed_data[key] = value
end
def self.register_seed_path_builder(&block)
seed_path_builders << block
end
def self.register_html_builder(name, &block)
html_builders[name] ||= []
html_builders[name] << block
end
2017-07-27 20:20:09 -05:00
def self.build_html(name, ctx = nil)
builders = html_builders[name] || []
builders.map { |b| b.call(ctx) }.join("\n").html_safe
end
def self.seed_paths
result = SeedFu.fixture_paths.dup
unless Rails.env.test? && ENV['LOAD_PLUGINS'] != "1"
seed_path_builders.each { |b| result += b.call }
end
2017-11-16 14:22:05 -06:00
result.uniq
end
def self.register_seedfu_filter(filter = nil)
self.seedfu_filter << filter
end
VENDORED_CORE_PRETTY_TEXT_MAP = {
"moment.js" => "vendor/assets/javascripts/moment.js",
"moment-timezone.js" => "vendor/assets/javascripts/moment-timezone-with-data.js"
}
def self.core_asset_for_name(name)
asset = VENDORED_CORE_PRETTY_TEXT_MAP[name]
raise KeyError, "Asset #{name} not found in #{VENDORED_CORE_PRETTY_TEXT_MAP}" unless asset
asset
end
def self.reset!
@@register_names.each do |name|
instance_variable_set(:"@#{name}", nil)
end
end
2013-02-05 13:16:51 -06:00
end