diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php index 6c3d2d04b..9602396ed 100644 --- a/application/controllers/ConfigController.php +++ b/application/controllers/ConfigController.php @@ -72,6 +72,7 @@ class ConfigController extends ActionController $allowedActions[] = 'roles'; } $this->firstAllowedAction = array_shift($allowedActions); + $this->getTabs()->setTitle($this->translate('Config Navigation')); } public function devtoolsAction() diff --git a/application/controllers/RolesController.php b/application/controllers/RolesController.php index 25b3651d9..6cbb4f703 100644 --- a/application/controllers/RolesController.php +++ b/application/controllers/RolesController.php @@ -51,6 +51,7 @@ class RolesController extends ActionController 'label' => $this->translate('Roles'), 'url' => 'roles' )); + $this->getTabs()->setTitle($this->translate('Role Configuration')); } /** diff --git a/application/views/scripts/config/application.phtml b/application/views/scripts/config/application.phtml index 9a168a904..4255befc4 100644 --- a/application/views/scripts/config/application.phtml +++ b/application/views/scripts/config/application.phtml @@ -1,9 +1,8 @@
tabs->render($this); ?>
-
-

+

translate('General Configuration'); ?>

messageBox)): ?> diff --git a/application/views/scripts/config/authentication/create.phtml b/application/views/scripts/config/authentication/create.phtml index 5f840aea0..48d1f00ed 100644 --- a/application/views/scripts/config/authentication/create.phtml +++ b/application/views/scripts/config/authentication/create.phtml @@ -2,7 +2,7 @@ tabs->showOnlyCloseButton() ?>
-

+

translate('Create New Authentication Backend'); ?>

diff --git a/application/views/scripts/config/authentication/modify.phtml b/application/views/scripts/config/authentication/modify.phtml index 5aeee7d12..ebc1937a7 100644 --- a/application/views/scripts/config/authentication/modify.phtml +++ b/application/views/scripts/config/authentication/modify.phtml @@ -2,7 +2,7 @@ tabs->showOnlyCloseButton() ?>

-

+

translate('Edit Backend'); ?>

diff --git a/application/views/scripts/config/authentication/remove.phtml b/application/views/scripts/config/authentication/remove.phtml index cdd615ac7..0a53af30c 100644 --- a/application/views/scripts/config/authentication/remove.phtml +++ b/application/views/scripts/config/authentication/remove.phtml @@ -2,7 +2,7 @@ tabs->showOnlyCloseButton() ?>
-

+

translate('Remove Backend'); ?>

diff --git a/application/views/scripts/config/authentication/reorder.phtml b/application/views/scripts/config/authentication/reorder.phtml index ad0d0ebc5..4583a23b3 100644 --- a/application/views/scripts/config/authentication/reorder.phtml +++ b/application/views/scripts/config/authentication/reorder.phtml @@ -2,21 +2,10 @@
-

- +

+ translate('Authentication Configuration'); ?>

- -

+

@@ -24,7 +13,7 @@ icon('plus'); ?>translate('Create A New Authentication Backend'); ?>

-

+

diff --git a/application/views/scripts/config/module.phtml b/application/views/scripts/config/module.phtml index 617740c5a..28fbeb39e 100644 --- a/application/views/scripts/config/module.phtml +++ b/application/views/scripts/config/module.phtml @@ -1,76 +1,80 @@
-tabs ?> -

escape($module->getTitle()) ?>

+ tabs ?>
- -translate('There is no such module installed.') ?> - -getDependencies(); -$restrictions = $module->getProvidedRestrictions(); -$permissions = $module->getProvidedPermissions(); -$state = $moduleData->enabled ? ($moduleData->loaded ? 'enabled' : 'failed') : 'disabled' - -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
escape($this->translate('Name')) ?>escape($module->getName()) ?>
translate('State') ?> - qlink( - $this->translate('disable'), - 'config/moduledisable', - array('name' => $module->getName()), - array('title' => sprintf($this->translate('Disable the %s module'), $module->getName())) - ); ?> - - - qlink( - $this->translate('enable'), - 'config/moduleenable', - array('name' => $module->getName()), - array('title' => sprintf($this->translate('Enable the %s module'), $module->getName())) - ); ?> - -
escape($this->translate('Version')) ?>escape($module->getVersion()) ?>
escape($this->translate('Description')) ?>escape($module->getDescription())) ?>
escape($this->translate('Dependencies')) ?>translate('This module has no dependencies'); - -else: foreach ($dependencies as $name => $versionString): ?> -escape($name) ?>: escape($versionString) ?>
-
escape($this->translate('Permissions')) ?> -escape($permission->name) ?>: escape($permission->description) ?>
-
escape($this->translate('Restrictions')) ?> -escape($restriction->name) ?>: escape($restriction->description) ?>
-
- +

+ escape($module->getTitle()) ?> +

+ + translate('There is no such module installed.') ?> + + getDependencies(); + $restrictions = $module->getProvidedRestrictions(); + $permissions = $module->getProvidedPermissions(); + $state = $moduleData->enabled ? ($moduleData->loaded ? 'enabled' : 'failed') : 'disabled' + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
escape($this->translate('Name')) ?>escape($module->getName()) ?>
translate('State') ?> + qlink( + $this->translate('disable'), + 'config/moduledisable', + array('name' => $module->getName()), + array('title' => sprintf($this->translate('Disable the %s module'), $module->getName())) + ); ?> + + + qlink( + $this->translate('enable'), + 'config/moduleenable', + array('name' => $module->getName()), + array('title' => sprintf($this->translate('Enable the %s module'), $module->getName())) + ); ?> + +
escape($this->translate('Version')) ?>escape($module->getVersion()) ?>
escape($this->translate('Description')) ?>escape($module->getDescription())) ?>
escape($this->translate('Dependencies')) ?> + translate('This module has no dependencies'); + else: foreach ($dependencies as $name => $versionString): ?> + escape($name) ?>: escape($versionString) ?>
+ +
escape($this->translate('Permissions')) ?> + + escape($permission->name) ?>: escape($permission->description) ?>
+ +
escape($this->translate('Restrictions')) ?> + + escape($restriction->name) ?>: escape($restriction->description) ?>
+ +
diff --git a/application/views/scripts/config/modules.phtml b/application/views/scripts/config/modules.phtml index 2c79fcee0..feb7facad 100644 --- a/application/views/scripts/config/modules.phtml +++ b/application/views/scripts/config/modules.phtml @@ -1,32 +1,32 @@
tabs ?> -

translate('Installed Modules') ?>

paginationControl($modules) ?>
- - - - - + + + +
- enabled && $module->loaded) { - echo $this->icon('thumbs-up', sprintf($this->translate('Module %s is enabled'), $module->name)); - } elseif (! $module->enabled) { - echo $this->icon('thumbs-down', sprintf($this->translate('Module %s is disabled'), $module->name)); - } else { // ! $module->loaded - echo $this->icon('thumbs-down', sprintf($this->translate('Module %s has failed to load'), $module->name)); - } +

translate('Installed Modules') ?>

+ + + + + - - - -
+ enabled && $module->loaded) { + echo $this->icon('thumbs-up', sprintf($this->translate('Module %s is enabled'), $module->name)); + } elseif (! $module->enabled) { + echo $this->icon('thumbs-down', sprintf($this->translate('Module %s is disabled'), $module->name)); + } else { // ! $module->loaded + echo $this->icon('thumbs-down', sprintf($this->translate('Module %s has failed to load'), $module->name)); + } - echo $this->qlink( - $module->name, - 'config/module/', - array('name' => $module->name), - array('title' => sprintf($this->translate('Show the overview of the %s module'), $module->name)) - ); ?> -
+ echo $this->qlink( + $module->name, + 'config/module/', + array('name' => $module->name), + array('title' => sprintf($this->translate('Show the overview of the %s module'), $module->name)) + ); ?> +
diff --git a/application/views/scripts/config/resource.phtml b/application/views/scripts/config/resource.phtml index 8b58ea15a..c4eb9360f 100644 --- a/application/views/scripts/config/resource.phtml +++ b/application/views/scripts/config/resource.phtml @@ -2,21 +2,10 @@
-

+

- -

+

@@ -24,7 +13,7 @@ icon('plus'); ?> translate('Create A New Resource'); ?>

-

+

diff --git a/application/views/scripts/config/resource/create.phtml b/application/views/scripts/config/resource/create.phtml index c70bd4779..71d8c946e 100644 --- a/application/views/scripts/config/resource/create.phtml +++ b/application/views/scripts/config/resource/create.phtml @@ -2,7 +2,7 @@ tabs->showOnlyCloseButton() ?>
-

+

translate('Create A New Resource'); ?>

translate('Resources are entities that provide data to Icinga Web 2.'); ?>

diff --git a/application/views/scripts/config/resource/modify.phtml b/application/views/scripts/config/resource/modify.phtml index 48255261b..b7bd0a2f7 100644 --- a/application/views/scripts/config/resource/modify.phtml +++ b/application/views/scripts/config/resource/modify.phtml @@ -2,7 +2,7 @@ tabs->showOnlyCloseButton() ?>
-

+

translate('Edit Existing Resource'); ?>

diff --git a/application/views/scripts/config/resource/remove.phtml b/application/views/scripts/config/resource/remove.phtml index ad5ed59cb..010f2d5d2 100644 --- a/application/views/scripts/config/resource/remove.phtml +++ b/application/views/scripts/config/resource/remove.phtml @@ -2,7 +2,7 @@ tabs->showOnlyCloseButton() ?>
-

+

translate('Remove Existing Resource'); ?>

diff --git a/application/views/scripts/preference/index.phtml b/application/views/scripts/preference/index.phtml index 163381531..fc19a1e10 100644 --- a/application/views/scripts/preference/index.phtml +++ b/application/views/scripts/preference/index.phtml @@ -1,7 +1,7 @@
-
+

translate('Preferences'); ?>

\ No newline at end of file diff --git a/application/views/scripts/roles/index.phtml b/application/views/scripts/roles/index.phtml index 0dcd75691..fa1297396 100644 --- a/application/views/scripts/roles/index.phtml +++ b/application/views/scripts/roles/index.phtml @@ -1,8 +1,10 @@
-

translate('Roles') ?>

+

+ translate('Roles') ?> +

isEmpty()): ?> translate('No roles found.') ?> @@ -66,6 +68,9 @@
+

+ translate('Create New Role'); ?> +

translate('Create a New Role') ?> diff --git a/application/views/scripts/roles/new.phtml b/application/views/scripts/roles/new.phtml index 4c21c6f6b..d18ada1a5 100644 --- a/application/views/scripts/roles/new.phtml +++ b/application/views/scripts/roles/new.phtml @@ -1,7 +1,9 @@
showOnlyCloseButton() ?> -

translate('New Role') ?>

+

+ translate('New Role') ?> +

diff --git a/application/views/scripts/roles/remove.phtml b/application/views/scripts/roles/remove.phtml index 4abff566a..432c3602d 100644 --- a/application/views/scripts/roles/remove.phtml +++ b/application/views/scripts/roles/remove.phtml @@ -1,7 +1,9 @@
showOnlyCloseButton() ?> -

translate('Remove Role %s'), $name) ?>

+

+ translate('Remove Role %s'), $name) ?> +

diff --git a/application/views/scripts/roles/update.phtml b/application/views/scripts/roles/update.phtml index f48f1ca69..32ab7d018 100644 --- a/application/views/scripts/roles/update.phtml +++ b/application/views/scripts/roles/update.phtml @@ -1,7 +1,9 @@
showOnlyCloseButton() ?> -

translate('Update Role %s'), $name) ?>

+

+ translate('Update Role %s'), $name) ?> +

diff --git a/library/Icinga/Chart/Chart.php b/library/Icinga/Chart/Chart.php index 13b0114e6..842bb56e8 100644 --- a/library/Icinga/Chart/Chart.php +++ b/library/Icinga/Chart/Chart.php @@ -38,11 +38,25 @@ abstract class Chart implements Drawable */ protected $palette; + /** + * The title of this chart, used for providing accessibility features + * + * @var string + */ + public $title; + + /** + * The description for this chart, mandatory for providing accessibility features + * + * @var string + */ + public $description; + /** * Create a new chart object and create internal objects * * If you want to extend this class use the init() method as an extension point, - * as this will be called at the end o fthe construct call + * as this will be called at the end of the construct call */ public function __construct() { @@ -86,7 +100,6 @@ abstract class Chart implements Drawable } /** - * * Render this graph and return the created SVG * * @return string The SVG created by the SvgRenderer @@ -105,6 +118,11 @@ abstract class Chart implements Drawable $this->renderer->setXAspectRatioAlignment(SVGRenderer::X_ASPECT_RATIO_MIN); $this->renderer->setYAspectRatioAlignment(SVGRenderer::Y_ASPECT_RATIO_MIN); } + + $this->renderer->setAriaDescription($this->description); + $this->renderer->setAriaTitle($this->title); + $this->renderer->getCanvas()->setAriaRole('presentation'); + $this->renderer->getCanvas()->addElement($this); return $this->renderer->render(); } diff --git a/library/Icinga/Chart/Graph/BarGraph.php b/library/Icinga/Chart/Graph/BarGraph.php index 2d20f8f22..dacc12878 100644 --- a/library/Icinga/Chart/Graph/BarGraph.php +++ b/library/Icinga/Chart/Graph/BarGraph.php @@ -65,7 +65,13 @@ class BarGraph extends Styleable implements Drawable ) { $this->order = $order; $this->dataSet = $dataSet; + $this->tooltips = $tooltips; + foreach ($this->tooltips as $value) { + $ts[] = $value; + } + $this->tooltips = $ts; + $this->graphs = $graphs; } diff --git a/library/Icinga/Chart/Graph/LineGraph.php b/library/Icinga/Chart/Graph/LineGraph.php index 630223968..7b831d625 100644 --- a/library/Icinga/Chart/Graph/LineGraph.php +++ b/library/Icinga/Chart/Graph/LineGraph.php @@ -38,6 +38,13 @@ class LineGraph extends Styleable implements Drawable */ private $isDiscrete = false; + /** + * The tooltips + * + * @var + */ + private $tooltips; + /** * The default stroke width * @var int @@ -56,10 +63,22 @@ class LineGraph extends Styleable implements Drawable * * @param array $dataset An array of [x, y] arrays to display */ - public function __construct(array $dataset) - { + public function __construct( + array $dataset, + array &$graphs, + $order, + array $tooltips = null + ) { usort($dataset, array($this, 'sortByX')); $this->dataset = $dataset; + $this->graphs = $graphs; + + $this->tooltips = $tooltips; + foreach ($this->tooltips as $value) { + $ts[] = $value; + } + $this->tooltips = $ts; + $this->order = $order; } /** @@ -142,14 +161,41 @@ class LineGraph extends Styleable implements Drawable $path->setAdditionalStyle('clip-path: url(#clip);'); $path->setId($this->id); $group = $path->toSvg($ctx); - if ($this->showDataPoints === true) { - foreach ($this->dataset as $point) { - $dot = new Circle($point[0], $point[1], $this->dotWith); - $dot->setFill($this->strokeColor); - $group->appendChild($dot->toSvg($ctx)); + foreach ($this->dataset as $x => $point) { + + if ($this->showDataPoints === true) { + $dot = new Circle($point[0], $point[1], $this->dotWith); + $dot->setFill($this->strokeColor); + $group->appendChild($dot->toSvg($ctx)); + } + + // Draw invisible circle for tooltip hovering + $invisible = new Circle($point[0], $point[1], 20); + $invisible->setFill($this->strokeColor); + $invisible->setAdditionalStyle('opacity: 0.0;'); + $invisible->setAttribute('class', 'chart-data'); + if (isset($this->tooltips[$x])) { + $data = array( + 'label' => isset($this->graphs[$this->order]['label']) ? + strtolower($this->graphs[$this->order]['label']) : '', + 'color' => isset($this->graphs[$this->order]['color']) ? + strtolower($this->graphs[$this->order]['color']) : '#fff' + ); + $format = isset($this->graphs[$this->order]['tooltip']) + ? $this->graphs[$this->order]['tooltip'] : null; + $invisible->setAttribute( + 'title', + $this->tooltips[$x]->renderNoHtml($this->order, $data, $format) + ); + $invisible->setAttribute( + 'data-title-rich', + $this->tooltips[$x]->render($this->order, $data, $format) + ); + } + $group->appendChild($invisible->toSvg($ctx)); } - } + return $group; } } diff --git a/library/Icinga/Chart/Graph/Tooltip.php b/library/Icinga/Chart/Graph/Tooltip.php index 5fa5c3608..8b2efa613 100644 --- a/library/Icinga/Chart/Graph/Tooltip.php +++ b/library/Icinga/Chart/Graph/Tooltip.php @@ -66,7 +66,7 @@ class Tooltip */ public function __construct ( $data = array(), - $format = '{title}
{value} of {sum} {label}' + $format = '{title}: {value} {label}' ) { $this->data = array_merge($this->data, $data); $this->defaultFormat = $format; diff --git a/library/Icinga/Chart/GridChart.php b/library/Icinga/Chart/GridChart.php index 7f2794282..9f867ac66 100644 --- a/library/Icinga/Chart/GridChart.php +++ b/library/Icinga/Chart/GridChart.php @@ -84,6 +84,13 @@ class GridChart extends Chart */ private $tooltips = array(); + public function __construct() + { + $this->title = t('Grid Chart'); + $this->description = t('Contains data in a bar or line chart.'); + parent::__construct(); + } + /** * Check if the current dataset has the proper structure for this chart. * @@ -395,7 +402,12 @@ class GridChart extends Chart ); break; case self::TYPE_LINE: - $graphObj = new LineGraph($axis->transform($graph['data'])); + $graphObj = new LineGraph( + $axis->transform($graph['data']), + $graphs, + $dataset, + $this->tooltips + ); break; default: continue; diff --git a/library/Icinga/Chart/PieChart.php b/library/Icinga/Chart/PieChart.php index 33ce32927..6b19969c8 100644 --- a/library/Icinga/Chart/PieChart.php +++ b/library/Icinga/Chart/PieChart.php @@ -50,6 +50,13 @@ class PieChart extends Chart */ private $noCaption = false; + public function __construct() + { + $this->title = t('Pie Chart'); + $this->description = t('Contains data in a pie chart.'); + parent::__construct(); + } + /** * Test if the given pies have the correct format * diff --git a/library/Icinga/Chart/Primitive/Canvas.php b/library/Icinga/Chart/Primitive/Canvas.php index c5617fa35..88e247f02 100644 --- a/library/Icinga/Chart/Primitive/Canvas.php +++ b/library/Icinga/Chart/Primitive/Canvas.php @@ -43,6 +43,13 @@ class Canvas implements Drawable */ private $rect; + /** + * The aria role used to describe this canvas' purpose in the accessibility tree + * + * @var string + */ + private $ariaRole; + /** * Create this canvas * @@ -111,6 +118,23 @@ class Canvas implements Drawable $innerContainer->appendChild($child->toSvg($ctx)); } + if (isset($this->ariaRole)) { + $outer->setAttribute('role', $this->ariaRole); + } return $outer; } + + /** + * Set the aria role used to determine the meaning of this canvas in the accessibility tree + * + * The role 'presentation' will indicate that the purpose of this canvas is entirely decorative, while the role + * 'img' will indicate that the canvas contains an image, with a possible title or a description. For other + * possible roles, see http://www.w3.org/TR/wai-aria/roles + * + * @param $role string The aria role to set + */ + public function setAriaRole($role) + { + $this->ariaRole = $role; + } } diff --git a/library/Icinga/Chart/SVGRenderer.php b/library/Icinga/Chart/SVGRenderer.php index 5cc223388..98eaa86d6 100644 --- a/library/Icinga/Chart/SVGRenderer.php +++ b/library/Icinga/Chart/SVGRenderer.php @@ -48,6 +48,27 @@ class SVGRenderer */ private $svg; + /** + * The description of this SVG, useful for screen readers + * + * @var string + */ + private $ariaDescription; + + /** + * The title of this SVG, useful for screen readers + * + * @var string + */ + private $ariaTitle; + + /** + * The aria role used by this svg element + * + * @var string + */ + private $ariaRole = 'img'; + /** * The root layer for all elements * @@ -126,6 +147,7 @@ class SVGRenderer $svg = $this->document->createElement('svg'); $svg->setAttribute('xmlns', 'http://www.w3.org/2000/svg'); $svg->setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); + $svg->setAttribute('role', $this->ariaRole); $svg->setAttribute('width', '100%'); $svg->setAttribute('height', '100%'); $svg->setAttribute( @@ -150,6 +172,42 @@ class SVGRenderer return $svg; } + /** + * Add aria title and description + * + * Adds an aria title and desc element to the given SVG node, which are used to describe this SVG by accessibility + * tools such as screen readers. + * + * @param DOMNode $svg The SVG DOMNode to which the aria attributes should be attached + * @param $title The title text + * @param $description The description text + */ + private function addAriaDescription (DOMNode $svg, $titleText, $descriptionText) + { + $doc = $svg->ownerDocument; + + $titleId = $descId = ''; + if (isset ($this->ariaTitle)) { + $titleId = 'aria-title-' . $this->stripNonAlphanumeric($titleText); + $title = $doc->createElement('title'); + $title->setAttribute('id', $titleId); + + $title->appendChild($doc->createTextNode($titleText)); + $svg->appendChild($title); + } + + if (isset ($this->ariaDescription)) { + $descId = 'aria-desc-' . $this->stripNonAlphanumeric($descriptionText); + $desc = $doc->createElement('desc'); + $desc->setAttribute('id', $descId); + + $desc->appendChild($doc->createTextNode($descriptionText)); + $svg->appendChild($desc); + } + + $svg->setAttribute('aria-labelledby', join(' ', array($titleId, $descId))); + } + /** * Initialises the XML-document, SVG-element and this figure's root canvas * @@ -172,6 +230,7 @@ class SVGRenderer { $this->createRootDocument(); $ctx = $this->createRenderContext(); + $this->addAriaDescription($this->svg, $this->ariaTitle, $this->ariaDescription); $this->svg->appendChild($this->rootCanvas->toSvg($ctx)); $this->document->formatOutput = true; return $this->document->saveXML(); @@ -232,4 +291,40 @@ class SVGRenderer { $this->yAspectRatio = $alignment; } + + /** + * Set the aria description, that is used as a title for this SVG in screen readers + * + * @param $text + */ + public function setAriaTitle($text) + { + $this->ariaTitle = $text; + } + + /** + * Set the aria description, that is used to describe this SVG in screen readers + * + * @param $text + */ + public function setAriaDescription($text) + { + $this->ariaDescription = $text; + } + + /** + * Set the aria role, that is used to describe the purpose of this SVG in screen readers + * + * @param $text + */ + public function setAriaRole($text) + { + $this->ariaRole = $text; + } + + + private function stripNonAlphanumeric($str) + { + return preg_replace('/[^A-Za-z]+/', '', $str); + } } diff --git a/library/Icinga/Web/Widget/Chart/InlinePie.php b/library/Icinga/Web/Widget/Chart/InlinePie.php index 341322714..0bddc906d 100644 --- a/library/Icinga/Web/Widget/Chart/InlinePie.php +++ b/library/Icinga/Web/Widget/Chart/InlinePie.php @@ -44,7 +44,6 @@ EOD; EOD; - /** * @var Url */ diff --git a/library/Icinga/Web/Widget/Dashboard/Dashlet.php b/library/Icinga/Web/Widget/Dashboard/Dashlet.php index cbb4bec33..614caf845 100644 --- a/library/Icinga/Web/Widget/Dashboard/Dashlet.php +++ b/library/Icinga/Web/Widget/Dashboard/Dashlet.php @@ -6,7 +6,6 @@ namespace Icinga\Web\Widget\Dashboard; use Zend_Form_Element_Button; use Icinga\Web\Form; use Icinga\Web\Url; -use Icinga\Web\Widget\AbstractWidget; use Icinga\Data\ConfigObject; use Icinga\Exception\IcingaException; @@ -54,7 +53,12 @@ class Dashlet extends UserWidget

{TITLE}

EOD; @@ -184,7 +188,8 @@ EOD; '{IFRAME_URL}', '{FULL_URL}', '{TOOLTIP}', - '{TITLE}' + '{TITLE}', + '{TITLE_PREFIX}' ); $replaceTokens = array( @@ -192,7 +197,8 @@ EOD; $iframeUrl, $url->getUrlWithout(array('view', 'limit')), sprintf($view->translate('Show %s', 'dashboard.dashlet.tooltip'), $view->escape($this->getTitle())), - $view->escape($this->getTitle()) + $view->escape($this->getTitle()), + $view->translate('Dashlet') . ': ' ); return str_replace($searchTokens, $replaceTokens, $this->template); diff --git a/library/Icinga/Web/Widget/FilterEditor.php b/library/Icinga/Web/Widget/FilterEditor.php index 16136a62a..21dd0f04a 100644 --- a/library/Icinga/Web/Widget/FilterEditor.php +++ b/library/Icinga/Web/Widget/FilterEditor.php @@ -678,20 +678,28 @@ class FilterEditor extends AbstractWidget public function render() { if (! $this->preservedUrl()->getParam('modifyFilter')) { - return $this->renderSearch() . $this->shorten($this->filter, 50); + $filterEditor = $this->renderSearch() . $this->shorten($this->filter, 50); + } else { + $filterEditor = $this->renderSearch() + . '
' + . '
  • ' + . $this->renderFilter($this->filter) + . '
' + . '
' + . '' + . '' + . '
' + . '
'; } - return $this->renderSearch() - . '
' - . '
  • ' - . $this->renderFilter($this->filter) - . '
' - . '
' - . '' - . '' - . '
' - . '
'; + + return sprintf( + '
' + . '

%s

%s
', + t('Filters'), + $filterEditor + ); } protected function shorten($string, $length) diff --git a/library/Icinga/Web/Widget/SortBox.php b/library/Icinga/Web/Widget/SortBox.php index 18ed95b86..a1728db4f 100644 --- a/library/Icinga/Web/Widget/SortBox.php +++ b/library/Icinga/Web/Widget/SortBox.php @@ -133,6 +133,13 @@ class SortBox extends AbstractWidget if ($this->request) { $form->populate($this->request->getParams()); } - return $form; + + return sprintf( + '
' + . '

%s

%s%s
', + t('Sort Criteria'), + t('Sort by'), + (string) $form + ); } } diff --git a/library/Icinga/Web/Widget/Tabs.php b/library/Icinga/Web/Widget/Tabs.php index 56bd3404c..202771237 100644 --- a/library/Icinga/Web/Widget/Tabs.php +++ b/library/Icinga/Web/Widget/Tabs.php @@ -19,6 +19,7 @@ class Tabs extends AbstractWidget implements Countable * @var string */ private $baseTpl = <<< 'EOT' +{HEADER}
    {TABS} {DROPDOWN} @@ -26,6 +27,13 @@ class Tabs extends AbstractWidget implements Countable
EOT; + /** + * Template used for the header + * + * @type string + */ + private $headerTpl = '

{TITLE}

'; + /** * Template used for the tabs dropdown * @@ -87,6 +95,13 @@ EOT; */ private $closeTab = true; + /** + * Title of the tab navigation + * + * @type string + */ + private $title; + /** * Set whether the current tab is closable */ @@ -309,11 +324,21 @@ EOT; } $close = $this->closeTab ? $this->renderCloseTab() : ''; - $html = $this->baseTpl; - $html = str_replace('{TABS}', $tabs, $html); - $html = str_replace('{DROPDOWN}', $drop, $html); - $html = str_replace('{CLOSE}', $close, $html); - return $html; + return str_replace( + array( + '{TABS}', + '{DROPDOWN}', + '{CLOSE}', + '{HEADER}' + ), + array( + $tabs, + $drop, + $close, + $this->renderHeader() + ), + $this->baseTpl + ); } public function __toString() @@ -372,4 +397,30 @@ EOT; $tabextension->apply($this); return $this; } + + /** + * Set the title of the tab navigation + * + * @param string $title + * @return self + */ + public function setTitle($title) + { + $this->title = $title; + return $this; + } + + /** + * Render the title into the header template + * + * @return string + */ + public function renderHeader() + { + if (! $this->title) { + return ''; + } + + return str_replace('{TITLE}', $this->title, $this->headerTpl); + } } diff --git a/modules/monitoring/application/controllers/AlertsummaryController.php b/modules/monitoring/application/controllers/AlertsummaryController.php index 3490da9b4..cc1d75193 100644 --- a/modules/monitoring/application/controllers/AlertsummaryController.php +++ b/modules/monitoring/application/controllers/AlertsummaryController.php @@ -44,7 +44,7 @@ class Monitoring_AlertsummaryController extends Controller 'label' => $this->translate('Alert Summary'), 'url' => Url::fromRequest() ) - )->activate('alertsummary'); + )->activate('alertsummary')->setTitle($this->translate('Alertsummary Navigation')); $this->view->title = $this->translate('Alert Summary'); $this->view->intervalBox = $this->createIntervalBox(); @@ -324,6 +324,8 @@ class Monitoring_AlertsummaryController extends Controller public function createHealingChart() { $gridChart = new GridChart(); + $gridChart->title = t('Healing Chart'); + $gridChart->description = t('Notifications and average reaction time per hour.'); $gridChart->alignTopLeft(); $gridChart->setAxisLabel($this->createPeriodDescription(), mt('monitoring', 'Notifications')) @@ -427,7 +429,8 @@ class Monitoring_AlertsummaryController extends Controller 'label' => $this->translate('Notifications'), 'color' => '#07C0D9', 'data' => $notifications, - 'showPoints' => true + 'showPoints' => true, + 'tooltip' => '{title}: {value} {label}' ) ); @@ -436,7 +439,8 @@ class Monitoring_AlertsummaryController extends Controller 'label' => $this->translate('Avg (min)'), 'color' => '#ffaa44', 'data' => $dAvg, - 'showPoints' => true + 'showPoints' => true, + 'tooltip' => t('{title}: {value}m min. reaction time') ) ); @@ -445,7 +449,8 @@ class Monitoring_AlertsummaryController extends Controller 'label' => $this->translate('Max (min)'), 'color' => '#ff5566', 'data' => $dMax, - 'showPoints' => true + 'showPoints' => true, + 'tooltip' => t('{title}: {value}m max. reaction time') ) ); @@ -460,6 +465,8 @@ class Monitoring_AlertsummaryController extends Controller public function createDefectImage() { $gridChart = new GridChart(); + $gridChart->title = t('Defect Chart'); + $gridChart->description = t('Notifications and defects per hour'); $gridChart->alignTopLeft(); $gridChart->setAxisLabel($this->createPeriodDescription(), mt('monitoring', 'Notifications')) @@ -472,7 +479,8 @@ class Monitoring_AlertsummaryController extends Controller 'label' => $this->translate('Notifications'), 'color' => '#07C0D9', 'data' => $this->notificationData, - 'showPoints' => true + 'showPoints' => true, + 'tooltip' => '{title}: {value} {label}' ) ); @@ -481,7 +489,8 @@ class Monitoring_AlertsummaryController extends Controller 'label' => $this->translate('Defects'), 'color' => '#ff5566', 'data' => $this->problemData, - 'showPoints' => true + 'showPoints' => true, + 'tooltip' => '{title}: {value} {label}' ) ); diff --git a/modules/monitoring/application/controllers/ChartController.php b/modules/monitoring/application/controllers/ChartController.php index b01702c04..f19d3f458 100644 --- a/modules/monitoring/application/controllers/ChartController.php +++ b/modules/monitoring/application/controllers/ChartController.php @@ -236,6 +236,9 @@ class Monitoring_ChartController extends Controller $unknownBars[] = array($servicegroup->servicegroup, $servicegroup->services_unknown_unhandled); } $this->view->chart = new GridChart(); + $this->view->chart->title = t('Service Group Chart'); + $this->view->chart->description = t('Contains service states for each service group.'); + $this->view->chart->alignTopLeft(); $this->view->chart->setAxisLabel('', mt('monitoring', 'Services')) ->setXAxis(new StaticAxis()) @@ -292,6 +295,9 @@ class Monitoring_ChartController extends Controller } $tooltip = mt('monitoring', '{title}:
{value} of {sum} hosts are {label}'); $this->view->chart = new GridChart(); + $this->view->chart->title = t('Host Group Chart'); + $this->view->chart->description = t('Contains host states of each service group.'); + $this->view->chart->alignTopLeft(); $this->view->chart->setAxisLabel('', mt('monitoring', 'Hosts')) ->setXAxis(new StaticAxis()) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index e43d64f1d..3fb782856 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -726,6 +726,7 @@ class Monitoring_ListController extends Controller private function createTabs() { $tabs = $this->getTabs(); + $tabs->setTitle($this->translate('Monitoring Navigation')); if (in_array($this->_request->getActionName(), array( 'hosts', 'services', diff --git a/modules/monitoring/application/controllers/ProcessController.php b/modules/monitoring/application/controllers/ProcessController.php index b20bd7576..efca3d520 100644 --- a/modules/monitoring/application/controllers/ProcessController.php +++ b/modules/monitoring/application/controllers/ProcessController.php @@ -29,7 +29,7 @@ class Monitoring_ProcessController extends Controller 'label' => $this->translate('Monitoring Health'), 'url' =>'monitoring/process/info' ) - ); + )->setTitle($this->translate('Process Information')); } /** diff --git a/modules/monitoring/application/controllers/TimelineController.php b/modules/monitoring/application/controllers/TimelineController.php index f1ef32592..4abe53c4b 100644 --- a/modules/monitoring/application/controllers/TimelineController.php +++ b/modules/monitoring/application/controllers/TimelineController.php @@ -22,7 +22,7 @@ class Monitoring_TimelineController extends Controller 'label' => $this->translate('Timeline'), 'url' => Url::fromRequest() ) - )->activate('timeline'); + )->activate('timeline')->setTitle($this->translate('Timeline Navigation')); $this->view->title = $this->translate('Timeline'); // TODO: filter for hard_states (precedence adjustments necessary!) diff --git a/modules/monitoring/application/forms/Config/BackendConfigForm.php b/modules/monitoring/application/forms/Config/BackendConfigForm.php index 3014974a3..62e3858a9 100644 --- a/modules/monitoring/application/forms/Config/BackendConfigForm.php +++ b/modules/monitoring/application/forms/Config/BackendConfigForm.php @@ -43,8 +43,11 @@ class BackendConfigForm extends ConfigForm { $resources = array(); foreach ($resourceConfig as $name => $resource) { - if ($resource->type === 'db' || $resource->type === 'livestatus') { - $resources[$resource->type === 'db' ? 'ido' : 'livestatus'][$name] = $name; +// if ($resource->type === 'db' || $resource->type === 'livestatus') { +// $resources[$resource->type === 'db' ? 'ido' : 'livestatus'][$name] = $name; +// } + if ($resource->type === 'db') { + $resources['ido'][$name] = $name; } } @@ -183,13 +186,19 @@ class BackendConfigForm extends ConfigForm { $resourceType = isset($formData['type']) ? $formData['type'] : key($this->resources); + if ($resourceType === 'livestatus') { + throw new ConfigurationError( + 'We\'ve disabled livestatus support for now because it\'s not feature complete yet' + ); + } + $resourceTypes = array(); if ($resourceType === 'ido' || array_key_exists('ido', $this->resources)) { $resourceTypes['ido'] = 'IDO Backend'; } - if ($resourceType === 'livestatus' || array_key_exists('livestatus', $this->resources)) { - $resourceTypes['livestatus'] = 'Livestatus'; - } +// if ($resourceType === 'livestatus' || array_key_exists('livestatus', $this->resources)) { +// $resourceTypes['livestatus'] = 'Livestatus'; +// } $this->addElement( 'checkbox', diff --git a/modules/monitoring/application/forms/Setup/BackendPage.php b/modules/monitoring/application/forms/Setup/BackendPage.php index d8d4c7fd0..f2df42a1f 100644 --- a/modules/monitoring/application/forms/Setup/BackendPage.php +++ b/modules/monitoring/application/forms/Setup/BackendPage.php @@ -51,7 +51,7 @@ class BackendPage extends Form if (Platform::hasMysqlSupport() || Platform::hasPostgresqlSupport()) { $resourceTypes['ido'] = 'IDO'; } - $resourceTypes['livestatus'] = 'Livestatus'; + // $resourceTypes['livestatus'] = 'Livestatus'; $this->addElement( 'select', diff --git a/modules/monitoring/application/views/scripts/alertsummary/index.phtml b/modules/monitoring/application/views/scripts/alertsummary/index.phtml index dbfff6433..3281f3ec8 100644 --- a/modules/monitoring/application/views/scripts/alertsummary/index.phtml +++ b/modules/monitoring/application/views/scripts/alertsummary/index.phtml @@ -1,6 +1,9 @@
tabs ?>
+

+ translate('Filters'); ?> +

widget('limiter') ?> @@ -8,25 +11,33 @@
- +

+ translate('Alert summary'); ?> +

-

translate('Notifications and Problems'); ?>

+

+ translate('Notifications and Problems'); ?> +

render(); ?>
-

translate('Time to Reaction (Ack, Recover)'); ?>

+

+ translate('Time to Reaction (Ack, Recover)'); ?> +

render(); ?>
-

translate('Trend'); ?>

+

+ translate('Trend'); ?> +

@@ -53,7 +64,9 @@
recentAlerts): ?> -

translate('Top 5 Recent Alerts'); ?>

+

+ translate('Top 5 Recent Alerts'); ?> +

@@ -66,7 +79,9 @@
-

translate('History'); ?>

+

+ translate('History'); ?> +

partial('list/notifications.phtml', array( diff --git a/modules/monitoring/application/views/scripts/host/show.phtml b/modules/monitoring/application/views/scripts/host/show.phtml index 867692301..f490c25f9 100644 --- a/modules/monitoring/application/views/scripts/host/show.phtml +++ b/modules/monitoring/application/views/scripts/host/show.phtml @@ -3,6 +3,7 @@ render('partials/host/servicesummary.phtml') ?>
+

translate('Host Detail Information') ?>

render('show/components/output.phtml') ?> render('show/components/grapher.phtml') ?> diff --git a/modules/monitoring/application/views/scripts/list/comments.phtml b/modules/monitoring/application/views/scripts/list/comments.phtml index 6f49bf4a8..d41399984 100644 --- a/modules/monitoring/application/views/scripts/list/comments.phtml +++ b/modules/monitoring/application/views/scripts/list/comments.phtml @@ -1,15 +1,14 @@ compact): ?> -
- tabs->render($this); ?> -
- translate('Sort by'); ?> sortControl->render($this); ?> -
- widget('limiter', array('url' => $this->url, 'max' => $comments->count())); ?> - paginationControl($comments, null, null, array('preserve' => $this->preserve)); ?> -
+
+ tabs ?> + sortControl ?> + widget('limiter', array('url' => $this->url, 'max' => $comments->count())); ?> + paginationControl($comments, null, null, array('preserve' => $this->preserve)); ?> +
+

translate('Comments') ?>

translate('No comments matching the filter'); ?>
diff --git a/modules/monitoring/application/views/scripts/list/contactgroups.phtml b/modules/monitoring/application/views/scripts/list/contactgroups.phtml index a44b388b7..b00e78031 100644 --- a/modules/monitoring/application/views/scripts/list/contactgroups.phtml +++ b/modules/monitoring/application/views/scripts/list/contactgroups.phtml @@ -4,6 +4,9 @@
+

+ translate('Contact Groups'); ?> +

- tabs ?> -
- sortControl->render($this); ?> +compact): ?> +
+ tabs ?> + sortControl ?> + widget('limiter', array('url' => $this->url, 'max' => $contacts->count())); ?> + paginationControl($contacts, null, null, array('preserve' => $this->preserve)); ?>
- paginationControl($contacts, null, null, array('preserve' => $this->preserve)); ?> -
+
+

translate('Contacts') ?>

translate('No contacts matching the filter'); diff --git a/modules/monitoring/application/views/scripts/list/downtimes.phtml b/modules/monitoring/application/views/scripts/list/downtimes.phtml index 1fbaa713f..5ad554f99 100644 --- a/modules/monitoring/application/views/scripts/list/downtimes.phtml +++ b/modules/monitoring/application/views/scripts/list/downtimes.phtml @@ -4,23 +4,17 @@ use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Service; ?> - compact): ?> -
- tabs->render($this); ?> -
- translate('Sort by'); ?> sortControl->render($this); ?> - filterEditor): ?> - filterPreview ?> - -
- widget('limiter', array('url' => $this->url, 'max' => $downtimes->count())); ?> - paginationControl($downtimes, null, null, array('preserve' => $this->preserve)); ?> -
+
+ tabs ?> + sortControl ?> + widget('limiter', array('url' => $this->url, 'max' => $downtimes->count())); ?> + paginationControl($downtimes, null, null, array('preserve' => $this->preserve)); ?> +
-
filterEditor ?> +

translate('Downtimes'); ?>

translate('No active downtimes'); ?>
diff --git a/modules/monitoring/application/views/scripts/list/eventgrid.phtml b/modules/monitoring/application/views/scripts/list/eventgrid.phtml index 1af75caf9..6bf0b800b 100644 --- a/modules/monitoring/application/views/scripts/list/eventgrid.phtml +++ b/modules/monitoring/application/views/scripts/list/eventgrid.phtml @@ -2,18 +2,21 @@ use Icinga\Data\Filter\Filter; use Icinga\Web\Widget\Chart\HistoryColorGrid; ?> - - - +
tabs->render($this); ?>
+

+ translate('Filters'); ?> +

- - -
+
+

translate('Event Grid'); ?>

+ +
+ - compact): ?>
tabs ?> -
-
- translate('Sort by') ?> sortControl ?> -
-
- + sortControl ?> widget('limiter', array('url' => $this->url, 'max' => $this->history->count())); ?> paginationControl($history, null, null, array('preserve' => $this->preserve)); ?> -
- -
-filterEditor ?> + filterEditor ?> +

translate('Event History') ?>

+ +
+ + + translate('No history events matching the filter') ?>
diff --git a/modules/monitoring/application/views/scripts/list/hostgroups.phtml b/modules/monitoring/application/views/scripts/list/hostgroups.phtml index c702197b2..c8f5b2de2 100644 --- a/modules/monitoring/application/views/scripts/list/hostgroups.phtml +++ b/modules/monitoring/application/views/scripts/list/hostgroups.phtml @@ -3,14 +3,13 @@
tabs ?> -
- translate('Sort by'); ?> sortControl->render($this); ?> -
+ sortControl->render($this); ?> widget('limiter')->setMaxLimit(count($hostgroups)); ?> paginationControl($hostgroups, null, null, array('preserve' => $this->preserve)); ?>
filterEditor; ?> +

translate('Host Groups') ?>

compact): ?>
render('list/components/selectioninfo.phtml') ?> render('list/components/hostssummary.phtml') ?> - translate('Sort by') ?> sortControl->render($this) ?>
- +sortControl->render($this) ?> widget('limiter')->setMaxLimit($this->hosts->count()) ?> paginationControl($hosts, null, null, array('preserve' => $this->preserve)) ?> selectionToolbar('multi', $this->href('monitoring/hosts/show?' . $this->filter->toQueryString())) ?> @@ -19,6 +18,7 @@ if ($this->compact): ?>
filterEditor ?> +

translate('Hosts') ?>

count() === 0) { return; } ?> - - compact): ?>
tabs ?> -
- translate('Sort by') ?> sortControl->render($this) ?> -
+ sortControl->render($this) ?> widget('limiter') ?> paginationControl($notifications, null, null, array('preserve' => $this->preserve)) ?>
- -
+

translate('Notifications'); ?>

+ +
+ translate('No notifications matching the filter') ?> diff --git a/modules/monitoring/application/views/scripts/list/servicegrid.phtml b/modules/monitoring/application/views/scripts/list/servicegrid.phtml index a102c36eb..d4b5a4074 100644 --- a/modules/monitoring/application/views/scripts/list/servicegrid.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegrid.phtml @@ -6,12 +6,11 @@ use Icinga\Module\Monitoring\Object\Service; compact): ?>
tabs; ?> -
- translate('Sort by'); ?> sortControl; ?> -
+ sortControl; ?>
+

translate('Service Grid') ?>

tabs ?> -
- translate('Sort by'); ?> sortControl->render($this); ?> -
+ sortControl->render($this); ?> widget('limiter')->setMaxLimit(count($servicegroups)); ?> paginationControl($servicegroups, null, null, array('preserve' => $this->preserve)); ?>
filterEditor; ?> +

translate('Service Groups') ?>

compact): ?>
render('list/components/selectioninfo.phtml') ?> render('list/components/servicesummary.phtml') ?> -
-translate('Sort by') ?> sortControl ?> -
+sortControl ?> limit === 0): ?> widget('limiter') ?> @@ -24,6 +22,7 @@ if (!$this->compact): ?>
filterEditor ?> +

translate('Services') ?>

diff --git a/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml b/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml index f5edd0213..f892df6f4 100644 --- a/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/host/objects-header.phtml @@ -3,7 +3,9 @@ 0): ?>
- translatePlural('Host (%u)', 'Hosts (%u)', $hostCount), $hostCount); ?> +

+ translatePlural('Host (%u)', 'Hosts (%u)', $hostCount), $hostCount); ?> +

  diff --git a/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml b/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml index 1ac27b934..6389d992f 100644 --- a/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml +++ b/modules/monitoring/application/views/scripts/partials/service/objects-header.phtml @@ -4,7 +4,9 @@ 0): ?>
- translatePlural('Service (%u)', 'Services (%u)', $serviceCount), $serviceCount); ?> +

+ translatePlural('Service (%u)', 'Services (%u)', $serviceCount), $serviceCount); ?> +

  diff --git a/modules/monitoring/application/views/scripts/process/info.phtml b/modules/monitoring/application/views/scripts/process/info.phtml index 92bb6cb63..639b5ebc0 100644 --- a/modules/monitoring/application/views/scripts/process/info.phtml +++ b/modules/monitoring/application/views/scripts/process/info.phtml @@ -9,15 +9,23 @@ $cp = $this->checkPerformance()->create($this->checkperformance);
+

+ translate('Monitoring Health'); ?> +

+
-

translate('Feature Commands') ?>

+

+ translate('Feature Commands') ?> +

toggleFeaturesForm ?>
-

translate('Process Info') ?>

+

+ translate('Process Info') ?> +

@@ -68,9 +76,13 @@ $cp = $this->checkPerformance()->create($this->checkperformance);
-

translate('Performance Info') ?>

+

+ translate('Performance Info') ?> +

-

translate('Object summaries') ?>

+

+ translate('Object summaries') ?> +

@@ -118,7 +130,9 @@ $cp = $this->checkPerformance()->create($this->checkperformance);
-

translate('Active checks') ?>

+

+ translate('Active checks') ?> +

@@ -148,7 +162,9 @@ $cp = $this->checkPerformance()->create($this->checkperformance);
-

translate('Passive checks') ?>

+

+ translate('Passive checks') ?> +

diff --git a/modules/monitoring/application/views/scripts/tactical/index.phtml b/modules/monitoring/application/views/scripts/tactical/index.phtml index 3882b27b3..897ef9776 100644 --- a/modules/monitoring/application/views/scripts/tactical/index.phtml +++ b/modules/monitoring/application/views/scripts/tactical/index.phtml @@ -4,6 +4,7 @@
+

translate('Tactical Overview') ?>

statusSummary->hosts_down || $this->statusSummary->hosts_unreachable): ?> render('tactical/components/problem_hosts.phtml'); ?> diff --git a/modules/monitoring/application/views/scripts/timeline/index.phtml b/modules/monitoring/application/views/scripts/timeline/index.phtml index 6557b4a28..a9b5666f6 100644 --- a/modules/monitoring/application/views/scripts/timeline/index.phtml +++ b/modules/monitoring/application/views/scripts/timeline/index.phtml @@ -10,6 +10,9 @@ $firstRow = !$beingExtended;
tabs ?>
+

+ translate('Filters') ?> +

@@ -22,6 +25,7 @@ $firstRow = !$beingExtended;
+

translate('Timeline'); ?>

diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 387df892b..26cd5bc38 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -198,3 +198,8 @@ hr.command-separator { border: none; border-bottom: 2px solid @colorPetrol; } + +.sort-box { + float: right; + margin-right: 1em; +} \ No newline at end of file diff --git a/public/css/icinga/menu.less b/public/css/icinga/menu.less index c33c6670c..3c733db6e 100644 --- a/public/css/icinga/menu.less +++ b/public/css/icinga/menu.less @@ -270,7 +270,7 @@ a:focus { /* Accessibility Skip Links */ .skip-links { - position: absolute; + position: relative; opacity: 1; ul { list-style-type: none; @@ -286,7 +286,6 @@ a:focus { left: -999em; box-sizing: content-box; width: 10.4em !important; - top: 0em; text-align: left !important; padding: 0.8em; background-color: white; @@ -301,5 +300,8 @@ a:focus { } } .skip-links-inline { - margin-top: -3.5em; + ul > li > a { + width: 14em !important; + top: -3em; + } } diff --git a/public/js/icinga/behavior/tooltip.js b/public/js/icinga/behavior/tooltip.js index b08b1f3c1..c9a64257f 100644 --- a/public/js/icinga/behavior/tooltip.js +++ b/public/js/icinga/behavior/tooltip.js @@ -27,7 +27,7 @@ var $el = $(this); $el.attr('title', $el.data('title-rich') || $el.attr('title')); }); - $('svg rect.chart-data[title]', el).tipsy({ gravity: 'se', html: true }); + $('svg .chart-data', el).tipsy({ gravity: 'se', html: true }); $('.historycolorgrid a[title]', el).tipsy({ gravity: 's', offset: 2 }); $('img.icon[title]', el).tipsy({ gravity: $.fn.tipsy.autoNS, offset: 2 }); $('[title]', el).tipsy({ gravity: $.fn.tipsy.autoNS, delayIn: 500 }); diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index 098aaa88f..39a2a3de4 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -337,21 +337,29 @@ handleAnchor: function(query) { var $element = $(query); if ($element.length > 0) { - // Try to find the first header. It is more pleasant to users - // to select the header instead a container - var $header = $element.find(':header:first'); - if ($header.length > 0) { - $element = $header; - } else { - var $input = $element.find(':header:first'); - if ($input.length > 0) { - $element = $input - } + // TODO(mh): Some elements are missing to place the right focus + // This is a fixed workarround until all header took place + + var $item = $element.find(':header:first').nextUntil(':header:first').next(); + if ($item.length > 0) { + $element = $item; } + + /* + var focusQueries = ['h1:first', ':header:first', ':input:first']; + $.each(focusQueries, function(index,q) { + var $item = $element.find(q); + if ($item.length > 0) { + $element = $item; + return false; + } + }); + */ + // If we want to focus an element which has no tabindex // add one that we can focus is if ($element.prop('tabindex') < 0) { - $element.prop('tabindex', 0); + $element.prop('tabindex', '-1'); } $element.focus(); }