diff --git a/ajax/ajax_configSave.php b/ajax/ajax_configSave.php index dd009877..f4a33d63 100644 --- a/ajax/ajax_configSave.php +++ b/ajax/ajax_configSave.php @@ -47,6 +47,7 @@ $doActionOnClose = "doAction($actionId,'',$activeTab);"; if ($actionId === SP\Controller\ActionsInterface::ACTION_CFG_GENERAL) { $siteLang = SP\Request::analyze('sitelang'); + $siteTheme = SP\Request::analyze('sitetheme'); $sessionTimeout = SP\Request::analyze('session_timeout', 300); $logEnabled = SP\Request::analyze('log_enabled', false, false, true); $debugEnabled = SP\Request::analyze('debug', false, false, true); @@ -147,6 +148,7 @@ if ($actionId === SP\Controller\ActionsInterface::ACTION_CFG_GENERAL) { SP\Config::setValue('account_link', $accountLinkEnabled); SP\Config::setValue('account_count', $accountCount); SP\Config::setValue('sitelang', $siteLang); + SP\Config::setValue('sitetheme', $siteTheme); SP\Config::setValue('session_timeout', $sessionTimeout); SP\Config::setValue('log_enabled', $logEnabled); SP\Config::setValue('debug', $debugEnabled); diff --git a/css/chosen-sprite.png b/css/chosen-sprite.png index 3611ae4a..c57da70b 100644 Binary files a/css/chosen-sprite.png and b/css/chosen-sprite.png differ diff --git a/css/chosen-sprite@2x.png b/css/chosen-sprite@2x.png new file mode 100644 index 00000000..6b505452 Binary files /dev/null and b/css/chosen-sprite@2x.png differ diff --git a/css/chosen.css b/css/chosen.css index 8e10bd59..e7ea0922 100644 --- a/css/chosen.css +++ b/css/chosen.css @@ -1,23 +1,37 @@ +/*! +Chosen, a Select Box Enhancer for jQuery and Prototype +by Patrick Filler for Harvest, http://getharvest.com + +Version 1.4.2 +Full source at https://github.com/harvesthq/chosen +Copyright (c) 2011-2015 Harvest http://getharvest.com + +MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md +This file is generated by `grunt build`, do not edit it by hand. +*/ + /* @group Base */ .chosen-container { position: relative; display: inline-block; vertical-align: middle; - font-size: 12px; + font-size: 13px; zoom: 1; *display: inline; -webkit-user-select: none; -moz-user-select: none; user-select: none; } +.chosen-container * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} .chosen-container .chosen-drop { position: absolute; top: 100%; left: -9999px; z-index: 1010; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; width: 100%; border: 1px solid #aaa; border-top: 0; @@ -30,6 +44,19 @@ .chosen-container a { cursor: pointer; } +.chosen-container .search-choice .group-name, .chosen-container .chosen-single .group-name { + margin-right: 4px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-weight: normal; + color: #999999; +} +.chosen-container .search-choice .group-name:after, .chosen-container .chosen-single .group-name:after { + content: ":"; + padding-left: 2px; + vertical-align: top; +} /* @end */ /* @group Single Chosen */ @@ -38,7 +65,7 @@ display: block; overflow: hidden; padding: 0 0 0 8px; - height: 23px; + height: 25px; border: 1px solid #aaa; border-radius: 5px; background-color: #fff; @@ -105,9 +132,6 @@ white-space: nowrap; } .chosen-container-single .chosen-search input[type="text"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; margin: 1px 0; padding: 4px 20px 4px 5px; width: 100%; @@ -115,11 +139,7 @@ outline: 0; border: 1px solid #aaa; background: white url('chosen-sprite.png') no-repeat 100% -20px; - background: url('chosen-sprite.png') no-repeat 100% -20px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); - background: url('chosen-sprite.png') no-repeat 100% -20px, -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%); - background: url('chosen-sprite.png') no-repeat 100% -20px, -moz-linear-gradient(#eeeeee 1%, #ffffff 15%); - background: url('chosen-sprite.png') no-repeat 100% -20px, -o-linear-gradient(#eeeeee 1%, #ffffff 15%); - background: url('chosen-sprite.png') no-repeat 100% -20px, linear-gradient(#eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat 100% -20px; font-size: 1em; font-family: sans-serif; line-height: normal; @@ -138,6 +158,7 @@ /* @end */ /* @group Results */ .chosen-container .chosen-results { + color: #444; position: relative; overflow-x: hidden; overflow-y: auto; @@ -152,6 +173,8 @@ padding: 5px 6px; list-style: none; line-height: 15px; + word-wrap: break-word; + -webkit-touch-callout: none; } .chosen-container .chosen-results li.active-result { display: list-item; @@ -172,6 +195,7 @@ color: #fff; } .chosen-container .chosen-results li.no-results { + color: #777; display: list-item; background: #f4f4f4; } @@ -193,11 +217,8 @@ .chosen-container-multi .chosen-choices { position: relative; overflow: hidden; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; margin: 0; - padding: 0; + padding: 0 5px; width: 100%; height: auto !important; height: 1%; @@ -221,39 +242,42 @@ } .chosen-container-multi .chosen-choices li.search-field input[type="text"] { margin: 1px 0; - padding: 5px; - height: 15px; + padding: 0; + height: 25px; outline: 0; border: 0 !important; background: transparent !important; box-shadow: none; - color: #666; + color: #999; font-size: 100%; font-family: sans-serif; line-height: normal; border-radius: 0; } -.chosen-container-multi .chosen-choices li.search-field .default { - color: #999; -} .chosen-container-multi .chosen-choices li.search-choice { position: relative; - margin: 3px 0 3px 5px; + margin: 3px 5px 3px 0; padding: 3px 20px 3px 5px; border: 1px solid #aaa; + max-width: 100%; border-radius: 3px; - background-color: #e4e4e4; + background-color: #eeeeee; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); background-image: -webkit-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); background-image: -moz-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); background-image: -o-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-size: 100% 19px; + background-repeat: repeat-x; background-clip: padding-box; box-shadow: 0 0 2px white inset, 0 1px 0 rgba(0, 0, 0, 0.05); color: #333; line-height: 13px; cursor: default; } +.chosen-container-multi .chosen-choices li.search-choice span { + word-wrap: break-word; +} .chosen-container-multi .chosen-choices li.search-choice .search-choice-close { position: absolute; top: 4px; @@ -325,7 +349,7 @@ box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); } .chosen-container-active .chosen-choices li.search-field input[type="text"] { - color: #111 !important; + color: #222 !important; } /* @end */ @@ -398,11 +422,7 @@ .chosen-rtl .chosen-search input[type="text"] { padding: 4px 5px 4px 20px; background: white url('chosen-sprite.png') no-repeat -30px -20px; - background: url('chosen-sprite.png') no-repeat -30px -20px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); - background: url('chosen-sprite.png') no-repeat -30px -20px, -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%); - background: url('chosen-sprite.png') no-repeat -30px -20px, -moz-linear-gradient(#eeeeee 1%, #ffffff 15%); - background: url('chosen-sprite.png') no-repeat -30px -20px, -o-linear-gradient(#eeeeee 1%, #ffffff 15%); - background: url('chosen-sprite.png') no-repeat -30px -20px, linear-gradient(#eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat -30px -20px; direction: rtl; } .chosen-rtl.chosen-container-single .chosen-single div b { @@ -414,7 +434,7 @@ /* @end */ /* @group Retina compatibility */ -@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-resolution: 144dpi) { +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi), only screen and (min-resolution: 1.5dppx) { .chosen-rtl .chosen-search input[type="text"], .chosen-container-single .chosen-single abbr, .chosen-container-single .chosen-single div b, diff --git a/css/css.php b/css/css.php index 07d6937b..354fcfbb 100644 --- a/css/css.php +++ b/css/css.php @@ -2,8 +2,8 @@ /** * sysPass * - * @author nuxsmin - * @link http://syspass.org + * @author nuxsmin + * @link http://syspass.org * @copyright 2012-2015 Rubén Domínguez nuxsmin@syspass.org * * This file is part of sysPass. @@ -27,6 +27,8 @@ define('APP_ROOT', '..'); require_once APP_ROOT . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR . 'Base.php'; +$themeUri = 'inc/themes/' . \SP\Session::getTheme(); + $cssFiles = array( array('href' => 'css/reset.css', 'min' => true), array('href' => 'css/jquery-ui.min.css', 'min' => false), @@ -39,11 +41,11 @@ $cssFiles = array( array('href' => 'css/alertify.default.css', 'min' => true), array('href' => 'css/jquery.tagsinput.css', 'min' => true), array('href' => 'js/fancybox/jquery.fancybox.css', 'min' => true), - array('href' => 'css/styles.css', 'min' => true) + array('href' => $themeUri . '/css/styles.css', 'min' => true) ); if (!SP\Util::resultsCardsIsEnabled()) { - array_push($cssFiles, array('href' => 'css/search-grid.css', 'min' => true)); + array_push($cssFiles, array('href' => $themeUri . '/css/search-grid.css', 'min' => true)); } SP\Util::getMinified('css', $cssFiles); \ No newline at end of file diff --git a/inc/Base.php b/inc/Base.php index 61b48a26..e1af564b 100644 --- a/inc/Base.php +++ b/inc/Base.php @@ -25,8 +25,8 @@ define('MODEL_PATH', __DIR__); define('CONTROLLER_PATH', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'web'); -define('VIEW_PATH', __DIR__ . DIRECTORY_SEPARATOR . 'tpl'); -define('EXTENSIONS_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR . 'ext'); +define('VIEW_PATH', __DIR__ . DIRECTORY_SEPARATOR . 'themes'); +define('EXTENSIONS_DIR', __DIR__ . DIRECTORY_SEPARATOR . 'ext'); define('DEBUG', false); require_once MODEL_PATH . DIRECTORY_SEPARATOR . 'Init.class.php'; diff --git a/inc/Init.class.php b/inc/Init.class.php index 9ddcce47..3089f944 100644 --- a/inc/Init.class.php +++ b/inc/Init.class.php @@ -63,7 +63,10 @@ class Init * @var bool True if sysPass has been updated. Only for notices. */ public static $UPDATED = false; - + /** + * @var string + */ + public static $_THEME = ''; /** * @var string */ @@ -165,6 +168,9 @@ class Init // Comprobar la configuración self::checkConfig(); + // Establecer el tema de sysPass + self::selectTheme(); + // Comprobar si está instalado self::checkInstalled(); @@ -214,31 +220,41 @@ class Init } } - if (self::isLoggedIn() || Request::analyze('isAjax', false, true)){ + if (self::isLoggedIn() || Request::analyze('isAjax', false, true)) { return; } // El usuario no está logado y no es una petición, redirigir al login self::goLogin(); + } - // El usuario no está logado y no es una petición, redirigir al login - /* if (isset($_GET["logout"]) && $_GET["logout"]) { - self::logout(); + /** + * Establecer las rutas de sysPass en el PATH de PHP + */ + public static function setIncludes() + { + set_include_path(MODEL_PATH . PATH_SEPARATOR . CONTROLLER_PATH . PATH_SEPARATOR . get_include_path()); + } - if (count($_GET) > 1) { - foreach ($_GET as $param => $value) { - if ($param == 'logout') { - continue; - } + /** + * Cargador de clases de sysPass + * + * @param $class string El nombre de la clase a cargar + */ + public static function loadClass($class) + { + // Eliminar \\ para las clases con namespace definido + $class = (strripos($class, '\\')) ? substr($class, strripos($class, '\\') + 1) : $class; - $params[] = Html::sanitize($param) . '=' . Html::sanitize($value); - } +// error_log($class); - header("Location: " . self::$WEBROOT . '/index.php?' . implode('&', $params)); - } else { - header("Location: " . self::$WEBROOT . '/'); - } - }*/ + // Buscar la clase en los directorios de include + foreach (explode(':', get_include_path()) as $iPath) { + $classFile = $iPath . DIRECTORY_SEPARATOR . $class . '.class.php'; + if (is_readable($classFile)) { + require_once $classFile; + } + } } /** @@ -439,6 +455,55 @@ class Init return false; } + /** + * Comprobar si es necesario cerrar la sesión + */ + private static function checkLogout() + { + if (Request::analyze('logout', false, true)) { + self::logout(); + self::goLogin(); + } + } + + /** + * Deslogar el usuario actual y eliminar la información de sesión. + */ + private static function logout() + { + self::wrLogoutInfo(); + + session_unset(); + session_destroy(); + } + + /** + * Escribir la información de logout en el registro de eventos. + */ + private static function wrLogoutInfo() + { + $inactiveTime = round(((time() - Session::getLastActivity()) / 60), 2); + $totalTime = round(((time() - Session::getStartActivity()) / 60), 2); + $ulogin = Session::getUserLogin(); + + $log = new Log(_('Finalizar sesión')); + $log->addDescription(_('Usuario') . ": " . $ulogin); + $log->addDescription(_('Tiempo inactivo') . ": " . $inactiveTime . " min."); + $log->addDescription(_('Tiempo total') . ": " . $totalTime . " min."); + $log->writeLog(); + } + + /** + * Mostrar la página de login + */ + private static function goLogin() + { + $controller = new Controller\MainC(); + $controller->getLogin(); + $controller->view(); + exit; + } + /** * Comrpueba y actualiza la versión de la aplicación. */ @@ -553,22 +618,6 @@ class Init return Session::getSessionTimeout(); } - /** - * Escribir la información de logout en el registro de eventos. - */ - private static function wrLogoutInfo() - { - $inactiveTime = round(((time() - Session::getLastActivity()) / 60), 2); - $totalTime = round(((time() - Session::getStartActivity()) / 60), 2); - $ulogin = Session::getUserLogin(); - - $log = new Log(_('Finalizar sesión')); - $log->addDescription(_('Usuario') . ": " . $ulogin); - $log->addDescription(_('Tiempo inactivo') . ": " . $inactiveTime . " min."); - $log->addDescription(_('Tiempo total') . ": " . $totalTime . " min."); - $log->writeLog(); - } - /** * Comprobar si hay que ejecutar acciones de URL. * @@ -595,17 +644,6 @@ class Init exit(); } - /** - * Deslogar el usuario actual y eliminar la información de sesión. - */ - private static function logout() - { - self::wrLogoutInfo(); - - session_unset(); - session_destroy(); - } - /** * Comprobar si el usuario está logado. * @@ -621,35 +659,6 @@ class Init return false; } - /** - * Establecer las rutas de sysPass en el PATH de PHP - */ - public static function setIncludes() - { - set_include_path(MODEL_PATH . PATH_SEPARATOR . CONTROLLER_PATH . PATH_SEPARATOR . get_include_path()); - } - - /** - * Cargador de clases de sysPass - * - * @param $class string El nombre de la clase a cargar - */ - public static function loadClass($class) - { - // Eliminar \\ para las clases con namespace definido - $class = (strripos($class, '\\')) ? substr($class, strripos($class, '\\') + 1) : $class; - -// error_log($class); - - // Buscar la clase en los directorios de include - foreach (explode(':', get_include_path()) as $iPath) { - $classFile = $iPath . DIRECTORY_SEPARATOR . $class . '.class.php'; - if (is_readable($classFile)) { - require_once $classFile; - } - } - } - /** * Devuelve el tiempo actual en coma flotante. * Esta función se utiliza para calcular el tiempo de renderizado con coma flotante @@ -663,22 +672,15 @@ class Init } /** - * Comprobar si es necesario cerrar la sesión + * Establecer el tema visual de sysPass desde la configuración */ - private static function checkLogout(){ - if (Request::analyze('logout', false, true)) { - self::logout(); - self::goLogin(); + private static function selectTheme() + { + if (!empty(Session::getTheme())){ + self::$_THEME = Session::getTheme(); + } else { + self::$_THEME = Config::getValue('theme', 'default'); + Session::setTheme(self::$_THEME); } } - - /** - * Mostrar la página de login - */ - private static function goLogin(){ - $controller = new Controller\MainC(); - $controller->getLogin(); - $controller->view(); - exit; - } } \ No newline at end of file diff --git a/inc/Session.class.php b/inc/Session.class.php index d45e485a..8634f970 100644 --- a/inc/Session.class.php +++ b/inc/Session.class.php @@ -508,4 +508,24 @@ class Session { $_SESSION['lastAccountId'] = $id; } + + /** + * Devuelve el tema visual utilizado en sysPass + * + * @return string + */ + public static function getTheme() + { + return (isset($_SESSION['theme'])) ? $_SESSION['theme'] : ''; + } + + /** + * Establece el tema visual utilizado en sysPass + * + * @param $theme string El tema visual a utilizar + */ + public static function setTheme($theme) + { + $_SESSION['theme'] = $theme; + } } \ No newline at end of file diff --git a/inc/Template.class.php b/inc/Template.class.php index bfc96bef..c4bc9104 100644 --- a/inc/Template.class.php +++ b/inc/Template.class.php @@ -60,17 +60,59 @@ class Template } /** - * Overloading para añadir nuevas variables en al array de variables dela plantilla - * pasadas como atributos dinámicos de la clase + * Añadir una nueva plantilla al array de plantillas de la clase * - * @param string $name Nombre del atributo - * @param string $value Valor del atributo - * @return null + * @param string $file Con el nombre del archivo de plantilla + * @return bool */ - public function __set($name, $value) + public function addTemplate($file) { - $this->_vars[$name] = $value; - return null; + if (!is_null($file) && $this->checkTemplate($file)) { + return true; + } + + return false; + } + + /** + * Comprobar si un archivo de plantilla existe y se puede leer + * + * @param string $file Con el nombre del archivo + * @return bool + * @throws InvalidArgumentException + */ + private function checkTemplate($file) + { + $template = VIEW_PATH . DIRECTORY_SEPARATOR . Init::$_THEME . DIRECTORY_SEPARATOR . $file . '.inc'; + + if (!is_readable($template)) { + throw new InvalidArgumentException('No es posible obtener la plantilla "' . $file . '"'); + } + + $this->setTemplate($template); + return true; + } + + /** + * Añadir un nuevo archivo de plantilla al array de plantillas de la clase. + * + * @param string $file Con el nombre del archivo + */ + private function setTemplate($file) + { + $this->_file[] = $file; + } + + /** + * Establecer los atributos de la clase a partir de un array. + * + * @param array $vars Con los atributos de la clase + */ + private function setVars(&$vars) + { + foreach ($vars as $name => $value) { + $this->$name = $value; + } } /** @@ -89,6 +131,20 @@ class Template return $this->_vars[$name]; } + /** + * Overloading para añadir nuevas variables en al array de variables dela plantilla + * pasadas como atributos dinámicos de la clase + * + * @param string $name Nombre del atributo + * @param string $value Valor del atributo + * @return null + */ + public function __set($name, $value) + { + $this->_vars[$name] = $value; + return null; + } + /** * Overloading para comprobar si el atributo solicitado está declarado como variable * en el array de variables de la plantilla. @@ -139,62 +195,6 @@ class Template return ob_get_clean(); } - /** - * Comprobar si un archivo de plantilla existe y se puede leer - * - * @param string $file Con el nombre del archivo - * @return bool - * @throws InvalidArgumentException - */ - private function checkTemplate($file) - { - $template = Init::$SERVERROOT . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR . 'tpl' . DIRECTORY_SEPARATOR . $file . '.inc'; - - if (!is_readable($template)) { - throw new InvalidArgumentException('No es posible obtener la plantilla "' . $file . '"'); - } - - $this->setTemplate($template); - return true; - } - - /** - * Añadir un nuevo archivo de plantilla al array de plantillas de la clase. - * - * @param string $file Con el nombre del archivo - */ - private function setTemplate($file) - { - $this->_file[] = $file; - } - - /** - * Establecer los atributos de la clase a partir de un array. - * - * @param array $vars Con los atributos de la clase - */ - private function setVars(&$vars) - { - foreach ($vars as $name => $value) { - $this->$name = $value; - } - } - - /** - * Añadir una nueva plantilla al array de plantillas de la clase - * - * @param string $file Con el nombre del archivo de plantilla - * @return bool - */ - public function addTemplate($file) - { - if (!is_null($file) && $this->checkTemplate($file)) { - return true; - } - - return false; - } - /** * Crear la variable y asignarle un valor en el array de variables * diff --git a/inc/tpl/account.inc b/inc/themes/default/account.inc similarity index 100% rename from inc/tpl/account.inc rename to inc/themes/default/account.inc diff --git a/inc/tpl/backup.inc b/inc/themes/default/backup.inc similarity index 100% rename from inc/tpl/backup.inc rename to inc/themes/default/backup.inc diff --git a/inc/tpl/body.inc b/inc/themes/default/body.inc similarity index 100% rename from inc/tpl/body.inc rename to inc/themes/default/body.inc diff --git a/inc/tpl/categories.inc b/inc/themes/default/categories.inc similarity index 100% rename from inc/tpl/categories.inc rename to inc/themes/default/categories.inc diff --git a/inc/tpl/config.inc b/inc/themes/default/config.inc similarity index 95% rename from inc/tpl/config.inc rename to inc/themes/default/config.inc index 2ac42d21..ecf31f6b 100644 --- a/inc/tpl/config.inc +++ b/inc/themes/default/config.inc @@ -11,14 +11,25 @@