mirror of
https://github.com/redmine/redmine.git
synced 2026-02-23 07:01:18 +01:00
Allow themes to change default icons sprite (#43087):
* name of the sprite must be icons.svg. * if the icon doesn't exist in the theme sprite, it will fallback to default icon. git-svn-id: https://svn.redmine.org/redmine/trunk@24449 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -18,11 +18,23 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
module IconsHelper
|
||||
include Redmine::Themes::Helper
|
||||
|
||||
DEFAULT_ICON_SIZE = "18"
|
||||
DEFAULT_SPRITE = "icons"
|
||||
|
||||
def sprite_source(icon_name, sprite: DEFAULT_SPRITE, plugin: nil)
|
||||
if plugin
|
||||
"plugin_assets/#{plugin}/#{sprite}.svg"
|
||||
elsif current_theme && current_theme.icons(sprite).include?(icon_name)
|
||||
current_theme.image_path("#{sprite}.svg")
|
||||
else
|
||||
"#{sprite}.svg"
|
||||
end
|
||||
end
|
||||
|
||||
def sprite_icon(icon_name, label = nil, icon_only: false, size: DEFAULT_ICON_SIZE, style: :outline, css_class: nil, sprite: DEFAULT_SPRITE, plugin: nil, rtl: false)
|
||||
sprite = plugin ? "plugin_assets/#{plugin}/#{sprite}.svg" : "#{sprite}.svg"
|
||||
sprite = sprite_source(icon_name, sprite: sprite, plugin: plugin)
|
||||
|
||||
svg_icon = svg_sprite_icon(icon_name, size: size, style: style, css_class: css_class, sprite: sprite, rtl: rtl)
|
||||
|
||||
|
||||
@@ -110,6 +110,17 @@ module Redmine
|
||||
"themes/#{dir}/"
|
||||
end
|
||||
|
||||
# Returns an array of icon names available in the given sprite
|
||||
def icons(sprite)
|
||||
asset = Rails.application.assets.load_path.find(image_path("#{sprite}.svg"))
|
||||
|
||||
return [] unless asset
|
||||
|
||||
ActionController::Base.cache_store.fetch("theme-icons/#{id}/#{sprite}/#{asset.digest}") do
|
||||
asset.content.scan(/id=['"]icon--([^'"]+)['"]/).flatten
|
||||
end
|
||||
end
|
||||
|
||||
def asset_paths
|
||||
base_dir = Pathname.new(path)
|
||||
paths = base_dir.children.select do |child|
|
||||
|
||||
@@ -43,6 +43,93 @@ class IconsHelperTest < Redmine::HelperTest
|
||||
assert_match expected, icon
|
||||
end
|
||||
|
||||
def test_sprite_source_without_theme_should_return_default_sprite
|
||||
stubs(:current_theme).returns(nil)
|
||||
|
||||
assert_equal "icons.svg", sprite_source('edit')
|
||||
end
|
||||
|
||||
def test_sprite_source_with_theme_and_sprite_image_should_return_theme_path_if_icon_exists
|
||||
theme = Redmine::Themes::Theme.new('/tmp/test')
|
||||
theme.stubs(:id).returns('test')
|
||||
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
||||
|
||||
asset = mock('asset')
|
||||
asset.stubs(:digest).returns('123456')
|
||||
asset.stubs(:content).returns('<symbol id="icon--edit"></symbol>')
|
||||
asset.stubs(:digested_path).returns('themes/test/icons-123456.svg')
|
||||
|
||||
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
||||
stubs(:current_theme).returns(theme)
|
||||
|
||||
assert_equal "themes/test/icons.svg", sprite_source('edit')
|
||||
end
|
||||
|
||||
def test_sprite_source_with_theme_without_sprite_image_should_return_default_sprite
|
||||
theme = Redmine::Themes::Theme.new('/tmp/test')
|
||||
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
||||
|
||||
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(nil)
|
||||
stubs(:current_theme).returns(theme)
|
||||
|
||||
assert_equal "icons.svg", sprite_source('edit')
|
||||
end
|
||||
|
||||
def test_sprite_source_with_theme_and_sprite_image_but_missing_icon_should_fallback_to_default_sprite
|
||||
theme = Redmine::Themes::Theme.new('/tmp/test')
|
||||
theme.stubs(:id).returns('test')
|
||||
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
||||
|
||||
asset = mock('asset')
|
||||
asset.stubs(:digest).returns('123456')
|
||||
asset.stubs(:content).returns('<symbol id="icon--other"></symbol>')
|
||||
asset.stubs(:digested_path).returns('themes/test/icons-123456.svg')
|
||||
|
||||
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
||||
stubs(:current_theme).returns(theme)
|
||||
|
||||
assert_equal "icons.svg", sprite_source('edit')
|
||||
end
|
||||
|
||||
def test_sprite_icon_with_theme_override_should_use_theme_sprite
|
||||
theme = Redmine::Themes::Theme.new('/tmp/test')
|
||||
theme.stubs(:id).returns('test')
|
||||
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
||||
|
||||
asset = mock('asset')
|
||||
asset.stubs(:digest).returns('123456')
|
||||
asset.stubs(:content).returns('<symbol id="icon--edit"></symbol>')
|
||||
asset.stubs(:digested_path).returns('themes/test/icons-123456.svg')
|
||||
|
||||
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
||||
stubs(:current_theme).returns(theme)
|
||||
|
||||
expected = %r{<svg class="s18 icon-svg" aria-hidden="true"><use href="/assets/themes/test/icons(-123456)?\.svg#icon--edit"></use></svg>$}
|
||||
assert_match expected, sprite_icon('edit')
|
||||
end
|
||||
|
||||
def test_sprite_icon_with_theme_missing_icon_should_fallback_to_default_sprite
|
||||
theme = Redmine::Themes::Theme.new('/tmp/test')
|
||||
theme.stubs(:id).returns('test')
|
||||
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
||||
|
||||
asset = mock('asset')
|
||||
asset.stubs(:digest).returns('123456')
|
||||
asset.stubs(:content).returns('<symbol id="icon--other"></symbol>')
|
||||
asset.stubs(:digested_path).returns('themes/test/icons-123456.svg')
|
||||
|
||||
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
||||
|
||||
default_asset = mock('asset')
|
||||
default_asset.stubs(:digested_path).returns('icons-default.svg')
|
||||
Rails.application.assets.load_path.stubs(:find).with('icons.svg').returns(default_asset)
|
||||
|
||||
stubs(:current_theme).returns(theme)
|
||||
|
||||
expected = %r{<svg class="s18 icon-svg" aria-hidden="true"><use href="/assets/icons(-\w+)?\.svg#icon--edit"></use></svg>$}
|
||||
assert_match expected, sprite_icon('edit')
|
||||
end
|
||||
|
||||
def test_sprite_icon_should_return_svg_with_custom_size
|
||||
expected = %r{<svg class="s24 icon-svg" aria-hidden="true"><use href="/assets/icons-\w+.svg#icon--edit"></use></svg>$}
|
||||
icon = sprite_icon('edit', size: '24')
|
||||
|
||||
@@ -59,4 +59,54 @@ class Redmine::ThemesTest < ActiveSupport::TestCase
|
||||
ensure
|
||||
Redmine::Themes.rescan
|
||||
end
|
||||
|
||||
def test_icons_should_return_available_icons
|
||||
theme = Redmine::Themes::Theme.new('/tmp/test')
|
||||
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
||||
|
||||
asset = mock('asset')
|
||||
asset.stubs(:content).returns('<svg><symbol id="icon--edit"></symbol><symbol id=\'icon--delete\'></symbol></svg>')
|
||||
asset.stubs(:digest).returns('123456')
|
||||
|
||||
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
||||
|
||||
assert_equal ['edit', 'delete'], theme.icons('icons')
|
||||
end
|
||||
|
||||
def test_icons_should_return_empty_array_if_asset_missing
|
||||
theme = Redmine::Themes::Theme.new('/tmp/test')
|
||||
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
||||
|
||||
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(nil)
|
||||
|
||||
assert_equal [], theme.icons('icons')
|
||||
end
|
||||
|
||||
def test_icons_should_be_cached
|
||||
theme = Redmine::Themes::Theme.new('/tmp/test')
|
||||
theme.stubs(:id).returns('test')
|
||||
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
||||
|
||||
asset = mock('asset')
|
||||
asset.stubs(:content).returns('<symbol id="icon--edit"></symbol>')
|
||||
asset.stubs(:digest).returns('123456')
|
||||
|
||||
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
||||
|
||||
# Use a memory store for this test since the test environment uses null_store
|
||||
memory_store = ActiveSupport::Cache.lookup_store(:memory_store)
|
||||
ActionController::Base.stubs(:cache_store).returns(memory_store)
|
||||
|
||||
# First call - cache miss
|
||||
assert_equal ['edit'], theme.icons('icons')
|
||||
|
||||
# Second call - verify it's in the cache
|
||||
cache_key = "theme-icons/test/icons/123456"
|
||||
assert_equal ['edit'], memory_store.read(cache_key)
|
||||
|
||||
# If digest changes, it should miss cache
|
||||
asset.stubs(:digest).returns('789')
|
||||
asset.stubs(:content).returns('<symbol id="icon--new"></symbol>')
|
||||
assert_equal ['new'], theme.icons('icons')
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user