Starting with OTRS 3.0, the CSS and JavaScript code in OTRS grew to a large amount. To be able to satisfy both development concerns (good maintainability by a large number of separate files) and performance issues (making few HTTP requests and serving minified content without unneccessary whitespace and documentation) had to be addressed. To achieve these goals, the Loader was invented.
To put it simple, the Loader
determines for each request precisely which CSS and JavaScript files are needed at the client side by the current application module
collects all the relevant data
minifies the data, removing unnecessary whitespace and documentation
serves it to the client in only a few HTTP requests instead of many individual ones, allowing the client to cache these snippets in the browser cache
performs these tasks in a highly performing way, utilizing the caching mechanisms of OTRS.
Of course, there is a little bit more detailed involved, but this should suffice as a first overview.
With the configuration settings Loader::Enabled::CSS
and Loader::Enabled::JavaScript
, the loader can be turned
on and off for CSS and JavaScript, respectively (it is on by default).
Because of rendering problems in Internet Explorer, the Loader cannot be turned off for CSS files for this client browser (config setting will be overridden). Up to version 8, Internet Explorer cannot handle more than 32 CSS files on a page.
To learn about how the Loader works, please turn it off in your OTRS installation
with the aforementioned configuration settings. Now look at the source code of
the application module that you are currently using in this OTRS system (after a
reload, of course). You will see that there are many CSS files loaded in the
<head>
section of the page, and many JavaScript files
at the bottom of the page, just before the closing </body>
element.
Having the content like this in many individual files with a readable formatting makes the development much easier, and even possible at all. However, this has the disadvantage of a large number of HTTP requests (network latency has a big effect) and unnecessary content (whitespace and documentation) which needs to be transferred to the client.
The Loader solves this problem by performing the steps outlined in the short description above. Please turn on the Loader again and reload your page now. Now you can see that there are only very few CSS and JavaScript tags in the HTML code, like this:
<script type="text/javascript" src="/otrs30-dev-web/js/js-cache/CommonJS_d16010491cbd4faaaeb740136a8ecbfd.js"></script> <script type="text/javascript" src="/otrs30-dev-web/js/js-cache/ModuleJS_b54ba9c085577ac48745f6849978907c.js"></script>
What just happened? During the original request generating the HTML code for this page,
the Loader generated these two files (or took them from the cache) and put the
shown <script>
tags on the page which link to these files,
instead of linking to all relevant JavaScript files separately (as you saw it without
the loader being active).
The CSS section looks a little more complicated:
<link rel="stylesheet" type="text/css" href="/otrs30-dev-web/skins/Agent/default/css-cache/CommonCSS_00753c78c9be7a634c70e914486bfbad.css" /> <!--[if IE 7]> <link rel="stylesheet" type="text/css" href="/otrs30-dev-web/skins/Agent/default/css-cache/CommonCSS_IE7_59394a0516ce2e7359c255a06835d31f.css" /> <![endif]--> <!--[if IE 8]> <link rel="stylesheet" type="text/css" href="/otrs30-dev-web/skins/Agent/default/css-cache/CommonCSS_IE8_ff58bd010ef0169703062b6001b13ca9.css" /> <![endif]-->
The reason is that Internet Explorer 7 and 8 need special treatment in addition to the default CSS because of their lacking support of web standard technologies. So we have some normal CSS that is loaded in all browsers, and some special CSS that is inside of so-called "conditional comments" which cause it to be loaded only by Internet Explorer 7/8. All other browsers will ignore it.
Now we have outlined how the loader works. Let's look at how you can utilize that in your own OTRS extensions by adding configuration data to the loader, telling it to load additional or alternative CSS or JavaScript content.
To be able to operate correctly, the Loader needs to know which content it has to load for a particular OTRS application module. First, it will look for JavaScript files which always have to be loaded, and then it looks for special files which are only relevant for the current application module.
The list of JavaScript files to be loaded is configured in the configuration settings
Loader::Agent::CommonJS
(for the agent interface) and
Loader::Customer::CommonJS
(for the customer interface).
These settings are designed as hashes, so that OTRS extensions can add their own hash keys for additional content to be loaded. Let's look at an example:
<ConfigItem Name="Loader::Agent::CommonJS###000-Framework" Required="1" Valid="1"> <Description Translatable="1">List of JS files to always be loaded for the agent interface.</Description> <Group>Framework</Group> <SubGroup>Core::Web</SubGroup> <Setting> <Array> <Item>thirdparty/json/json2.js</Item> <Item>thirdparty/jquery-1.4.4/jquery.js</Item> ... <Item>Core.App.js</Item> <Item>Core.Agent.js</Item> <Item>Core.Agent.Search.js</Item> </Array> </Setting> </ConfigItem>
This is the list of JavaScript files which always need to be loaded for the agent interface of OTRS.
To add new content which is supposed to be loaded always in the agent interface, just add an XML configuration file with another hash entry:
<ConfigItem Name="Loader::Agent::CommonJS###100-CustomPackage" Required="0" Valid="1"> <Description Translatable="1">List of JS files to always be loaded for the agent interface for package "CustomPackage".</Description> <Group>Framework</Group> <SubGroup>Core::Web</SubGroup> <Setting> <Array> <Item>CustomPackage.App.js</Item> </Array> </Setting> </ConfigItem>
Simple, isn't it?
Not all JavaScript is usable for all application modules of OTRS.
Therefore it is possible to specify module-specific JavaScript files.
Whenever a certain module is used (such as AgentDashboard
),
the module-specific JavaScript for this module will also be loaded.
The configuration is done in the frontend module registration in the
XML configurations.
Again, an example:
<ConfigItem Name="Frontend::Module###AgentDashboard" Required="0" Valid="1"> <Description Translatable="1">Frontend module registration for the agent interface.</Description> <Group>Framework</Group> <SubGroup>Frontend::Agent::ModuleRegistration</SubGroup> <Setting> <FrontendModuleReg> <Description>Agent Dashboard</Description> <Title></Title> <NavBarName>Dashboard</NavBarName> <NavBar> <Description Translatable="1"></Description> <Name Translatable="1">Dashboard</Name> <Link>Action=AgentDashboard</Link> <NavBar>Dashboard</NavBar> <Type>Menu</Type> <Description Translatable="1"></Description> <Block>ItemArea</Block> <AccessKey>d</AccessKey> <Prio>50</Prio> </NavBar> <Loader> <JavaScript>thirdparty/flot/excanvas.js</JavaScript> <JavaScript>thirdparty/flot/jquery.flot.js</JavaScript> <JavaScript>Core.UI.Chart.js</JavaScript> <JavaScript>Core.UI.DnD.js</JavaScript> <JavaScript>Core.Agent.Dashboard.js</JavaScript> </Loader> </FrontendModuleReg> </Setting> </ConfigItem>
It is possible to put a <Loader>
tag
in the frontend module registrations which may contain
<JavaScript>
tags, one for each file
that is supposed to be loaded for this application module.
Now you have all information you need to configure the way the Loader handles JavaScript code.
There is one special case: for ToolbarModule
s, you can also add custom
JavaScript files. Just add a JavaScript
attribute to
the configuration like this:
<ConfigItem Name="Frontend::ToolBarModule###410-Ticket::AgentTicketEmail" Required="0" Valid="1"> <Description Translatable="1">Toolbar Item for a shortcut.</Description> <Group>Ticket</Group> <SubGroup>Frontend::Agent::ToolBarModule</SubGroup> <Setting> <Hash> <Item Key="Module">Kernel::Output::HTML::ToolBarLink</Item> <Item Key="Name">New email ticket</Item> <Item Key="Priority">1009999</Item> <Item Key="Link">Action=AgentTicketEmail</Item> <Item Key="Action">AgentTicketEmail</Item> <Item Key="AccessKey">l</Item> <Item Key="CssClass">EmailTicket</Item> <Item Key="JavaScript">OTRS.Agent.CustomToolbarModule.js</Item> </Hash> </Setting> </ConfigItem>
The loader handles CSS files very similar to JavaScript files, as described in the previous section, and extending the settings works in the same way too.
The way common CSS is handled is very similar to the way
common JavaScript
is loaded. Here, the configuration settings are called
Loader::Agent::CommonCSS
and
Loader::Customer::CommonCSS
, respectively.
However, as we already noted above, Internet Explorer 7 and 8
(and for the customer interface also 6) need special treatment.
That's why there are special configuration settings for them, to
specify common CSS which should only be loaded in these browsers.
The respective settings are
Loader::Agent::CommonCSS::IE7
,
Loader::Agent::CommonCSS::IE8
,
Loader::Customer::CommonCSS::IE6
,
Loader::Customer::CommonCSS::IE7
and
Loader::Customer::CommonCSS::IE8
.
An example:
<ConfigItem Name="Loader::Agent::CommonCSS::IE8###000-Framework" Required="1" Valid="1"> <Description Translatable="1">List of IE8-specific CSS files to always be loaded for the agent interface.</Description> <Group>Framework</Group> <SubGroup>Core::Web</SubGroup> <Setting> <Array> <Item>Core.OverviewSmall.IE8.css</Item> </Array> </Setting> </ConfigItem>
This is the list of common CSS files for the agent interface which should only be loaded in Internet Explorer 8.
Module-specific CSS is handled very similar to the way module-specific JavaScript is handled. It is also configured in the frontend module registrations. Example:
<ConfigItem Name="Frontend::Module###Admin" Required="0" Valid="1"> <Description Translatable="1">Frontend module registration for the agent interface.</Description> <Group>Framework</Group> <SubGroup>Frontend::Admin::ModuleRegistration</SubGroup> <Setting> <FrontendModuleReg> <Group>admin</Group> <Description>Admin-Area</Description> <Title></Title> <NavBarName>Admin</NavBarName> <NavBar> <Type>Menu</Type> <Description Translatable="1"></Description> <Block>ItemArea</Block> <Name Translatable="1">Admin</Name> <Link>Action=Admin</Link> <NavBar>Admin</NavBar> <AccessKey>a</AccessKey> <Prio>10000</Prio> </NavBar> <NavBarModule> <Module>Kernel::Output::HTML::NavBarModuleAdmin</Module> </NavBarModule> <Loader> <CSS>Core.Agent.Admin.css</CSS> <CSS_IE7>Core.Agent.AdminIE7.css</CSS_IE7> <JavaScript>Core.Agent.Admin.SysConfig.js</JavaScript> </Loader> </FrontendModuleReg> </Setting> </ConfigItem>
Here we have a module (the admin overview page of the agent interface)
which has special JavaScript, normal CSS
(tagname <CSS>
) and special CSS for
Internet Explorer 7 (tagname <CSS_IE7>
).
All of these need to be loaded in addition to the common JavaScript
and CSS defined for the agent interface.
It is also possible to specify module-specific CSS for Internet Explorer 8
(tagname <CSS_IE8>
) and, in the case of the customer interface,
for Internet Explorer 6 (tagname <CSS_IE6>
).
There is one special case: for ToolbarModule
s, you can also add custom
CSS files. Just add a CSS
, CSS_IE7
or
CSS_IE8
attribute to the configuration like this:
<ConfigItem Name="Frontend::ToolBarModule###410-Ticket::AgentTicketEmail" Required="0" Valid="1"> <Description Translatable="1">Toolbar Item for a shortcut.</Description> <Group>Ticket</Group> <SubGroup>Frontend::Agent::ToolBarModule</SubGroup> <Setting> <Hash> <Item Key="Module">Kernel::Output::HTML::ToolBarLink</Item> <Item Key="Name">New email ticket</Item> <Item Key="Priority">1009999</Item> <Item Key="Link">Action=AgentTicketEmail</Item> <Item Key="Action">AgentTicketEmail</Item> <Item Key="AccessKey">l</Item> <Item Key="CssClass">EmailTicket</Item> <Item Key="CSS">OTRS.Agent.CustomToolbarModule.css</Item> <Item Key="CSS_IE7">OTRS.Agent.CustomToolbarModule.IE7.css</Item> </Hash> </Setting> </ConfigItem>