Implement on-the-fly less compilation

refs #4892
This commit is contained in:
Marius Hein 2013-10-16 12:00:09 +02:00
parent ff58d1b675
commit 460e0fe242
7 changed files with 219 additions and 105 deletions

View File

@ -141,10 +141,9 @@ class StaticController extends ActionController
*/
private function setCacheHeader($maxAge)
{
$response = $this->getResponse();
$response->setHeader('Cache-Control', 'max-age=3600', true);
$response->setHeader('Pragma', 'cache', true);
$response->setHeader(
$this->_response->setHeader('Cache-Control', 'max-age=3600', true);
$this->_response->setHeader('Pragma', 'cache', true);
$this->_response->setHeader(
'Expires',
gmdate(
'D, d M Y H:i:s',
@ -153,5 +152,31 @@ class StaticController extends ActionController
true
);
}
public function stylesheetAction()
{
$lessCompiler = new \Icinga\Web\LessCompiler();
$moduleManager = Icinga::app()->getModuleManager();
$publicDir = realpath(dirname($_SERVER['SCRIPT_FILENAME']));
$lessCompiler->addItem($publicDir . '/css/vendor');
$lessCompiler->addItem($publicDir . '/css/icinga');
foreach ($moduleManager->getLoadedModules() as $moduleName) {
$cssDir = $moduleName->getCssDir();
if (is_dir($cssDir)) {
$lessCompiler->addItem($cssDir);
}
}
$this->_response->setHeader('Content-Type', 'text/css');
$this->setCacheHeader(3600);
$lessCompiler->printStack();
return;
}
}
// @codingStandardsIgnoreEnd

View File

@ -16,16 +16,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<!-- Bootstrap and components -->
<link rel="stylesheet" href="<?= $this->baseUrl('css/vendor/bootstrap/bootstrap.min.css') ?>" media="screen">
<link rel="stylesheet" href="<?= $this->baseUrl('css/main.css') ?>">
<link rel="stylesheet" href="<?= $this->baseUrl('css/vendor/bootstrap/datetimepicker.min.css') ?>">
<!--
Not used until styling is clear (see #4550)
<link rel="stylesheet" href="<?= $this->baseUrl('css.php') ?>">
-->
<link rel="stylesheet" href="<?= $this->baseUrl('static/stylesheet') ?>" media="screen">
<script type="text/javascript">
var base_url = '<?= $this->baseUrl() ?>';

View File

@ -197,9 +197,9 @@ class Module
*
* @return string
*/
public function getCssFilename()
public function getCssDir()
{
return $this->cssdir . '/module.less';
return $this->cssdir;
}
/**

View File

@ -0,0 +1,121 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Web;
use \RecursiveDirectoryIterator;
use \RecursiveIteratorIterator;
use \RegexIterator;
use \RecursiveRegexIterator;
/**
* Less compiler prints files or directories to stdout
*/
class LessCompiler
{
/**
* Collection of items: File or directories
*
* @var array
*/
private $items = array();
/**
* lessphp compiler
*
* @var \lessc
*/
private $lessc;
/**
* Create a new instance
*/
public function __construct()
{
require_once 'vendor/lessphp/lessc.inc.php';
$this->lessc = new \lessc();
}
/**
* Add usable style item to stack
*
* @param string $item File or directory
*/
public function addItem($item)
{
$this->items[] = $item;
}
/**
* Compile and print a single file
*
* @param string $file
*/
public function printFile($file)
{
$ext = pathinfo($file, PATHINFO_EXTENSION);
echo PHP_EOL. '/* CSS: ' . $file . ' */' . PHP_EOL;
if ($ext === 'css') {
readfile($file);
} elseif ($ext === 'less') {
echo $this->lessc->compileFile($file);
}
echo PHP_EOL;
}
/**
* Compile and print a path content (recursive)
*
* @param string $path
*/
public function printPathRecursive($path)
{
$directoryInterator = new RecursiveDirectoryIterator($path);
$iterator = new RecursiveIteratorIterator($directoryInterator);
$filteredIterator = new RegexIterator($iterator, '/\.(css|less)$/', RecursiveRegexIterator::GET_MATCH);
foreach ($filteredIterator as $file => $extension) {
$this->printFile($file);
}
}
/**
* Compile and print the whole item stack
*/
public function printStack()
{
foreach ($this->items as $item) {
if (is_dir($item)) {
$this->printPathRecursive($item);
} elseif (is_file($item)) {
$this->printFile($item);
}
}
}
}

View File

@ -1,23 +0,0 @@
<?php
use Icinga\Application\EmbeddedWeb;
require_once dirname(__FILE__) . '/../library/Icinga/Application/EmbeddedWeb.php';
$app = EmbeddedWeb::start(dirname(__FILE__) . '/../config/');
require_once 'vendor/lessphp/lessc.inc.php';
header('Content-type: text/css');
$less = new lessc;
$cssdir = dirname(__FILE__) . '/css';
echo $less->compileFile($cssdir . '/base.less');
foreach ($app->getModuleManager()->getLoadedModules() as $name => $module) {
if ($module->hasCss()) {
echo $less->compile(
'.icinga-module.module-'
. $name
. " {\n"
. file_get_contents($module->getCssFilename())
. "}\n\n"
);
}
}

View File

@ -6,258 +6,258 @@
}
.icinga-icon-acknowledgement {
background: transparent url("../img/icons/acknowledgement.png") center center no-repeat;
background: transparent url("../../img/icons/acknowledgement.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-comment {
background: transparent url("../img/icons/comment.png") center center no-repeat;
background: transparent url("../../img/icons/comment.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-create {
background: transparent url("../img/icons/create.png") center center no-repeat;
background: transparent url("../../img/icons/create.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-dashboard {
background: transparent url("../img/icons/dashboard.png") center center no-repeat;
background: transparent url("../../img/icons/dashboard.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-disabled {
background: transparent url("../img/icons/disabled.png") center center no-repeat;
background: transparent url("../../img/icons/disabled.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-edit {
background: transparent url("../img/icons/edit.png") center center no-repeat;
background: transparent url("../../img/icons/edit.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-error {
background: transparent url("../img/icons/error.png") center center no-repeat;
background: transparent url("../../img/icons/error.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-flapping {
background: transparent url("../img/icons/flapping.png") center center no-repeat;
background: transparent url("../../img/icons/flapping.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-in-downtime {
background: transparent url("../img/icons/in_downtime.png") center center no-repeat;
background: transparent url("../../img/icons/in_downtime.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-remove {
background: transparent url("../img/icons/remove.png") center center no-repeat;
background: transparent url("../../img/icons/remove.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-save {
background: transparent url("../img/icons/save.png") center center no-repeat;
background: transparent url("../../img/icons/save.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-service {
background: transparent url("../img/icons/service.png") center center no-repeat;
background: transparent url("../../img/icons/service.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-submit {
background: transparent url("../img/icons/submit.png") center center no-repeat;
background: transparent url("../../img/icons/submit.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-unhandled {
background: transparent url("../img/icons/unhandled.png") center center no-repeat;
background: transparent url("../../img/icons/unhandled.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-user {
background: transparent url("../img/icons/user.png") center center no-repeat;
background: transparent url("../../img/icons/user.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-active-checks-disabled {
background: transparent url("../img/icons/active_checks_disabled.png") center center no-repeat;
background: transparent url("../../img/icons/active_checks_disabled.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-active-passive-checks-disabled {
background: transparent url("../img/icons/active_passive_checks_disabled.png") center center no-repeat;
background: transparent url("../../img/icons/active_passive_checks_disabled.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-notification {
background: transparent url("../img/icons/notification.png") center center no-repeat;
background: transparent url("../../img/icons/notification.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-notification-disabled {
background: transparent url("../img/icons/notification_disabled.png") center center no-repeat;
background: transparent url("../../img/icons/notification_disabled.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-csv {
background: transparent url("../img/icons/csv.png") center center no-repeat;
background: transparent url("../../img/icons/csv.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-pdf {
background: transparent url("../img/icons/pdf.png") center center no-repeat;
background: transparent url("../../img/icons/pdf.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-json {
background: transparent url("../img/icons/json.png") center center no-repeat;
background: transparent url("../../img/icons/json.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-downtime-start {
background: transparent url("../img/icons/downtime_start.png") center center no-repeat;
background: transparent url("../../img/icons/downtime_start.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-downtime-end {
background: transparent url("../img/icons/downtime_end.png") center center no-repeat;
background: transparent url("../../img/icons/downtime_end.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-hostgroup {
background: transparent url("../img/icons/hostgroup.png") center center no-repeat;
background: transparent url("../../img/icons/hostgroup.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-servicegroup {
background: transparent url("../img/icons/servicegroup.png") center center no-repeat;
background: transparent url("../../img/icons/servicegroup.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-host {
background: transparent url("../img/icons/host.png") center center no-repeat;
background: transparent url("../../img/icons/host.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-service {
background: transparent url("../img/icons/service.png") center center no-repeat;
background: transparent url("../../img/icons/service.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-success {
background: transparent url("../img/icons/success.png") center center no-repeat;
background: transparent url("../../img/icons/success.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-history {
background: transparent url("../img/icons/history.png") center center no-repeat;
background: transparent url("../../img/icons/history.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-reschedule {
background: transparent url("../img/icons/reschedule.png") center center no-repeat;
background: transparent url("../../img/icons/reschedule.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-softstate {
background: transparent url("../img/icons/softstate.png") center center no-repeat;
background: transparent url("../../img/icons/softstate.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-next {
background: transparent url("../img/icons/next.png") center center no-repeat;
background: transparent url("../../img/icons/next.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-prev {
background: transparent url("../img/icons/prev.png") center center no-repeat;
background: transparent url("../../img/icons/prev.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-refresh {
background: transparent url("../img/icons/refresh.png") center center no-repeat;
background: transparent url("../../img/icons/refresh.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-expand {
background: transparent url("../img/icons/expand.png") center center no-repeat;
background: transparent url("../../img/icons/expand.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;
}
.icinga-icon-search {
background: transparent url("../img/icons/search.png") center center no-repeat;
background: transparent url("../../img/icons/search.png") center center no-repeat;
display: inline-block;
width: 16px;
height: 16px;

View File

@ -39,7 +39,7 @@ body { padding-top: 51px; }
}
.icinga-logo {
background: transparent url("../img/logo_icinga.png") center center no-repeat;
background: transparent url("../../img/logo_icinga.png") center center no-repeat;
width: 94px;
height: 33px;
display: block;
@ -452,39 +452,39 @@ select.input-sm {
}
.icon-flapping {
background-image: url('../img/icons/flapping.png');
background-image: url('../../img/icons/flapping.png');
background-repeat: no-repeat;
}
.icon-comment {
background-image: url('../img/icons/comment.png');
background-image: url('../../img/icons/comment.png');
background-repeat: no-repeat;
}
.icon-unhandled {
background-image: url('../img/icons/unhandled.png');
background-image: url('../../img/icons/unhandled.png');
background-repeat: no-repeat;
}
.icon-host {
background-image: url('../img/icons/host.png');
background-image: url('../../img/icons/host.png');
background-repeat: no-repeat;
}
.icon-acknowledgement {
background-image: url('../img/icons/acknowledgement.png');
background-image: url('../../img/icons/acknowledgement.png');
background-repeat: no-repeat;
}
.icon-remove {
background-image: url('../img/icons/remove.png');
background-image: url('../../img/icons/remove.png');
background-repeat: no-repeat;
}
.icon-submit {
background-image: url('../img/icons/submit.png');
background-image: url('../../img/icons/submit.png');
background-repeat: no-repeat;
}
.icon-create {
background-image: url('../img/icons/create.png');
background-image: url('../../img/icons/create.png');
background-repeat: no-repeat;
}
.icon-dashboard {
background-image: url('../img/icons/dashboard.png');
background-image: url('../../img/icons/dashboard.png');
background-repeat: no-repeat;
}
.icon-disable {
@ -492,31 +492,31 @@ select.input-sm {
background-repeat: no-repeat;
}
.icon-edit {
background-image: url('../img/icons/edit.png');
background-image: url('../../img/icons/edit.png');
background-repeat: no-repeat;
}
.icon-error {
background-image: url('../img/icons/error.png');
background-image: url('../../img/icons/error.png');
background-repeat: no-repeat;
}
.icon-downtime {
background-image: url('../img/icons/in_downtime.png');
background-image: url('../../img/icons/in_downtime.png');
background-repeat: no-repeat;
}
.icon-save {
background-image: url('../img/icons/save.png');
background-image: url('../../img/icons/save.png');
background-repeat: no-repeat;
}
.icon-service {
background-image: url('../img/icons/service.png');
background-image: url('../../img/icons/service.png');
background-repeat: no-repeat;
}
.icon-user {
background-image: url('../img/icons/user.png');
background-image: url('../../img/icons/user.png');
background-repeat: no-repeat;
}
.icon-reschedule {
background-image: url('../img/icons/reschedule.png');
background-image: url('../../img/icons/reschedule.png');
background-repeat: no-repeat;
}
@ -741,45 +741,45 @@ ul.icinga-subnavigation {
.nav-icon-hosts {
background-image: url('../img/icons/host_petrol.png');
background-image: url('../../img/icons/host_petrol.png');
background-repeat: no-repeat;
background-position: 19px 50%;
}
.nav-icon-services {
background-image: url('../img/icons/service_petrol.png');
background-image: url('../../img/icons/service_petrol.png');
background-repeat: no-repeat;
background-position: 19px 50%;
}
.nav-icon-downtimes {
background-image: url('../img/icons/in_downtime_petrol.png');
background-image: url('../../img/icons/in_downtime_petrol.png');
background-repeat: no-repeat;
background-position: 19px 50%;
}
.nav-icon-notifications {
background-image: url('../img/icons/notification_petrol.png');
background-image: url('../../img/icons/notification_petrol.png');
background-repeat: no-repeat;
background-position: 19px 20px;
}
.nav-icon-comments {
background-image: url('../img/icons/comment_petrol.png');
background-image: url('../../img/icons/comment_petrol.png');
background-repeat: no-repeat;
background-position: 19px 50%;
}
.nav-icon-dashboard {
background-image: url('../img/icons/dashboard_petrol.png');
background-image: url('../../img/icons/dashboard_petrol.png');
background-repeat: no-repeat;
background-position: 19px 50%;
}
.nav-icon-configuration {
background-image: url('../img/icons/configuration_petrol.png');
background-image: url('../../img/icons/configuration_petrol.png');
background-repeat: no-repeat;
background-position: 19px 50%;
}
.subnav-icon-configuration {
background-image: url('../img/icons/configuration_petrol.png');
background-image: url('../../img/icons/configuration_petrol.png');
background-repeat: no-repeat;
background-position: 19px 50%;
}
@ -901,7 +901,7 @@ ul.icinga-subnavigation {
background-attachment: scroll;
background-clip: border-box;
background-color: rgba(0, 0, 0, 0);
background-image: url("../img/icons/user.png");
background-image: url("../../img/icons/user.png");
background-origin: padding-box;
background-position: center center;
background-repeat: no-repeat;
@ -920,7 +920,7 @@ ul.icinga-subnavigation {
}
.icinga-navbar-search {
background-image: url('../img/icons/search.png');
background-image: url('../../img/icons/search.png');
background-repeat: no-repeat;
background-position: 5px 50%;
padding-left: 25px !important;
@ -935,14 +935,14 @@ ul.icinga-subnavigation {
.icinga-navbar-hosts-container {
background-image: url('../img/icons/host.png');
background-image: url('../../img/icons/host.png');
background-repeat: no-repeat;
background-position: 5px 50%;
padding-left: 30px !important;
margin-top: 15px;
}
.icinga-navbar-services-container {
background-image: url('../img/icons/service.png');
background-image: url('../../img/icons/service.png');
background-repeat: no-repeat;
background-position: 5px 50%;
padding-left: 25px !important;