Skip to content

Dropdown menu items still render icons the old way — every menu icon is blank (all editors) #313

Description

@cerede2000

Summary

Toolbar icons render fine here, which I assume is the result of the #199 fix. Menu
icons do not: every dropdown menu item that declares an icon shows an empty 20×20
box where the icon should be. Captions, shortcuts and behaviour are all correct.

Common.UI.Button was migrated to the SVG symbol sprite, but Common.UI.MenuItem
was not. It still emits the old CSS-sprite <span>, and the PNG sprites that
mechanism needs (iconssmall*.png, iconsbig*.png, iconshuge*.png) are no longer
generated or shipped, so nothing paints.

This is unchanged in v9.3.3: apps/common/main/lib/component/Menu.js is identical
between the web-apps submodule of v9.3.1 (7c69898) and of v9.3.3 (91f0f97).

Where

apps/common/main/lib/component/Menu.js:846-848, in MenuItem.itemTemplate:

'<% if (typeof iconCls !== "undefined") { %>',
    '<span class="menu-item-icon <%= iconCls %>"></span>',
'<% } %>',

apps/common/main/lib/component/Button.js:176-187, which was migrated:

// SVG sprite approach - uses <svg><use href="#id"> for dark mode support
// Sprite is injected into DOM via svg-injector, so we use fragment-only references
var templateBtnIcon =
        '<% if ( iconImg ) { %>' +
            '<img src="<%= iconImg %>">' +
        '<% } else { %>' +
            '<% var iconMatch = /btn-[^\\s]+/.exec(iconCls); ' +
            'if (iconMatch) {' +
                'print(\'<svg class=\"icon uni-scale\"><use href=\"#\' + iconMatch[0] + \'\"></use></svg>\');' +
            '} else ' +
                'print(\'<i class=\"icon \' + iconCls + \'\">&nbsp;</i>\'); %>' +
        '<% } %>';

The only rule matching the markup MenuItem emits is geometry — there is no image
anywhere in the chain:

.dropdown-menu li .menu-item-icon {
  display: inline-block; float: left;
  width: var(--x-small-btn-icon-size, 20px);
  height: var(--x-small-btn-icon-size, 20px);
  margin: calc((16px - var(--x-small-btn-icon-size, 20px)) / 2) 4px 0 -16px;
  background-repeat: no-repeat;
  opacity: var(--component-normal-icon-opacity, 0.8);
}

The background-image / background-position for each icon class used to come from
apps/<editor>/main/resources/less/sprites/*.less. Those files no longer exist and
their @imports are commented out in every app.less. Grepping the built app.css
for .btn-* selectors returns 55 hits, all of them component classes
(.btn-default, .btn-danger, .btn-toolbar, …) — no icon classes at all.

Impact

Menu items declaring an icon, counted on v9.3.3 sources:

editor items
documenteditor 315
presentationeditor 298
pdfeditor 266
spreadsheeteditor 194
visioeditor 19
total 1092

Where it shows most, in the document editor:

  • app/view/DocumentHolderExt.js — 273 (right-click context menu and its submenus)
  • app/view/FileMenu.js — 21 (File menu)
  • app/view/Toolbar.js — 13 (toolbar dropdowns)

The sprite already contains what is needed

The 91 distinct icons requested by the document editor's menus are all present as
<symbol id="btn-…"> in the shipped
apps/documenteditor/main/resources/img/toolbar/icons.svg. So no artwork is missing
— only the template needs to emit <use>.

Aligning MenuItem.itemTemplate with the button approach should be enough:

'<% if (typeof iconCls !== "undefined") { %>',
    '<% var iconMatch = /btn-[^\\s]+/.exec(iconCls); %>',
    '<% if (iconMatch) { %>',
        '<svg class="menu-item-icon icon"><use href="#<%= iconMatch[0] %>"></use></svg>',
    '<% } else { %>',
        '<span class="menu-item-icon <%= iconCls %>"></span>',
    '<% } %>',
'<% } %>',

.dropdown-menu li .menu-item-icon then needs fill: currentColor so the symbols
follow the theme colour, the way .svg-icon does in icons-svg.less.

One related spot to check while fixing: Menu.js:1054, in setChecked(), still
clears the icon with itemEl.css('background-image', 'none'). That assumes the icon
is a CSS background, so it will need the same treatment once menu icons become
<svg><use>.

Smaller findings in the same area

  1. apps/common/main/lib/util/themeinit.js:107 requests three sprite files the build
    never produces — iconssmall@2.5x.svg, iconsbig@2.5x.svg, iconshuge@2.5x.svg.
    build/scripts/deploy-sprites.js only emits toolbar/icons.svg per editor plus
    doc-formats/formats@2.5x.svg. That is three 404s on every editor load, and any
    path relying on apply_icons_from_url() to re-inject icons (theme switch, custom
    themes with their own icons.basepath) gets nothing back.

  2. apps/common/main/resources/less/colors-table.less:205-224 still defines 15
    --sprite-button-{small,big,huge}-{100,125,150,175,200} variables pointing at
    iconssmall*.png / iconsbig*.png / iconshuge*.png, none of which exist any
    more. Nothing consumes them in the built CSS, so they are harmless, but they are
    what sends you chasing missing PNGs when tracing this.

  3. btn-find-redacted is referenced by the document editor but has no symbol in
    icons.svg.

  4. apps/common/main/resources/img/plugin/icon_add_on_default@1.5x.png → 404, while
    the 1x and 2x variants ship. Default plugin icon is blank on 1.5x displays.

  5. apps/common/main/resources/img/doc-formats/large/hwp.svg and hwpx.svg → 404,
    both referenced by the format-list CSS.

Environment

  • ghcr.io/euro-office/documentserver, amd64, served resources report 9.3.3
  • Behind Traefik, TLS terminated at the proxy
  • Integrated through a small self-hosted file manager (JWT + callback), not Nextcloud
  • All 404s above verified over HTTP against the running instance; code references
    checked against the v9.3.3 sources (web-apps 91f0f97)
Image Image Image

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingbuildBuild process related changes

Type

Projects

Status
📄 To do

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions