This commit is contained in:
yuri
2015-07-31 17:18:24 +03:00
parent c89c7f5e0e
commit 1b5aea85ba
25 changed files with 193 additions and 63 deletions

3
.gitignore vendored
View File

@@ -9,7 +9,8 @@
/client
/test.php
/main.html
/frontend/client/css/bootstrap.css
/frontend/client/css/espo.css
/frontend/client/css/sacura.css
/tests/testData/cache/*
composer.phar
vendor/

View File

@@ -59,22 +59,28 @@ module.exports = function (grunt) {
final: ['build/tmp'],
},
less: {
bootstrap: {
espo: {
options: {
yuicompress: true,
},
files: {
'frontend/client/css/bootstrap.css': 'frontend/less/espo/main.less',
'frontend/client/css/espo.css': 'frontend/less/espo/main.less',
},
},
sacura: {
options: {
yuicompress: true,
},
files: {
'frontend/client/css/sacura.css': 'frontend/less/sacura/main.less',
},
},
},
cssmin: {
minify: {
files: {
'build/tmp/client/css/espo.min.css': [
'frontend/client/css/bootstrap.css',
'frontend/client/css/datepicker.css',
'frontend/client/css/jquery.timepicker.css',
'build/tmp/client/css/espo.css': [
'frontend/client/css/espo.css',
]
}
},

View File

@@ -86,11 +86,12 @@ class Application
public function runClient()
{
$config = $this->getContainer()->get('config');
$themeManager = $this->getContainer()->get('themeManager');
$html = file_get_contents('main.html');
$html = str_replace('{{cacheTimestamp}}', $config->get('cacheTimestamp', 0), $html);
$html = str_replace('{{useCache}}', $config->get('useCache') ? 'true' : 'false' , $html);
$html = str_replace('{{stylesheet}}', $config->get('stylesheet', 'client/css/espo.min.css'), $html);
$html = str_replace('{{stylesheet}}', $themeManager->getStylesheet(), $html);
$html = str_replace('{{runScript}}', 'app.start();' , $html);
echo $html;
exit;

View File

@@ -278,6 +278,14 @@ class Container
);
}
private function loadThemeManager()
{
return new \Espo\Core\Utils\ThemeManager(
$this->get('config'),
$this->get('metadata')
);
}
public function setUser($user)
{
$this->data['user'] = $user;

View File

@@ -25,19 +25,19 @@ namespace Espo\Core\Utils;
class Crypt
{
private $config;
private $key = null;
private $cryptKey = null;
private $iv = null;
public function __construct($config)
{
$this->config = $config;
$this->cryptKey = $config->get('cryptKey', '');
}
protected function getKey()
{
if (empty($this->key)) {
@@ -53,13 +53,13 @@ class Crypt
}
return $this->iv;
}
public function encrypt($string)
{
$iv = $this->getIv();
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->getKey(), $string, MCRYPT_MODE_CBC, $iv) . $iv);
}
public function decrypt($encryptedString)
{
$encryptedString = base64_decode($encryptedString);
@@ -68,7 +68,7 @@ class Crypt
$iv = substr($encryptedString, -16);
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->getKey(), $string, MCRYPT_MODE_CBC, $iv));
}
public function generateKey()
{
return md5(uniqid());

View File

@@ -0,0 +1,52 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM 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 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
namespace Espo\Core\Utils;
class ThemeManager
{
protected $config;
protected $metadata;
private $defaultName = 'Espo';
private $defaultStylesheet = 'Espo';
public function __construct(Config $config, Metadata $metadata)
{
$this->config = $config;
$this->metadata = $metadata;
}
public function getName()
{
return $this->config->get('theme', $this->defaultName);
}
public function getStylesheet()
{
return $this->metadata->get('themes.' . $this->getName() . '.stylesheet', 'client/css/espo.css');
}
}

View File

@@ -102,6 +102,7 @@ return array (
'followCreatedEntities' => false,
'b2cMode' => false,
'restrictedMode' => false,
'theme' => 'Espo',
'isInstalled' => false,
);

View File

@@ -38,6 +38,7 @@ class ChangePassword extends \Espo\Core\EntryPoints\Base
}
$config = $this->getConfig();
$themeManager = $this->getThemeManager();
$p = $this->getEntityManager()->getRepository('PasswordChangeRequest')->where(array(
'requestId' => $requestId
@@ -56,10 +57,15 @@ class ChangePassword extends \Espo\Core\EntryPoints\Base
$html = file_get_contents('main.html');
$html = str_replace('{{cacheTimestamp}}', $config->get('cacheTimestamp', 0), $html);
$html = str_replace('{{useCache}}', $config->get('useCache') ? 'true' : 'false' , $html);
$html = str_replace('{{stylesheet}}', $config->get('stylesheet', 'client/css/espo.min.css'), $html);
$html = str_replace('{{stylesheet}}', $themeManager->getStylesheet(), $html);
$html = str_replace('{{runScript}}', $runScript , $html);
echo $html;
exit;
}
protected function getThemeManager()
{
return $this->getContainer()->get('themeManager');
}
}

View File

@@ -530,5 +530,8 @@
"redo":"Redo"
}
}
},
"themes": {
"Espo": "Espo"
}
}

View File

@@ -51,7 +51,8 @@
"assignmentEmailNotificationsEntityList": "Entities to Notify about with Email upon Assignment",
"b2cMode": "B2C Mode",
"disableAvatars": "Disable Avatars",
"followCreatedEntities": "Follow Created Entities"
"followCreatedEntities": "Follow Created Entities",
"theme": "Theme"
},
"options": {
"weekStart": {

View File

@@ -3,7 +3,7 @@
"label": "Configuration",
"rows": [
[{"name": "recordsPerPage"},{"name": "recordsPerPageSmall"}],
[{"name": "disableAvatars"},false],
[{"name": "theme"}, {"name": "disableAvatars"}],
[{"name": "tabList"},{"name": "quickCreateList"}]
]
}

View File

@@ -235,6 +235,11 @@
},
"adminPanelIframeUrl": {
"type": "varchar"
},
"theme": {
"type": "enum",
"view": "Settings.Fields.Theme",
"translation": "themes"
}
}
}

View File

@@ -0,0 +1,3 @@
{
"stylesheet": "client/css/espo.css"
}

View File

@@ -0,0 +1,3 @@
{
"stylesheet": "client/css/sacura.css"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,35 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM 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 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
Espo.define('views/settings/fields/theme', 'views/fields/enum', function (Dep) {
return Dep.extend({
setup: function () {
this.params.options = Object.keys(this.getMetadata().get('themes')).sort(function (v1, v2) {
return this.translate(v1, 'theme').localeCompare(this.translate(v2, 'theme'));
}.bind(this));
Dep.prototype.setup.call(this);
},
});
});

View File

@@ -29,8 +29,11 @@ if (!empty($_GET['entryPoint'])) {
exit;
}
$themeManager = $app->getContainer()->get('themeManager');
$runScript = "app.start();";
$html = file_get_contents("frontend/main.html");
$html = str_replace('{{stylesheet}}', $themeManager->getStylesheet() , $html);
$html = str_replace('{{runScript}}', $runScript , $html);
echo $html;
exit;

View File

@@ -299,7 +299,7 @@ ul.dropdown-menu > li.checkbox:last-child {
}
#login.panel > .panel-heading {
background-color: #4A6492;
background-color: @login-panel-heading-bg;
padding: 0;
margin: -2px;
}
@@ -792,6 +792,10 @@ img.avatar.avatar-link {
line-height: @line-height-computed;
}
.list-group-item {
background-color: transparent;
}
.note-editable blockquote {
font-size: @font-size-base;
}

View File

@@ -1,3 +1,5 @@
@import "misc/selectize/selectize.less";
@import "misc/selectize/selectize.bootstrap3.less";
@import "misc/summernote/summernote.less";
@import "misc/summernote/summernote.less";
@import "misc/datepicker/datepicker.less";
@import "misc/timepicker/timepicker.less";

View File

@@ -9,9 +9,6 @@
*/
.datepicker {
padding: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
direction: ltr;
/*.dow {
border-top: 1px solid #ddd !important;
@@ -104,9 +101,6 @@
text-align: center;
width: 20px;
height: 20px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
border: none;
}
.table-striped .datepicker table tr td,
@@ -132,13 +126,6 @@
.datepicker table tr td.today.disabled,
.datepicker table tr td.today.disabled:hover {
background-color: #fde19a;
background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);
background-image: linear-gradient(top, #fdd49a, #fdf59a);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
border-color: #fdf59a #fdf59a #fbed50;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
@@ -300,17 +287,6 @@
.datepicker table tr td.active.disabled,
.datepicker table tr td.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
background-image: linear-gradient(top, #0088cc, #0044cc);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
@@ -334,7 +310,7 @@
.datepicker table tr td.active:hover[disabled],
.datepicker table tr td.active.disabled[disabled],
.datepicker table tr td.active.disabled:hover[disabled] {
background-color: #0044cc;
background-color: @brand-primary;
}
.datepicker table tr td.active:active,
.datepicker table tr td.active:hover:active,
@@ -372,13 +348,6 @@
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
background-image: linear-gradient(top, #0088cc, #0044cc);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
@@ -406,7 +375,7 @@
.datepicker table tr td span.active:hover[disabled],
.datepicker table tr td span.active.disabled[disabled],
.datepicker table tr td span.active.disabled:hover[disabled] {
background-color: #0044cc;
background-color: @brand-primary;
}
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
@@ -454,14 +423,8 @@
text-align: center;
}
.input-daterange input:first-child {
-webkit-border-radius: 3px 0 0 3px;
-moz-border-radius: 3px 0 0 3px;
border-radius: 3px 0 0 3px;
}
.input-daterange input:last-child {
-webkit-border-radius: 0 3px 3px 0;
-moz-border-radius: 0 3px 3px 0;
border-radius: 0 3px 3px 0;
}
.input-daterange .add-on {
display: inline-block;

View File

@@ -46,7 +46,8 @@
li.ui-timepicker-selected,
.ui-timepicker-list li:hover,
.ui-timepicker-list .ui-timepicker-selected:hover {
background: #1980EC; color: #fff;
background: @brand-primary;
color: #fff;
}
li.ui-timepicker-selected .ui-timepicker-duration,

View File

@@ -106,3 +106,5 @@
@zindex-popover: 1600;
@zindex-tooltip: 1600;
@navbar-collapse-max-height: none;
@login-panel-heading-bg: @navbar-inverse-bg;

View File

@@ -0,0 +1,8 @@
@import "../espo/bootstrap/bootstrap.less";
@import "../espo/variables.less";
@import "variables.less";
@import "../espo/mixins.less";
@import "../espo/misc.less";
@import "../espo/custom.less";
@import "../espo/bootstrap/utilities.less";

View File

@@ -0,0 +1,15 @@
@gray-dark: lighten(@gray-base, 25%);
@main-gray: #CCD9F0;
@input-border: #CCD9F0;
@body-bg: #FAFBFC;
@brand-primary: #739BBE;
@brand-success: #83CD77;
@navbar-inverse-color: #FFF;
@navbar-inverse-bg: #BB7690;
@navbar-inverse-link-color: #F7F7F7;
@login-panel-heading-bg: @brand-primary;

View File

@@ -26,9 +26,7 @@
<script type="text/javascript" src="client/src/exceptions.js"></script>
<link href="client/css/bootstrap.css" rel="stylesheet">
<link href="client/css/jquery.timepicker.css" rel="stylesheet">
<link href="client/css/datepicker.css" rel="stylesheet">
<link href="{{stylesheet}}" rel="stylesheet">
<link rel="icon" href="client/img/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="client/img/favicon.ico" type="image/x-icon">