Templates 

The study plan content element renders from one template and four partials, and its script finds every part it drives by a data-study-plan-* attribute. Together those are the contract: replace any partial, with your own elements and your own class names, keep the attributes where this page puts them, and the filter, the highlighting, the semester accordion and the module dialogs keep working.

Where they live 

File Renders
Frontend/Default/Templates/AcademicStudyPlan.html The container, and the script of Skip the script.
Frontend/Default/Partials/StudyPlan/Filter.html The category filter.
Frontend/Default/Partials/StudyPlan/Semester.html One semester column, with its header and its modules.
Frontend/Default/Partials/StudyPlan/Module.html One module, with its dialog trigger.
Frontend/Default/Partials/StudyPlan/ModuleDialog.html The dialog of one module.

All five sit below EXT:academic_study_plan/Resources/Private/. Point the element at templates of your own with the three constants plugin.tx_academicstudyplan.view.templateRootPath , .partialRootPath and .layoutRootPath , or add a higher entry to tt_content.academic_study_plan.partialRootPaths . A path that holds one file replaces that one file; everything else keeps coming from the extension.

What a partial is given 

Each partial receives exactly the variables it renders, so an override has an argument list it can rely on rather than whatever the template happened to have in scope.

Partial Arguments
StudyPlan/Filter collapsible - whether the site asked for the collapsible filter, see Collapse the category filter.
StudyPlan/Semester semester - the semester, with its modules , and idPrefix , which it passes on to the modules.
StudyPlan/Module module and the semester it belongs to, the latter only for the label the dialog trigger announces, and idPrefix , which the dialog id starts with.
StudyPlan/ModuleDialog module and idPrefix .

idPrefix is empty for a plan placed on the page, so its dialog ids are popup-<module uid> . A plan rendered inside another content element - an "Insert records" element, or a grid element that renders its children through RECORDS , CONTENT , f:cObject or, on TYPO3 v14, f:render.record - gets c<uid>- of that element, so its dialogs are popup-c<uid>-<module uid> and no copy of a plan repeats the dialog ids of another. An override that does not pass idPrefix on renders the ids without it and keeps working, see data-dialog-id.

The credit_points of a semester and of a module are a number, not the value the database returns: printed as they are, they read "2.5", "30" and "0" rather than "2.50", "30.00" and "0.00". They render with a decimal point on every page language; format them in the override for a decimal comma.

The data attributes 

Attribute Belongs on What the script does with it
data-study-plan The element that wraps the whole plan. Starts one instance on it. The value is the uid of the content element; several plans on a page are told apart by the element itself, not by the value, so it may repeat.
data-study-plan-filter The list the filter buttons go into. Empties it and fills it with one button per category the rendered modules carry.
data-study-plan-filter-template The single item inside that list. Clones it per category, substituting category-id-placeholder , category-color-placeholder and category-label-placeholder , and takes hidden off every clone.
data-study-plan-filter-collapsible The same list as data-study-plan-filter , and only when the site switched the collapsible filter on. The extension renders it for you. Hides the list and puts a toggle button in front of it, labelled from data-filter-label . Without that label, or with no category in the filter, no toggle is inserted and the filter stays expanded.
data-study-plan-semester The element that holds one semester with its modules. Opens and closes it, and highlights it with its modules.
data-study-plan-semester-header The header inside a semester. Makes it the accordion control below 768 pixels and inert above it.
data-study-plan-module One module inside a semester. Reads its data-categories , highlights it, levels its height on a wide viewport, and looks for its dialog and trigger inside it.
data-study-plan-dialog-trigger The control that opens the dialog of a module, inside that module - or the module element itself, see below. Opens the dialog of that module, by pointer and by keyboard. The dialog is the one named by data-dialog-id , looked up inside the plan first, and the module's own when the trigger names none.
data-study-plan-dialog The <dialog> of a module, inside that module. Opens it as a modal and closes it again from the first <button> inside it, stopping whatever it was playing.

Two class names are not part of this list and are written by the script rather than looked up: highlighted and open , on the container, the semesters and the modules. Style them, do not rely on them being absent.

The script also writes hidden on the filter list while it is collapsed. That attribute only hides anything when the stylesheet of the site says .ace-filter .ace-list[hidden] { display: none } - the browser's own rule for it loses to any author rule that gives the list a display . The extension ships no stylesheet, see Style the element.

The attributes the script reads a value from 

The attributes above are markers. These four carry values the script needs, and an override that renders modules or filter buttons itself has to produce them:

Attribute Belongs on Value
data-filter-label The container. The label of the collapsible filter's toggle button. The extension renders the translation of filter.label into it.
data-categories A module. A JSON array of the categories the module carries, each an object with uid, label and colour - for example [{"uid":1,"label":"Mandatory","colour":"#cc0000"}]. An absent attribute, an empty string and [] all mean "no category"; anything that does not parse is treated the same way. The title is rendered as text, never as markup.
data-category-id , data-category-color The <button> inside the filter template item. Substituted from category-id-placeholder and category-color-placeholder when the item is cloned, and read back when the button is activated. A button without them highlights nothing. A colour that is not a hexadecimal value, a plain keyword or an rgb() / rgba() function is dropped.
data-dialog-id A dialog trigger. The id of the dialog it opens. The script looks for it among the dialogs of its own plan first, and in the whole document only when the plan has none, so the same plan shown twice opens the dialog of each copy even with repeated ids, and a dialog an override renders outside the plan is still found. Without it the trigger opens the dialog inside its own module.

The three placeholder strings - category-id-placeholder , category-color-placeholder and category-label-placeholder - are substituted wherever they appear in the item, in an attribute value or in text. Keep them in an override of the filter, in the attributes above and wherever the label is to be read.

The glyphs of a semester header 

The semester partial renders two glyphs into the header, inside a <span class="ace-actions"> , tx-academicbase-action-expand and tx-academicbase-action-collapse, and the dialog partial renders tx-academicbase-action-close into its close button. All three are shared action icons of EXT:academic_base: inlined SVGs drawn in currentColor , rendered with its ab:icon ViewHelper from its frontend icon registry. An override that renders them declares xmlns:ab="http://typo3.org/ns/FGTCLB/AcademicBase/ViewHelpers" in its <html> tag. With core:icon it shows TYPO3's not-found icon, see Breaking: The study plan icons are renamed and the controls are frontend icons.

The script does not look at the glyphs, the stylesheet of the site does. The example of Style the element selects the classes the ViewHelper writes: icon-tx-academicbase-action-collapse is hidden in a closed semester, icon-tx-academicbase-action-expand in an open one, and every .icon in the header from 768 pixels on. It also sizes every .icon of the element to 1.25rem and the drawing inside it to the full icon, so a drawing without a size of its own stays visible. An override of StudyPlan/Semester.html for a stylesheet like that one therefore keeps rendering the two identifiers, with ab:icon. One that renders glyphs of its own brings the rules for them.

To draw a glyph differently, register a file of your own under its identifier in the Configuration/FrontendIcons.php of your site package, which has to depend on EXT:academic_base so that its entry is read last. The identifiers belong to EXT:academic_base, so the replacement shows in every academic extension that renders the glyph, not in the study plan alone. An entry in Configuration/Icons.php does not reach the study plan.

The module element as the trigger 

data-study-plan-dialog-trigger may sit on the module element itself instead of on a control inside it, which makes the whole module open its dialog. The script pairs it with the dialog of that very module, so a plan full of such modules opens the right one each time.

The script does not make that element focusable, and an override that wants this has to: give it tabindex="0" and role="button" itself, or the dialog opens by pointer only. A key pressed on something inside the module - a link, an audio control - is left to that control and does not open the dialog.

The extension does not render it that way, and does not offer a setting for it: a module that is itself a control nests its heading, its credits and its dialog inside interactive content, which assistive technology reads differently and which no keyboard order describes well. It is supported because an installation that wants it should not have to fork the script for it.

Markup of version 2.x keeps working 

Before these attributes existed the script found its parts by class name: .academic-study-plan , .filter , the first <li> inside it, .col , .header , .module , .modal-trigger and the <dialog> inside a module. Each of those inside a plan is still read, per part, when the attribute of that part is nowhere in that plan. So an override written for 2.x keeps working, and one that carries the attributes on some parts and not on others works too.

The container is the exception: .academic-study-plan is read next to data-study-plan rather than instead of it, because two plans of one page can come from different templates, and one whose template lacks the attribute must not disappear because the other one carries it.

That fallback is deprecated and is removed in 4.0. See Deprecation: The study plan class selectors.

What a page without the script shows 

The markup is not a fallback: the filter, the accordion and the dialogs need a script. The one part that would otherwise be visible is handled - the item inside the filter list is rendered hidden , because its placeholder text is not meant for anybody. An installation that brings a script of its own has to take that attribute off the items it builds.

See also 

  • Configuration - the site settings and constants this page refers to.