Icons 

This extension ships the icons the academic extensions share: the actions of a control, the states a control shows, and the glyphs in front of a piece of information such as a phone number or an address. An icon that means the same in several extensions exists once, here, so a site package that replaces it replaces it everywhere.

They are frontend icons. They are registered in the frontend icon registry of this extension, in its Configuration/FrontendIcons.php, and the templates of the academic extensions render them with the view helper ab:icon, see Frontend icons. The backend does not show them, and the icon registry of TYPO3 does not know them.

Every icon is a Font Awesome Free icon of the solid style, drawn in currentColor and registered with \FGTCLB\AcademicBase\Imaging\IconProvider\CurrentColorSvgIconProvider (see Icons that follow the text colour). It therefore takes the colour of the text around it, and it sizes itself by the font size: every file carries width="1em" and height="1em".

Identifiers and files 

The identifiers follow tx-<extension key without underscores>-<group>-<name>, the files Resources/Public/Icons/<group>/<name>.svg. This extension uses three groups:

  • action, something a control does,
  • state, a state a control shows,
  • info, the glyph in front of a piece of information.

The other academic extensions name their icons the same way. The group decides the registry: an action, state or info icon is a frontend icon, registered in Configuration/FrontendIcons.php, and a record, plugin or doktype icon, the icon of a record type, a content element or a page type, is a backend icon, registered in Configuration/Icons.php. The icons of category types and category groups are the exception: their identifiers are derived by EXT:category_types from the Configuration/CategoryTypes.yaml that declares them, and they reach both registries. Their files live in the directories category-type/ and category-group/, or are files of this set.

The tables below give the file relative to EXT:academic_base/Resources/Public/Icons/ and the name of the icon in Font Awesome.

Actions 

Identifier Meaning File Font Awesome
tx-academicbase-action-add Add an item action/add.svg plus
tx-academicbase-action-back Go back action/back.svg arrow-left
tx-academicbase-action-clear Clear a field action/clear.svg eraser
tx-academicbase-action-close Close or dismiss action/close.svg xmark
tx-academicbase-action-collapse Collapse a section action/collapse.svg minus
tx-academicbase-action-delete Delete an item action/delete.svg trash-can
tx-academicbase-action-drag Drag-and-drop handle action/drag.svg grip-lines
tx-academicbase-action-edit Edit action/edit.svg pen
tx-academicbase-action-expand Expand a section action/expand.svg plus
tx-academicbase-action-help Show or hide a help text action/help.svg circle-question
tx-academicbase-action-move-down Move one position down action/move-down.svg arrow-down
tx-academicbase-action-move-up Move one position up action/move-up.svg arrow-up
tx-academicbase-action-save Save action/save.svg floppy-disk
tx-academicbase-action-undo Undo or reset action/undo.svg rotate-left
tx-academicbase-action-upload-image Upload or replace an image action/upload-image.svg camera
tx-academicbase-action-view Show a preview action/view.svg eye
tx-academicbase-action-view-close Close the preview action/view-close.svg eye-slash

States 

Identifier Meaning File Font Awesome
tx-academicbase-state-hidden Item is hidden (switch off) state/hidden.svg toggle-off
tx-academicbase-state-visible Item is visible (switch on) state/visible.svg toggle-on

Information 

Identifier Meaning File Font Awesome
tx-academicbase-info-calendar Date info/calendar.svg calendar-days
tx-academicbase-info-company Company or institution info/company.svg building
tx-academicbase-info-contract Contract info/contract.svg file-contract
tx-academicbase-info-degree Degree info/degree.svg graduation-cap
tx-academicbase-info-department Department or faculty info/department.svg building-columns
tx-academicbase-info-email E-mail info/email.svg envelope
tx-academicbase-info-employment Employment or job info/employment.svg briefcase
tx-academicbase-info-information Additional information info/information.svg circle-info
tx-academicbase-info-international International info/international.svg earth-europe
tx-academicbase-info-link Link info/link.svg link
tx-academicbase-info-location Location or address info/location.svg location-dot
tx-academicbase-info-partnership Partnership or cooperation info/partnership.svg handshake
tx-academicbase-info-person Person, a contact info/person.svg user
tx-academicbase-info-phone Phone info/phone.svg phone
tx-academicbase-info-recommendation Recommendation info/recommendation.svg star
tx-academicbase-info-role Role info/role.svg user-tag
tx-academicbase-info-room Room info/room.svg door-open
tx-academicbase-info-sector Sector or industry info/sector.svg industry
tx-academicbase-info-time Time, office hours info/time.svg clock

expand and add are the same drawing in two files, so a site package can replace one without the other.

Five of the nineteen information identifiers are rendered by a template of the academic extensions: -info-email, -info-phone, -info-location, -info-room and -info-time. The other fourteen stay registered on purpose, so a site package can render and replace them like the others. The job views render identifiers of academic_jobs that draw the same files, and several files are also the drawings of record and category type icons, which other academic extensions register under identifiers of their own. A replacement of one of the fourteen therefore changes neither the job views nor those record and category type icons.

Rendering an icon 

In a Fluid template of the frontend, with the view helper of this extension:

EXT:my_sitepackage/Resources/Private/Partials/Contact.html
<html xmlns:ab="http://typo3.org/ns/FGTCLB/AcademicBase/ViewHelpers"
      data-namespace-typo3-fluid="true">

<ab:icon identifier="tx-academicbase-info-phone" alternativeMarkupIdentifier="inline" />

</html>
Copied!

The markup is the inlined file with or without alternativeMarkupIdentifier="inline", because the provider inlines both markups. The argument keeps the icon inlined where a site package replaces it with the core \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider , which inlines the file only when it is asked to.

The rendered icon carries the CSS class icon-<identifier>, for example icon-tx-academicbase-info-phone, and the attribute data-identifier. A stylesheet can address it through either. <core:icon> does not render these icons: it reads the icon registry of TYPO3 and shows its not-found icon for them.

Replacing an icon in a site package 

Register the same identifier again in Configuration/FrontendIcons.php of the site package. The later registration wins, and every template of every academic extension that renders the identifier shows the replacement:

EXT:my_sitepackage/Configuration/FrontendIcons.php
return [
    'tx-academicbase-info-phone' => [
        'provider' => \FGTCLB\AcademicBase\Imaging\IconProvider\CurrentColorSvgIconProvider::class,
        'source' => 'EXT:my_sitepackage/Resources/Public/Icons/phone.svg',
    ],
];
Copied!
  • The site package has to load after this extension: it requires fgtclb/academic-base , or an academic extension, which requires it, in its composer.json, and in classic mode names it under depends in its ext_emconf.php as well. The files are read in the loading order of the packages, and without the dependency the site package may be read first and lose.
  • The entry replaces the whole registration, provider and source alike.
  • Keep the replacement drawable for inlining if it stays with CurrentColorSvgIconProvider : a viewBox, currentColor, no id and no <style>, see What the SVG file must look like.
  • Flush the system caches afterwards.

An entry in Configuration/Icons.php changes nothing in the frontend, the frontend registry does not read that file. The record, content element and page type icons of the academic extensions are the other way round: they are backend icons, and a site package replaces them in its Configuration/Icons.php.

Icons in frontend JavaScript 

The backend JavaScript icon API of TYPO3 cannot be used on a frontend page: it asks a backend route that answers a logged-in backend user only, and it serves the icon registry of TYPO3. Frontend JavaScript therefore takes the markup of an icon of the frontend icon registry from the server.

Where the JavaScript stamps out a piece of markup anyway, a list item or a row with its buttons, render the icon with ab:icon into a <template> element and clone it. Where it picks an icon by its identifier at runtime, hand it the icons it may need as a JSON map:

<html xmlns:ab="http://typo3.org/ns/FGTCLB/AcademicBase/ViewHelpers"
      data-namespace-typo3-fluid="true">

<ab:frontendIconMap identifiers="{0: 'tx-academicbase-action-add', 1: 'tx-academicbase-action-delete'}" />
Copied!

This renders a JSON data block that the browser neither executes nor checks against the Content Security Policy:

Shortened
<script type="application/json" data-academic-icons data-academic-icons-size="small">{"tx-academicbase-action-add":"\u003Cspan class=\u0022t3js-icon icon icon-size-small ...\u0022 ...\u003E...\u003C/span\u003E","tx-academicbase-action-delete":"..."}</script>
Copied!

Each value is the markup <ab:icon identifier="..." alternativeMarkupIdentifier="inline" /> renders, so the replacement of an icon in a site package arrives in the JavaScript as it does in a template. The JSON escapes <, >, & and both quotes as unicode escapes, so no markup can end the element, and JSON.parse() returns the plain markup.

Arguments:

identifiers (array, required)
The identifiers to render. One that is not served is left out of the map, see below.
size (string, default small)
default, small, medium, large or mega. It sets the icon-size-* class of the markup. The icons of the academic extensions size themselves by the font size.
endpoint (bool, default false)
Adds data-academic-icons-url and data-academic-icons-version to the element: the icon endpoint of the current site language and the version token of the served icons. Outside a site both are left out.

The icon endpoint 

Where the JavaScript learns an identifier only after the page was rendered, from data it loads or from a choice of the visitor, it asks the icon endpoint of the site:

GET https://example.com/_academic/icons.json?i=tx-academicbase-action-add,tx-academicbase-info-phone&s=small&v=<token>
Copied!

The answer is a JSON object in the same shape as the JSON map, for the identifiers that are served, in the order asked for. The endpoint is available below the base of every site and site language, for example https://example.com/de/_academic/icons.json. Its path, its parameters, its answer and its caching are public API like the rest of this section.

i (required)
Up to 32 icon identifiers, separated by commas.
s (optional, default small)
default, small, medium, large or mega.
v (optional)
The version token of the served icons, as data-academic-icons-version of the JSON map carries it. With the current token the answer may be cached for a year (Cache-Control: public, max-age=31536000, immutable), otherwise for five minutes. The answer carries an ETag and answers a matching If-None-Match with 304 Not Modified. The ETag only helps the five-minute answers, an immutable one is never revalidated.

A malformed identifier, more than 32 of them or an unknown size are answered with 400 Bad Request, any method other than GET and HEAD with 405 Method Not Allowed. The endpoint answers before the frontend user authentication: it never starts a session and never sets a cookie, so a proxy or a CDN can cache it like a file. A site in maintenance mode answers it with 503, like every page.

The token covers what decides the markup of a served icon:

  • the identifiers the frontend icon registry serves and their registrations, so a site package that replaces an icon changes it once the system caches are flushed,
  • the modification time of each source file,
  • the modification time of the class files of each provider and of the classes it extends, so a provider changed in place changes it as well,
  • TYPO3's package dependent cache identifier: the TYPO3 version, the project path and, in composer mode, the content of composer.lock.

A deployment that writes the files anew therefore changes the token, and the browsers fetch the icons once more. Not covered is other rendering code changed in place without any of these, the icon markup of TYPO3 or the SVG sanitiser library edited on the server. Touch the SVG files of the affected icons then.

Each web node computes the token from its own file times and project path, so nodes that do not share one build compute different tokens, and a page rendered on one node gets the five-minute answer from another.

The icon factory 

Both are read by the JavaScript module @fgtclb/academic-base/frontend/icons.js, which this extension publishes in its import map. The module and its exports are public API like the rest of this section. A module asks it for an icon by its identifier. The factory answers from the JSON maps of the page and asks the endpoint only for what the page does not carry, collecting the icons asked for at the same time into one request. The request names them sorted by identifier, so the same icons always make the same URL and a browser or a proxy caches their answer once:

The template of the plugin
<div class="my-plugin" data-my-plugin>
    <ab:frontendIconMap identifiers="{0: 'tx-academicbase-action-add'}" endpoint="1" />
</div>
<f:asset.module identifier="@my-vendor/my-sitepackage/frontend/my-plugin.js" />
Copied!
The module of the plugin
import { IconFactory, Sizes, endpointFrom } from '@fgtclb/academic-base/frontend/icons.js';

const root = document.querySelector('[data-my-plugin]');
const icons = new IconFactory(endpointFrom(root));

// From the JSON map of the page, without a request.
button.append(await icons.getIconElement('tx-academicbase-action-add'));
// From the endpoint, in one request for both.
const [edit, remove] = await Promise.all([
    icons.getIcon('tx-academicbase-action-edit', Sizes.medium),
    icons.getIcon('tx-academicbase-action-delete', Sizes.medium),
]);
Copied!

The extension or site package that ships the module has to name academic_base in the dependencies of its import map. A page only carries the import map entries of the packages its modules declare:

EXT:my_sitepackage/Configuration/JavaScriptModules.php
return [
    'dependencies' => ['core', 'academic_base'],
    'imports' => [
        '@my-vendor/my-sitepackage/frontend/' => 'EXT:my_sitepackage/Resources/Public/JavaScript/frontend/',
    ],
];
Copied!

getIcon() answers the markup, getIconElement() a new element on every call, and prefetch() asks for several icons ahead of time. An identifier that is not served, or that is not an icon identifier at all, rejects the promise. A malformed one is never sent, so it cannot fail the icons asked for with it. The factory reads every JSON map of the document, not only those inside the element it was given, and the first map that carries an icon wins. An icon the endpoint leaves out stays rejected for the page, unless a JSON map that reaches the page later carries it. Each icon is asked for once per page, without cookies. A request that fails or gets no answer within ten seconds rejects its icons, and the next call asks again. The browser keeps the answer of the endpoint as long as the token does not change.

Which icons are served 

The JSON map and the endpoint serve the same icons. The icons of the frontend icon registry, and no other: what the Configuration/FrontendIcons.php of an extension or a site package registers, what a listener of CollectFrontendIconsEvent contributes, and the icons of category types and category groups. The icon registry of TYPO3 is never read, so a core icon or the backend icon of a record type is not served, even when a template asks for its identifier. A site package hands an icon of its own to its JavaScript by registering it in its Configuration/FrontendIcons.php, see Frontend icons.

Of the frontend icons, three kinds are left out of the answer rather than answered with the placeholder of an unknown icon:

  • the placeholder default-not-found itself, and an identifier the frontend registry does not know,
  • an icon whose provider does not inline an SVG file: a bitmap icon, a sprite icon or a font icon. Served are the icons of CurrentColorSvgIconProvider and of the core \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider ,
  • an identifier that is longer than 100 characters, holds anything but lowercase letters, digits, _, . and -, or starts with . or -.

The markup is what the provider of the icon renders, sanitised as far as that provider sanitises. CurrentColorSvgIconProvider sanitises on TYPO3 v13 and v14, the inline markup of the core SvgIconProvider is sanitised on TYPO3 v14 only. That is the same markup, with the same exposure, as the icon rendered inline by a template.

Third-party icons 

The SVG icons below Resources/Public/Icons/, except Extension.svg, are Font Awesome Free icons by Fonticons, Inc., licensed under the Creative Commons Attribution 4.0 International license. The notice Resources/Public/Icons/LICENSE-font-awesome.txt lists every file with its Font Awesome name and the changes made to it.

The files are taken from version 7.3.1. They are modified: the fill colour moved to the root element, width and height were added, and each file is named after its purpose. Each file keeps Font Awesome's attribution comment, which the icon provider removes from the rendered markup together with every other comment. Extension.svg is the icon of the extension itself and is not part of the set.