Feature #43087 » 0001-Allow-to-change-icons-sprite-from-theme-with-a-fallb.patch
| app/helpers/icons_helper.rb | ||
|---|---|---|
| 18 | 18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 19 | 19 | |
| 20 | 20 |
module IconsHelper |
| 21 |
include Redmine::Themes::Helper |
|
| 22 | ||
| 21 | 23 |
DEFAULT_ICON_SIZE = "18" |
| 22 | 24 |
DEFAULT_SPRITE = "icons" |
| 23 | 25 | |
| 26 |
def sprite_source(icon_name, sprite: DEFAULT_SPRITE, plugin: nil) |
|
| 27 |
if plugin |
|
| 28 |
"plugin_assets/#{plugin}/#{sprite}.svg"
|
|
| 29 |
elsif current_theme && current_theme.icons(sprite).include?(icon_name) |
|
| 30 |
current_theme.image_path("#{sprite}.svg")
|
|
| 31 |
else |
|
| 32 |
"#{sprite}.svg"
|
|
| 33 |
end |
|
| 34 |
end |
|
| 35 | ||
| 24 | 36 |
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) |
| 25 |
sprite = plugin ? "plugin_assets/#{plugin}/#{sprite}.svg" : "#{sprite}.svg"
|
|
| 37 |
sprite = sprite_source(icon_name, sprite: sprite, plugin: plugin)
|
|
| 26 | 38 | |
| 27 | 39 |
svg_icon = svg_sprite_icon(icon_name, size: size, style: style, css_class: css_class, sprite: sprite, rtl: rtl) |
| 28 | 40 | |
| lib/redmine/themes.rb | ||
|---|---|---|
| 110 | 110 |
"themes/#{dir}/"
|
| 111 | 111 |
end |
| 112 | 112 | |
| 113 |
# Returns an array of icon names available in the given sprite |
|
| 114 |
def icons(sprite) |
|
| 115 |
asset = Rails.application.assets.load_path.find(image_path("#{sprite}.svg"))
|
|
| 116 | ||
| 117 |
return [] unless asset |
|
| 118 | ||
| 119 |
ActionController::Base.cache_store.fetch("theme-icons/#{id}/#{sprite}/#{asset.digest}") do
|
|
| 120 |
asset.content.scan(/id=['"]icon--([^'"]+)['"]/).flatten |
|
| 121 |
end |
|
| 122 |
end |
|
| 123 | ||
| 113 | 124 |
def asset_paths |
| 114 | 125 |
base_dir = Pathname.new(path) |
| 115 | 126 |
paths = base_dir.children.select do |child| |
| test/helpers/icons_helper_test.rb | ||
|---|---|---|
| 43 | 43 |
assert_match expected, icon |
| 44 | 44 |
end |
| 45 | 45 | |
| 46 |
def test_sprite_source_without_theme_should_return_default_sprite |
|
| 47 |
stubs(:current_theme).returns(nil) |
|
| 48 | ||
| 49 |
assert_equal "icons.svg", sprite_source('edit')
|
|
| 50 |
end |
|
| 51 | ||
| 52 |
def test_sprite_source_with_theme_and_sprite_image_should_return_theme_path_if_icon_exists |
|
| 53 |
theme = Redmine::Themes::Theme.new('/tmp/test')
|
|
| 54 |
theme.stubs(:id).returns('test')
|
|
| 55 |
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
|
| 56 | ||
| 57 |
asset = mock('asset')
|
|
| 58 |
asset.stubs(:digest).returns('123456')
|
|
| 59 |
asset.stubs(:content).returns('<symbol id="icon--edit"></symbol>')
|
|
| 60 |
asset.stubs(:digested_path).returns('themes/test/icons-123456.svg')
|
|
| 61 | ||
| 62 |
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
|
| 63 |
stubs(:current_theme).returns(theme) |
|
| 64 | ||
| 65 |
assert_equal "themes/test/icons.svg", sprite_source('edit')
|
|
| 66 |
end |
|
| 67 | ||
| 68 |
def test_sprite_source_with_theme_without_sprite_image_should_return_default_sprite |
|
| 69 |
theme = Redmine::Themes::Theme.new('/tmp/test')
|
|
| 70 |
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
|
| 71 | ||
| 72 |
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(nil)
|
|
| 73 |
stubs(:current_theme).returns(theme) |
|
| 74 | ||
| 75 |
assert_equal "icons.svg", sprite_source('edit')
|
|
| 76 |
end |
|
| 77 | ||
| 78 |
def test_sprite_source_with_theme_and_sprite_image_but_missing_icon_should_fallback_to_default_sprite |
|
| 79 |
theme = Redmine::Themes::Theme.new('/tmp/test')
|
|
| 80 |
theme.stubs(:id).returns('test')
|
|
| 81 |
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
|
| 82 | ||
| 83 |
asset = mock('asset')
|
|
| 84 |
asset.stubs(:digest).returns('123456')
|
|
| 85 |
asset.stubs(:content).returns('<symbol id="icon--other"></symbol>')
|
|
| 86 |
asset.stubs(:digested_path).returns('themes/test/icons-123456.svg')
|
|
| 87 | ||
| 88 |
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
|
| 89 |
stubs(:current_theme).returns(theme) |
|
| 90 | ||
| 91 |
assert_equal "icons.svg", sprite_source('edit')
|
|
| 92 |
end |
|
| 93 | ||
| 94 |
def test_sprite_icon_with_theme_override_should_use_theme_sprite |
|
| 95 |
theme = Redmine::Themes::Theme.new('/tmp/test')
|
|
| 96 |
theme.stubs(:id).returns('test')
|
|
| 97 |
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
|
| 98 | ||
| 99 |
asset = mock('asset')
|
|
| 100 |
asset.stubs(:digest).returns('123456')
|
|
| 101 |
asset.stubs(:content).returns('<symbol id="icon--edit"></symbol>')
|
|
| 102 |
asset.stubs(:digested_path).returns('themes/test/icons-123456.svg')
|
|
| 103 | ||
| 104 |
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
|
| 105 |
stubs(:current_theme).returns(theme) |
|
| 106 | ||
| 107 |
expected = %r{<svg class="s18 icon-svg" aria-hidden="true"><use href="/assets/themes/test/icons(-123456)?\.svg#icon--edit"></use></svg>$}
|
|
| 108 |
assert_match expected, sprite_icon('edit')
|
|
| 109 |
end |
|
| 110 | ||
| 111 |
def test_sprite_icon_with_theme_missing_icon_should_fallback_to_default_sprite |
|
| 112 |
theme = Redmine::Themes::Theme.new('/tmp/test')
|
|
| 113 |
theme.stubs(:id).returns('test')
|
|
| 114 |
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
|
| 115 | ||
| 116 |
asset = mock('asset')
|
|
| 117 |
asset.stubs(:digest).returns('123456')
|
|
| 118 |
asset.stubs(:content).returns('<symbol id="icon--other"></symbol>')
|
|
| 119 |
asset.stubs(:digested_path).returns('themes/test/icons-123456.svg')
|
|
| 120 | ||
| 121 |
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
|
| 122 | ||
| 123 |
default_asset = mock('asset')
|
|
| 124 |
default_asset.stubs(:digested_path).returns('icons-default.svg')
|
|
| 125 |
Rails.application.assets.load_path.stubs(:find).with('icons.svg').returns(default_asset)
|
|
| 126 | ||
| 127 |
stubs(:current_theme).returns(theme) |
|
| 128 | ||
| 129 |
expected = %r{<svg class="s18 icon-svg" aria-hidden="true"><use href="/assets/icons(-\w+)?\.svg#icon--edit"></use></svg>$}
|
|
| 130 |
assert_match expected, sprite_icon('edit')
|
|
| 131 |
end |
|
| 132 | ||
| 46 | 133 |
def test_sprite_icon_should_return_svg_with_custom_size |
| 47 | 134 |
expected = %r{<svg class="s24 icon-svg" aria-hidden="true"><use href="/assets/icons-\w+.svg#icon--edit"></use></svg>$}
|
| 48 | 135 |
icon = sprite_icon('edit', size: '24')
|
| test/unit/lib/redmine/themes_test.rb | ||
|---|---|---|
| 59 | 59 |
ensure |
| 60 | 60 |
Redmine::Themes.rescan |
| 61 | 61 |
end |
| 62 | ||
| 63 |
def test_icons_should_return_available_icons |
|
| 64 |
theme = Redmine::Themes::Theme.new('/tmp/test')
|
|
| 65 |
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
|
| 66 | ||
| 67 |
asset = mock('asset')
|
|
| 68 |
asset.stubs(:content).returns('<svg><symbol id="icon--edit"></symbol><symbol id=\'icon--delete\'></symbol></svg>')
|
|
| 69 |
asset.stubs(:digest).returns('123456')
|
|
| 70 | ||
| 71 |
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
|
| 72 | ||
| 73 |
assert_equal ['edit', 'delete'], theme.icons('icons')
|
|
| 74 |
end |
|
| 75 | ||
| 76 |
def test_icons_should_return_empty_array_if_asset_missing |
|
| 77 |
theme = Redmine::Themes::Theme.new('/tmp/test')
|
|
| 78 |
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
|
| 79 | ||
| 80 |
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(nil)
|
|
| 81 | ||
| 82 |
assert_equal [], theme.icons('icons')
|
|
| 83 |
end |
|
| 84 | ||
| 85 |
def test_icons_should_be_cached |
|
| 86 |
theme = Redmine::Themes::Theme.new('/tmp/test')
|
|
| 87 |
theme.stubs(:id).returns('test')
|
|
| 88 |
theme.stubs(:image_path).with('icons.svg').returns('themes/test/icons.svg')
|
|
| 89 | ||
| 90 |
asset = mock('asset')
|
|
| 91 |
asset.stubs(:content).returns('<symbol id="icon--edit"></symbol>')
|
|
| 92 |
asset.stubs(:digest).returns('123456')
|
|
| 93 | ||
| 94 |
Rails.application.assets.load_path.stubs(:find).with('themes/test/icons.svg').returns(asset)
|
|
| 95 | ||
| 96 |
# Use a memory store for this test since the test environment uses null_store |
|
| 97 |
memory_store = ActiveSupport::Cache.lookup_store(:memory_store) |
|
| 98 |
ActionController::Base.stubs(:cache_store).returns(memory_store) |
|
| 99 | ||
| 100 |
# First call - cache miss |
|
| 101 |
assert_equal ['edit'], theme.icons('icons')
|
|
| 102 | ||
| 103 |
# Second call - verify it's in the cache |
|
| 104 |
cache_key = "theme-icons/test/icons/123456" |
|
| 105 |
assert_equal ['edit'], memory_store.read(cache_key) |
|
| 106 | ||
| 107 |
# If digest changes, it should miss cache |
|
| 108 |
asset.stubs(:digest).returns('789')
|
|
| 109 |
asset.stubs(:content).returns('<symbol id="icon--new"></symbol>')
|
|
| 110 |
assert_equal ['new'], theme.icons('icons')
|
|
| 111 |
end |
|
| 62 | 112 |
end |
- « Previous
- 1
- 2
- 3
- 4
- Next »