51 Commits
Author SHA1 Message Date
Michal Kváček 8098288139 FIX: fix path to admin routes 2018-09-20 00:14:53 +02:00
Michal Kváček cf90d1b91e FEATURE: make nested margin on subpages 2018-04-11 23:04:16 +02:00
Michal Kváček 8acfcabb3c FEATURE: add infinite content pages depth into overview 2018-04-11 22:48:00 +02:00
Michal Kváček b91b80debb FEATURE: allow infinite subpages depth 2018-04-11 22:36:25 +02:00
Michal Kváček ae29c49acf Merge branch 'master' of binarity.cz:/opt/git/internal/cms/minicms 2018-03-25 11:23:38 +02:00
Michal Kváček 7e4507e9e4 FEATURE: add template to menu widget 2018-03-25 11:23:12 +02:00
Peter Hrdlica f0bb159efb Merge branch 'master' of binarity.cz:/opt/git/internal/cms/minicms 2017-10-15 15:54:57 +02:00
Peter Hrdlica ddae98d233 multiselect component 2017-10-15 15:54:21 +02:00
Michal Kváček b1ca6e4cfb FEATURE: allow multiple ckEditor instances 2017-10-09 00:14:48 +02:00
Michal Kváček c69bd9bcf7 FEATURE: add bootstrap datepicker. All elements with .date class are now datepicker holders 2017-09-25 23:22:25 +02:00
Michal Kváček 271e7f5170 FIX: fix insanely low file previews 2017-09-25 15:29:54 +02:00
Michal Kváček 1ecef555ef FIX: fix minor bug in content overview and module installation 2017-09-25 14:37:30 +02:00
Michal Kváček 4ef5e3e3cd FEATURE: make top menu extendable 2017-09-25 11:20:57 +02:00
Michal Kváček 1388383bb6 FEATURE: update Font Awesome and add bottom border and margin to submenus in admin 2017-09-24 16:44:36 +02:00
Michal Kváček f1ff45cfb1 FIX: do not fire error when module service provider is not found. Log it and let it go 2017-09-24 13:57:03 +02:00
Michal Kváček 6d723f026d FIX: remove template service provider from core repository 2017-09-23 00:52:35 +02:00
Michal Kváček b99f70c269 FEATURE: move profiler into own repository 2017-09-23 00:51:24 +02:00
Michal Kváček 680edb14c1 Merge branch 'dev' into module_profiler 2017-09-23 00:45:51 +02:00
Michal Kváček ced920505a FIX #2556: fix user edit 2017-09-22 21:32:47 +02:00
Michal Kváček a1c4a19a59 FEATURE: add cache into public/.htaccess 2017-09-22 21:25:14 +02:00
Michal Kváček 62f73c51e6 FEATURE: add input for setting preview size and quality 2017-09-19 14:18:15 +02:00
Michal Kváček ba55702585 FEATURE: make own page for template overview 2017-09-15 13:32:09 +02:00
Michal Kváček 4d68156a73 FIX: add missing cache forget after disabling module 2017-09-14 20:32:21 +02:00
Michal Kváček f10847dede FIX: just another bugfix 2017-09-14 20:17:16 +02:00
Michal Kváček 73681a5a4d FIX: minor bugfix 2017-09-14 11:34:08 +02:00
Michal Kváček a2d83ce3fa REFACTORING: split javascripts 2017-09-14 10:14:11 +02:00
Michal Kváček a0c31c7a5f FIX: fix error in translation 2017-09-13 14:34:11 +02:00
Michal Kváček 422339b313 MAINTENANCE: update laravel, dependencies, fix few bugs 2017-09-13 14:02:39 +02:00
Michal Kváček 3fdae2669b FEATURE: add page ordering 2017-09-13 14:02:07 +02:00
Michal Kváček d90ca08ba6 FEATURE: add new relationship to Content model - only visible subpages 2017-09-08 00:33:46 +02:00
Michal Kváček e8cbc1b537 FIX: fix permissions for publishing content pages 2017-09-07 23:53:34 +02:00
Michal Kváček 983efad9f0 TESTING #1931: do something with tests.. Not really usefull 2017-09-02 00:35:52 +02:00
Michal Kváček 2d66cf672a FEATURE #2520: add template for creating new table 2017-09-01 23:49:34 +02:00
Michal Kváček a5b6f6fa0d FEATURE #2520: add commands for creating new migration and running migrations in modules 2017-09-01 23:25:26 +02:00
Michal Kváček c92ba41def FIX: fix registering service providers in templates 2017-08-26 22:34:40 +02:00
Michal Kváček 6468c8f49c FEATURE: conditionally publish views in module, fix confirm dialog for forms 2017-08-25 11:40:34 +02:00
Michal Kváček 8bae8a43f9 FEATURE: add SITE_URL into installer 2017-08-24 14:29:06 +02:00
Michal Kváček 0e535c3ed1 FIX: fix few bugs in generating new module 2017-08-24 14:28:52 +02:00
Michal Kváček ce183d4805 FEATURE #2503: add easier installer 2017-08-24 14:15:08 +02:00
Michal Kváček 8946ef7441 FEATURE: update dependencies 2017-08-24 03:52:21 +02:00
Michal Kváček 295e8927a9 FIX: lots of bugfixes 2017-08-24 03:48:17 +02:00
Michal Kváček 029d84fed1 FEATURE: remove unused tables (custom fields) from database 2017-08-24 03:17:49 +02:00
Michal Kváček 862f49771f FEATURE: move templates into their own repositories 2017-08-24 03:05:30 +02:00
Michal Kváček 7d6a3737e3 FEATURE #2389 @20m: add deleting all data from profiler 2017-03-28 01:01:21 +02:00
Michal Kváček aa55ffe46a FEATURE #2389 @2h: group http request by url 2017-03-28 00:27:31 +02:00
Michal Kváček 848fa7b7cb Merge branch 'dev' into module_profiler 2017-03-27 21:24:31 +02:00
Michal Kváček 05c9e56973 FEATURE #2389 @2h: add request detail into profiler 2017-03-24 01:28:21 +01:00
Michal Kváček 52e02d67c6 Merge branch 'dev' into module_profiler 2017-03-23 23:18:01 +01:00
Michal Kváček 9c90e844b0 FEATURE: add simple view for requests and queries 2017-03-02 20:04:35 +01:00
Michal Kváček d99c046103 Merge branch 'dev' into module_profiler 2017-03-02 12:29:21 +01:00
Michal Kváček c027ffe2df FEATURE: add first basics of profiler 2017-02-22 08:54:26 +01:00
376 changed files with 8403 additions and 83852 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ interface Module extends BaseRepository
public function getUpdateContentTitle(ModuleModel $module, ContentModel $content = null);
public function getOverviewTitle(ModuleModel $module);
public function getOverviewTitle(ModuleModel $module = null);
public function getByHandler($handler);
+23 -10
View File
@@ -3,7 +3,6 @@
namespace App\CMS\Handlers;
use App\CMS\Contracts\Modules\BaseModuleHandler;
use App\CMS\Enumerations\TemplatePathsHumanReadableRootOnly;
use App\CMS\Enumerations\WidgetTypes;
use App\CMS\Repositories\Module;
use App\Models\ActionLog\ActionLog;
@@ -14,6 +13,7 @@ use App\Models\Templates\Template;
use App\Models\User;
use App\Models\Widgets\Widget;
use App\Models\Widgets\WidgetArea;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
abstract class BaseHandler implements BaseModuleHandler
{
@@ -44,6 +44,7 @@ abstract class BaseHandler implements BaseModuleHandler
if ($user->can('manage', Content::class) && !$contentModules->isEmpty()) {
$menu->dropdown(trans('admin/mainMenu.contentPages'), function ($sub) {
$sub->route('content.order', trans('admin/mainMenu.contentOrder'), [], 999, ['icon' => 'fa fa-fw fa-reorder']);
$sub->route('content.overview', trans('admin/mainMenu.contentPageOverview'), [], 10000, ['icon' => 'fa fa-fw fa-list']);
}, 20, ['icon' => 'fa fa-fw fa-database']);
}
@@ -110,15 +111,7 @@ abstract class BaseHandler implements BaseModuleHandler
* Templates
*/
if ($user->can('manage', Template::class)) {
$templatePaths = TemplatePathsHumanReadableRootOnly::getWithTranslations();
if (!empty($templatePaths)) {
$sub->dropdown(trans('admin/mainMenu.templates'), function ($sub) use ($templatePaths) {
$i = 1;
foreach ($templatePaths as $id => $name) {
$sub->route('templates.overview', $name, ['id' => $id], $i++);
}
}, 60, ['icon' => 'fa fa-fw fa-file-code-o']);
}
$sub->route('templates.index', trans('admin/mainMenu.templates'), [], 70, ['icon' => 'fa fa-fw fa-file-code-o']);
}
if ($user->can('manage', ActionLog::class)) {
@@ -132,6 +125,26 @@ abstract class BaseHandler implements BaseModuleHandler
}, 10000, ['icon' => 'fa fa-fw fa-gears']);
});
\Menu::create('topMenu', function ($menu) use ($user) {
if (count(LaravelLocalization::getSupportedLocales()) > 1) {
$menu->dropdown(trans(LaravelLocalization::getCurrentLocaleName()), function ($menu) use ($user) {
foreach (LaravelLocalization::getSupportedLocales() as $localeCode => $properties) {
$menu->url(LaravelLocalization::getLocalizedURL($localeCode), $properties['native']);
}
});
}
if ($user->can('manage', Content::class)) {
$menu->route('page.index', '', [], 10, [
'icon' => 'fa fa-fw fa-globe',
'title' => trans('common.goToWeb'),
'target' => '_blank',
'data-toggle' => 'tooltip',
'data-placement' => 'left'
]);
}
});
// create menu with user profile
\Menu::create('profileMenu', function ($menu) use ($user) {
$menu->route('users.detail', trans('admin/userManagement.profile'), ['user' => $user], 10, ['icon' => 'fa fa-fw fa-user icon']);
@@ -15,6 +15,7 @@ class SettingExtension
* @var string view used for rendering given settings part
*/
protected $view;
protected $order;
/**
* SettingExtension constructor.
@@ -23,11 +24,12 @@ class SettingExtension
* @param string $name
* @param string $view
*/
public function __construct($id, $name, $view)
public function __construct($id, $name, $view, $order)
{
$this->id = $id;
$this->name = $name;
$this->view = $view;
$this->order = $order;
}
/**
@@ -53,4 +55,14 @@ class SettingExtension
{
return $this->view;
}
/**
* @return mixed
*/
public function getOrder()
{
return $this->order;
}
}
@@ -1,7 +1,8 @@
<?php
namespace App\CMS\Handlers\Registrators;
use App\CMS\Enumerations\Exceptions\EnumerationExistsException;
use App\CMS\Exceptions\Enumerations\EnumerationExistsException;
use App\CMS\Handlers\Registrators\Items\SettingExtension;
class SettingsExtensionRegistrator
@@ -22,12 +23,16 @@ class SettingsExtensionRegistrator
*
* @throws EnumerationExistsException
*/
public function register($sectionId, $sectionName, $sectionView)
public function register($sectionId, $sectionName, $sectionView, $order = null)
{
$this->checkIfRegistered($sectionId);
if (is_null($order)) {
$order = count($this->settingsExtensions);
}
// register new extension
$this->settingsExtensions[$sectionId] = new SettingExtension($sectionId, $sectionName, $sectionView);
$this->settingsExtensions[$sectionId] = new SettingExtension($sectionId, $sectionName, $sectionView, $order);
}
/**
@@ -44,14 +49,15 @@ class SettingsExtensionRegistrator
/**
* Getter for all registered extensions
*
* @return array
*/
public function get()
{
// sort registered extensions by key
ksort($this->settingsExtensions);
// sort registered extensions
uasort($this->settingsExtensions, function (SettingExtension $a, SettingExtension $b) {
return $a->getOrder() - $b->getOrder();
});
return $this->settingsExtensions;
}
@@ -207,6 +207,7 @@ class TemplateRegistrator
protected function registerTemplates($path, $templatePathId)
{
$templates = File::files($path);
$registeredTemplates = Templates::getWithTranslations();
foreach ($templates as $template) {
@@ -217,7 +218,6 @@ class TemplateRegistrator
// get all templates and template name (path/to/template.blade.php -> path.to.template)
$templateName = $this->getTemplateName($template);
$registeredTemplates = Templates::getWithTranslations();
if (!in_array($templateName, $registeredTemplates)) {
$params = [
@@ -316,4 +316,14 @@ class TemplateRegistrator
return $this->namespace . trim($templateName, '.');
}
public function deleteNonExistingPaths()
{
$paths = TemplatePath::all();
foreach ($paths as $path) {
if (!is_dir(base_path($path->path)))
\File::deleteDirectory($path->path);
}
}
}
-37
View File
@@ -1,37 +0,0 @@
<?php
namespace App\CMS\Helpers;
use App\CMS\Handlers\Contracts\AppHandler;
use App\Models\Content\Content;
use Webwizo\Shortcodes\Facades\Shortcode;
/**
* Class PageRenderer
*
* Simple class for rendering page for visitor
*
* @package App\CMS\Helpers
*/
class PageRenderer
{
/**
* Render page
*
* @param Content $page
*
* @return mixed
*/
public static function render(Content $page)
{
// do something template-specific
$parameters = call_user_func_array([CurrentTemplate::handler(), 'beforeRender'], [&$page]);
/**
* @var $handler AppHandler
*/
$handler = new $page->moduleHandler;
// render page
return $handler->render($page, $parameters);
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ trait Nullable {
* @return null|string
*/
public function nullableDate($date) {
return empty($date) ? null : Carbon::parse($date)->toDateTimeString();
return empty($date) ? null : Carbon::createFromFormat(config('app.date_format'), $date)->toDateTimeString();
}
/**
@@ -1,83 +0,0 @@
<?php
namespace App\CMS\MenuPresenters;
use Nwidart\Menus\MenuItem;
use Nwidart\Menus\Presenters\Presenter;
class FoundationDrilldownMenuPresenter extends Presenter
{
/**
* {@inheritdoc }
*/
public function getOpenTagWrapper()
{
return PHP_EOL . '<ul class="vertical menu" data-drilldown>' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getCloseTagWrapper()
{
return PHP_EOL . '</ul>' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getMenuWithoutDropdownWrapper($item)
{
return '<li' . $this->getActiveState($item) . '><a href="' . $item->getUrl() . '">' . $item->getIcon() . ' ' . $item->title . '</a></li>' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getActiveState(MenuItem $item)
{
$active = ' class="active"';
if (empty($item->getChilds())) {
// for direct menu input return if page is active
return \Request::is($item->getRequest()) ? $active : null;
} else {
// on nested menu inputs loop over children and in case any of them is active, mark active also root level
foreach ($item->getChilds() as $child) {
if ($this->getActiveState($child)) {
return $active;
}
}
}
return null;
}
/**
* {@inheritdoc }
*/
public function getDividerWrapper()
{
return '<li class="divider"></li>' . PHP_EOL;
}
public function getMultiLevelDropdownWrapper($item)
{
return $this->getMenuWithDropDownWrapper($item);
}
/**
* {@inheritdoc }
*/
public function getMenuWithDropDownWrapper($item)
{
$active = $this->getActiveState($item);
return '<li>
<a ' . $active . ' href="#">' . $item->getIcon() . ' ' . $item->title . '</a>
<ul class="vertical menu">
' . $this->getChildMenuItems($item) . '
</ul>
</li>' . PHP_EOL;
}
}
@@ -1,62 +0,0 @@
<?php
namespace App\CMS\MenuPresenters;
use Nwidart\Menus\Presenters\Presenter;
class FoundationDropdownMenuPresenter extends Presenter
{
/**
* {@inheritdoc }
*/
public function getOpenTagWrapper()
{
return PHP_EOL . '<ul class="vertical dropdown menu" data-dropdown-menu>' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getCloseTagWrapper()
{
return PHP_EOL . '</ul>' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getMenuWithoutDropdownWrapper($item)
{
$link = '<a href="' . $item->getUrl() . '">' . $item->getIcon() . ' ' . $item->title . '</a>';
return '<li' . $this->getActiveState($item) . '>' . $link . '</li>' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getActiveState($item)
{
return \Request::is($item->getRequest()) || $item->hasActiveOnChild ? ' class="active"' : null;
}
/**
* {@inheritdoc }
*/
public function getDividerWrapper()
{
return '<li class="divider"></li>' . PHP_EOL;
}
/**
* {@inheritdoc }
*/
public function getMenuWithDropDownWrapper($item)
{
return '<li>
<a href="#">' . $item->getIcon() . ' ' . $item->title . '</a>
<ul class="vertical menu">
' . $this->getChildMenuItems($item) . '
</ul>
</li>' . PHP_EOL;
}
}
@@ -1,10 +0,0 @@
<?php
namespace App\CMS\MenuPresenters;
class FoundationInitializedDropdownMenuPresenter extends FoundationDropdownMenuPresenter
{
public function getOpenTagWrapper()
{
return PHP_EOL . '<ul class="menu">' . PHP_EOL;
}
}
@@ -0,0 +1,16 @@
<?php
namespace App\CMS\MenuPresenters;
use Nwidart\Menus\Presenters\Bootstrap\NavbarPresenter;
class TopMenuPresenter extends NavbarPresenter {
public function getOpenTagWrapper()
{
return '';
}
public function getCloseTagWrapper()
{
return '';
}
}
@@ -3,6 +3,8 @@
namespace App\CMS\ModuleManager\Providers;
use App\CMS\Repositories\Module as ModuleRepository;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;
class ModuleManager extends ServiceProvider
@@ -14,13 +16,22 @@ class ModuleManager extends ServiceProvider
public function boot()
{
// this service provider needs published config - config is merged right after this service provider
$modules = app(ModuleRepository::class)->getOnlyModules();
try {
$modules = app(ModuleRepository::class)->all();
} catch (QueryException $e) {
return;
}
// iterate over all modules and enable or disable them
foreach ($modules as $module) {
if (isset($module->module_settings['providers']) && !empty($module->module_settings['providers'])) {
foreach ($module->module_settings['providers'] as $provider) {
if (!class_exists($provider)) {
Log::warning($provider.' does not exists. Skipping');
continue;
}
$this->app->register($provider);
}
}
@@ -28,7 +39,13 @@ class ModuleManager extends ServiceProvider
// include files (if any)
if (isset($module->module_settings['files']) && !empty($module->module_settings['files'])) {
foreach ($module->module_settings['files'] as $file) {
include config('modules.paths.modules') . '/' . $module->static_name . '/' . $file;
$path = config('modules.paths.modules') . '/' . $module->static_name . '/' . $file;
if (!file_exists($path)) {
$path = base_path($file);
}
@include_once $path;
}
}
}
@@ -13,6 +13,7 @@ abstract class ServiceProvider extends LaravelServiceProvider
protected $defer = false;
protected $alias = false;
protected $path = false;
protected $publishViews = true;
abstract protected function setModuleAlias();
@@ -59,7 +60,7 @@ abstract class ServiceProvider extends LaravelServiceProvider
return $path . '/modules/' . $this->alias;
}, \Config::get('view.paths')), [$sourcePath]), $this->alias);
if (is_dir($sourcePath)) {
if (is_dir($sourcePath) && $this->publishViews) {
$this->publishes([$sourcePath => $viewPath], 'module-views');
}
}
@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class $MigrationName$ extends Migration
{
/**
* Run migration
*/
public function up()
{
Schema::create('$TableName$', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
});
}
/**
* Rollback migration
*/
public function down()
{
Schema::dropIfExists('$TableName$');
}
}
+28
View File
@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class $MigrationName$ extends Migration
{
/**
* Run migration
*/
public function up()
{
Schema::table('$TableName$', function (Blueprint $table) {
});
}
/**
* Rollback migration
*/
public function down()
{
Schema::table('$TableName$', function (Blueprint $table) {
});
}
}
@@ -4,7 +4,7 @@ return [
'name' => '$Module$',
'translatedName' => '$module$::$module$.name',
'translatedDescription' => '$module$::$module$.description',
'alias' => 'categories',
'alias' => strtolower('$Module$'),
'handler' => \Modules\$Module$\Handlers\$Module$Handler::class,
'providers' => [\Modules\$Module$\Providers\$Module$ServiceProvider::class],
'files' => ['Http/routes.php'],
@@ -4,5 +4,7 @@ namespace Modules\$ModuleNamespace$\Entities;
use Illuminate\Database\Eloquent\Model;
class $Entity$ extends Model {
protected $table = 'contents';
// ...
}
@@ -6,7 +6,7 @@ use App\Http\Controllers\Admin\Controller;
use Modules\$ModuleNamespace$\Http\Requests\Update$Entity$;
use Modules\$ModuleNamespace$\Http\Requests\Create$Entity$;
use Modules\$ModuleNamespace$\Repositories\$Module$Repository;
use $EntityNamespace$\$Entity$ as $Entity$Entity;
use $EntityNamespace$$Entity$ as $Entity$Entity;
class $Module$ extends Controller
{
@@ -2,7 +2,7 @@
namespace Modules\$Module$\Providers;
use App\CMS\Contracts\Modules\ServiceProvider;
use App\CMS\Modules\ServiceProviders\ServiceProvider;
/**
* Class $Module$ServiceProvider
@@ -1,7 +1,7 @@
<?php
namespace Modules\$ModuleNamespace$\Repositories;
use $EntityNamespace$\$Entity$ as $Entity$Entity;
use $EntityNamespace$$Entity$ as $Entity$Entity;
class $Module$Repository {
/**
+4 -5
View File
@@ -7,7 +7,6 @@ use App\CMS\Enumerations\ContentStatuses;
use App\CMS\Repositories\Repository;
use App\Models\Content\Content as ContentModel;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class Content extends Repository implements IContent
@@ -106,15 +105,15 @@ class Content extends Repository implements IContent
*/
public function getOverview($handler = null, $statuses = null)
{
$query = ContentModel::select('contents.*', 'modules.name AS module_name', 'modules.id AS module_id')
$query = ContentModel::select('contents.*')
->join('modules', 'modules.handler', '=', 'contents.moduleHandler')
->join('users', 'users.id', '=', 'contents.userId')
->addSelect(DB::raw('COALESCE(users.name, users.email) AS author_name'))
->addSelect('users.email AS author_email')
->whereNull('contents.deleted_at')
->whereNull('contents.parentId')
->where('contents.language', LaravelLocalization::getCurrentLocale())
->where('modules.enabled', 1)
->with('module')
->with('module', 'subpages', 'subpages.module', 'subpages.templateModel', 'templateModel')
->orderBy('contents.order')
->orderBy('contents.created_at', 'DESC');
// filter results using handler
+11 -6
View File
@@ -30,10 +30,10 @@ class Module extends Repository implements IModule
public function getContentModules()
{
return Cache::remember('enabled-content-modules', 3600, function () {
return Cache::remember('enabled-content-modules', setting('cacheModules', 3600), function () {
return ModuleModel::where('enabled', true)
->where('manages_content', true)
->get();
->where('manages_content', true)
->get();
});
}
@@ -53,9 +53,14 @@ class Module extends Repository implements IModule
return is_null($moduleHeading) ? $pageHeading : $moduleHeading;
}
public function getOverviewTitle(ModuleModel $module)
public function getOverviewTitle(ModuleModel $module = null)
{
$pageHeading = 'admin/contents.overview';
if (is_null($module)) {
return $pageHeading;
}
$moduleHeading = $this->call($module, 'getOverviewTitle');
return is_null($moduleHeading) ? $pageHeading : $moduleHeading;
@@ -63,7 +68,7 @@ class Module extends Repository implements IModule
public function all()
{
return Cache::rememberForever('enabled-modules-and-template', function () {
return Cache::remember('enabled-modules-and-template', setting('cacheModules', 3600), function () {
return ModuleModel::where('enabled', true)
->get();
});
@@ -71,7 +76,7 @@ class Module extends Repository implements IModule
public function getOnlyModules()
{
return Cache::rememberForever('enabled-modules', function () {
return Cache::remember('enabled-modules', setting('cacheModules', 3600), function () {
return ModuleModel::where('enabled', true)
->where('is_template', false)
->get();
+1 -1
View File
@@ -70,7 +70,7 @@ class Template extends Repository implements ITemplate
public function getForModule(Module $module)
{
return Cache::rememberForever('templates-for-module', function () use ($module) {
return Cache::remember('templates-for-module-'.$module->id, setting('cacheModules', 3600), function () use ($module) {
return TemplateModel::where('module_id', $module->id)
->select(['template_name', 'name', 'description'])
->get();
+26 -13
View File
@@ -12,9 +12,10 @@ use Illuminate\Support\Facades\Route;
class Menu implements WidgetRenderer
{
public static $template = null;
/**
* Method used for displaying widget.
*
* This method renders some HTML code for displaying.
*
* @param Widget $widget
@@ -27,6 +28,11 @@ class Menu implements WidgetRenderer
$links = (array)$settings->links;
$pageIds = array_keys($links);
if (!self::$template) {
throw new \Exception('neni nastavena sablona');
return;
}
// get pages
$pages = WidgetMenu::selectContentPages($pageIds);
@@ -40,14 +46,15 @@ class Menu implements WidgetRenderer
$parameters = Route::current()
->parameters();
$code = '<ul class="menu ' . $widget->container_class . '"';
// $code = '<ul class="menu ' . $widget->container_class . '"';
if ($widget->container_id) {
$code .= ' id="' . e($widget->container_id) . '"';
}
// if ($widget->container_id) {
// $code .= ' id="' . e($widget->container_id) . '"';
// }
$code .= '>';
// $code .= '>';
$menuItems = [];
foreach ($links as $pageId => $link) {
if (!isset($pages[$pageId])) {
continue;
@@ -57,16 +64,22 @@ class Menu implements WidgetRenderer
$active = ($page->isHomepage && $routeName == 'page.index') || ($routeName == 'page.content' && isset($parameters['url']) && $parameters['url'] == $page->url);
$route = $page->isHomepage ? route('page.index') : route('page.content', ['url' => $page->url]);
$code .= '<li';
if ($active) {
$code .= ' class="is-active active"';
}
$code .= '><a href="' . $route . '">' . e($page->title) . '</a></li>';
$menuItems[] = compact('page', 'active', 'route');
// $code .= '<li';
// if ($active) {
// $code .= ' class="is-active active"';
}
// $code .= '><a href="' . $route . '">' . e($page->title) . '</a></li>';
// }
$code .= "</ul>";
// $code .= "</ul>";
return $code;
return view(self::$template, [
'containerClass' => $widget->container_class,
'containerId' => $widget->container_id,
'menuItems' => $menuItems
]);
}
/**
+1 -1
View File
@@ -30,7 +30,7 @@ class ChangePassword extends Command
$email = $this->argument('email');
try {
$user = User::where(['email' => $email])
->first();
->firstOrFail();
} catch (ModelNotFoundException $e) {
$this->error('Invalid user ' . $email . '.');
return;
+9 -6
View File
@@ -13,14 +13,14 @@ class InitDatabaseSchema extends Command
*
* @var string
*/
protected $signature = 'db:init {schema.sql}';
protected $signature = 'db:init';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
protected $description = 'Init database structure';
/**
* Create a new command instance.
@@ -39,13 +39,16 @@ class InitDatabaseSchema extends Command
*/
public function handle()
{
do {
$schema = $this->ask('Path to database schema file', 'database/schema.sql');
} while (!file_exists($schema));
$schema = $this->argument('schema.sql');
if (!file_exists($schema)) throw new NotFoundHttpException('File '.$schema.' does not exist.');
DB::unprepared(file_get_contents($schema));
$this->line('Successfully imported');
$this->call('migrate');
$this->call('db:seed');
$this->line('Database successfully initialized.');
}
}
+153
View File
@@ -0,0 +1,153 @@
<?php
namespace App\Console\Commands;
use App\Models\Language;
use Illuminate\Console\Command;
use Illuminate\Database\QueryException;
class InstallCMS extends Command
{
/**
* The name and signature of the console command.
* @var string
*/
protected $signature = 'cms:install';
/**
* The console command description.
* @var string
*/
protected $description = 'Try to make installation of CMS as easy as possible';
/**
* Execute the console command.
* @return mixed
*/
public function handle()
{
// check and eventualy create .env file
if (!file_exists(base_path('.env'))) {
$this->createEnv();
$this->line('Rerun this script again, we need to load changes.');
return;
}
// install php dependencies
$parameters = env('APP_DEBUG') ? '' : '--no-dev';
exec('composer install ' . $parameters);
// init database
try {
// does exist something in laguages table? (Or event table itself?)
Language::all();
} catch (QueryException $e) {
// database is not initialized
$this->call('db:init');
}
// install npm dependencies
exec('npm install');
exec('bower install');
exec('gulp');
// change chmod of needed directories
$directories = ['bootstrap/cache', 'storage', 'public'];
foreach ($directories as $directory) {
$this->changeChmod($directory);
}
$this->line('Chmod changed');
// generate APP_KEY in .env
$this->call('key:generate');
// create user
$this->line('Creating admin user...');
do {
$email = $this->ask('E-mail for admin user');
} while (empty($email));
$this->call('user:new', compact('email'));
$this->line('All done. CMS should be prepared.');
}
/**
* Insert value into .env config file
*
* @param $envConstant
* @param $value
*/
private function setEnvConstant($envConstant, $value)
{
$content = file_get_contents(base_path('.env'));
$content = preg_replace('/' . $envConstant . '=(.*)/i', $envConstant . '=' . $value, $content);
file_put_contents(base_path('.env'), $content);
}
/**
* Create .env file with all needed constants
*/
private function createEnv()
{
\File::copy(base_path('.env.example'), base_path('.env'));
// set environment
do {
$env = $this->ask('Install environment: ', 'local');
} while (empty($env));
$this->setEnvConstant('APP_ENV', $env);
// set debugging
if ($env == 'local') {
$debug = 'true';
} else {
$debug = $this->confirm('Enable debugging?', true) ? 'true' : 'false';
}
$this->setEnvConstant('APP_DEBUG', $debug);
// setup database
$databaseFields = [
'DB_HOST' => 'Database server',
'DB_DATABASE' => 'Database name',
'DB_USERNAME' => 'Database user',
'DB_PASSWORD' => 'Password'
];
foreach ($databaseFields as $constant => $text) {
do {
$value = $this->ask($text);
} while (empty ($value));
$this->setEnvConstant($constant, $value);
}
// set app url
do {
$url = $this->ask('Application URL');
$url = trim($url, ' /');
} while (empty($url));
$this->setEnvConstant('SITE_URL', $url);
$this->setEnvConstant('UPLOAD_URL', $url . '/public/uploads');
$this->setEnvConstant('THUMBNAIL_URL', $url . '/public/uploads/thumbnails');
}
/**
* Recursively change chmod to 777 in given directory
*
* @param $directory
*/
private function changeChmod($directory)
{
@chmod($directory, 0777);
if (!is_dir($directory)) {
return;
}
$subdirectories = \File::allFiles($directory);
foreach ($subdirectories as $subdirectory) {
$this->changeChmod($subdirectory);
}
}
}
@@ -0,0 +1,106 @@
<?php
namespace App\Console\Commands\Modules;
use App\Models\Module;
use Illuminate\Console\Command;
class CreateMigration extends Command
{
/**
* The name and signature of the console command.
* @var string
*/
protected $signature = 'module:make-migration {module?} {name?} {--t|table= : Table name} {--c|create : Use template for creating new table}';
/**
* The console command description.
* @var string
*/
protected $description = 'Make new migration for given module';
protected $migrationName;
protected $tableName;
protected $moduleName;
/**
* Execute the console command.
*/
public function handle()
{
$this->moduleName = $module = $this->argument('module');
$this->migrationName = $name = $this->argument('name');
$this->tableName = trim($this->option('table'), ' =');
$modules = Module::where('enabled', true)
->get()
->pluck('static_name', 'id')
->toArray();
while (is_null($module) || !in_array($module, $modules)) {
$module = $this->anticipate('Input valid module name', $modules);
}
$selectedModule = Module::where('static_name', $module)
->first();
$basePath = $selectedModule->is_template ? config('modules.path.template') : config('modules.paths.modules');
$path = $basePath . '/' . $module . '/Database/Migrations/';
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
while (is_null($name)) {
$this->migrationName = $name = $this->ask('Input migration name');
}
$stubName = $this->option('create') ? 'create' : 'new';
$content = file_get_contents(config('modules.paths.stubs') . '/Migrations/' . $stubName . '.stub');
$content = $this->replacePlaceholders($content);
$migrationName = $path . $this->getMigrationName($name);
file_put_contents($migrationName, $content);
$this->line('Migration successfully created.', 'info');
}
/**
* Find and replace all placeholders in given content
*
* @param $content
*
* @return mixed
*/
private function replacePlaceholders($content)
{
$replace = [
'$MigrationName$' => studly_case($this->migrationName),
'$ModuleName$' => $this->moduleName,
'$TableName$' => $this->tableName
];
foreach ($replace as $what => $for) {
$content = str_replace($what, $for, $content);
}
return $content;
}
/**
* Get prefix for created migration
* @return false|string
*/
protected function getDatePrefix()
{
return date('Y_m_d_His');
}
/**
* @param $name
*
* @return string
*/
private function getMigrationName($name)
{
return $this->getDatePrefix() . '_' . snake_case($name) . '.php';
}
}
+4 -1
View File
@@ -42,7 +42,7 @@ class CreateNew extends Command
mkdir($path);
// copy stub files
\File::copyDirectory(config('modules.paths.stubs'), $path);
\File::copyDirectory(config('modules.paths.stubs').'/NewModule', $path);
$files = \File::allFiles($path);
foreach ($files as $file) {
@@ -64,6 +64,9 @@ class CreateNew extends Command
}
$this->info('Module successfully created.');
$this->call('module:install', ['name' => $this->moduleName]);
}
/**
@@ -40,6 +40,7 @@ class DisableModule extends Command
$module->save();
\Cache::forget('enabled-modules');
\Cache::forget('enabled-content-modules');
\Cache::forget('enabled-modules-and-template');
$this->line('Module ' . $module->static_name . ' disabled.');
@@ -44,6 +44,7 @@ class EnableModule extends Command
$module->save();
\Cache::forget('enabled-modules');
\Cache::forget('enabled-content-modules');
\Cache::forget('enabled-modules-and-template');
$this->line('Module ' . $module->static_name . ' enabled.');
@@ -67,6 +67,8 @@ class InstallModule extends Command
Cache::forget('enabled-modules');
Cache::forget('module-handler-to-id-enumeration');
exec('php artisan module:enable '.$name);
exec('php artisan cache:clear');
exec('composer dump-autoload');
// inform user
@@ -0,0 +1,49 @@
<?php
namespace App\Console\Commands\Modules;
use App\Models\Module;
use Illuminate\Console\Command;
class RunMigrations extends Command
{
/**
* The name and signature of the console command.
* @var string
*/
protected $signature = 'module:migrate {module?} {--rollback : Rollback one migration}';
/**
* The console command description.
* @var string
*/
protected $description = 'Run migrations for all modules or for one module';
/**
* Execute the console command.
* @return mixed
*/
public function handle()
{
$modules = Module::where('enabled', true);
if (!is_null($module = $this->argument('module'))) {
$modules = $modules->where('static_name', $module);
}
$modules = $modules->get();
if ($modules->isEmpty()) {
$this->error('No valid modules.');
return;
}
$command = $this->option('rollback') ? 'migrate:rollback' : 'migrate';
foreach ($modules as $module) {
$this->info('Migrating '.$module->static_name);
$basePath = $module->is_template ? config('modules.path.templates') : config('modules.paths.modules');
$path = $basePath . '/' . $module->static_name . '/Database/Migrations/';
$path = str_replace(base_path(), '', $path);
$this->call($command, ['--path' => $path]);
}
}
}
+6 -9
View File
@@ -3,6 +3,7 @@
namespace App\Console\Commands;
use App\CMS\Enumerations\UserRoles;
use App\Events\CreateNewUser;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Hash;
@@ -11,13 +12,11 @@ class NewUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'user:new {email}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Creates new user';
@@ -27,13 +26,9 @@ class NewUser extends Command
*/
public function handle()
{
$email = $this->argument('email');
// check if username is really email
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$this->error($email . ' is not a valid e-mail!');
return;
}
do {
$email = $this->argument('email');
} while (!filter_var($email, FILTER_VALIDATE_EMAIL));
// ask for password
do {
@@ -63,6 +58,8 @@ class NewUser extends Command
$user->role = $role;
$user->save();
event(new CreateNewUser($user));
$this->info('User ' . $email . ' successfully created.');
}
}
+1 -1
View File
@@ -74,7 +74,7 @@ class SetTemplate extends Command
// run again artisan for publishing resources
// it cannot be done using $this->call, because we need to load different template into service providers
if ($publish) {
exec('php artisan vendor:publish');
exec('php artisan template:publish');
}
}
}
+7 -1
View File
@@ -2,6 +2,9 @@
namespace App\Console;
use App\Console\Commands\InstallCMS;
use App\Console\Commands\Modules\CreateMigration;
use App\Console\Commands\Modules\RunMigrations;
use App\Console\Commands\Modules\CreateNew;
use App\Console\Commands\Modules\DisableModule;
use App\Console\Commands\Modules\EnableModule;
@@ -32,7 +35,10 @@ class Kernel extends ConsoleKernel
Commands\SetTemplate::class,
Commands\AddLanguage::class,
PublishTemplateResources::class,
TemplateInfo::class
TemplateInfo::class,
InstallCMS::class,
CreateMigration::class,
RunMigrations::class
];
/**
@@ -33,7 +33,7 @@ class ContentOverview extends Controller
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @internal param int|null $moduleId
*/
public function index(Module $module = null, $status = null)
public function index(Module $module, $status = null)
{
// get module settings
$pageHeading = $this->module->getOverviewTitle($module);
@@ -117,4 +117,24 @@ class EditContent extends Controller
->route('content.overview')
->with('success', trans('admin/contents.successfullyEdited'));
}
public function order() {
$pages = $this->content->getOverview()->get();
return view('admin.content.order', compact('pages'));
}
public function setOrder(Request $request) {
$data = $request->get('page');
foreach ($data as $id => $order) {
Content::where('id', $id)->update(['order' => $order]);
}
// something was changed, inform user
return redirect()
->route('content.overview')
->with('success', trans('admin/contents.orderSuccessfullySet'));
}
}
@@ -30,12 +30,12 @@ class UploadedFilesOverview extends Controller
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function index(Directory $directory = null)
public function index(Directory $directory)
{
// include hidden directories?
$subdirectories = $this->directoryRepository->getAllSubdirectories($directory);
if (!Input::get('hidden', true)) {
if (!Input::get('hidden', false)) {
$subdirectories = $subdirectories->where('hidden', false);
}
+1
View File
@@ -52,6 +52,7 @@ class Settings extends Controller
*/
public function saveSettings(Requests\SaveSettingsRequest $request)
{
$this->settings->save($request->except(['_token']));
return redirect()
@@ -98,7 +98,7 @@ class EditTemplate extends Controller
// try to save content
if (!is_writable($customDir) && !is_writable($originalDir)) {
return redirect()
->route('templates.edit', ['id' => $request->id])
->route('templates.edit', ['id' => $template->id])
->withInput()
->with('warning', trans('admin/templates.cannotWriteContent'));
}
@@ -7,6 +7,16 @@ use App\Models\Templates\TemplatePath;
class TemplateOverview extends Controller
{
public function index()
{
$templatePaths = TemplatePath::with('subdirectories')
->whereNull('parent_id')
->get();
return view('admin.templates.index', compact('templatePaths'));
}
/**
* Display overview of all templates in given path
*
@@ -17,12 +27,8 @@ class TemplateOverview extends Controller
public function getPath(TemplatePath $templatePath)
{
return view('admin.templates.list', [
'directory' => $templatePath,
'isWritable' => is_writable(base_path($templatePath->path)),
'templates' => $templatePath->templates()
->get(),
'subdirectories' => $templatePath->subdirectories()
->get()
'directory' => $templatePath,
'isWritable' => is_writable(base_path($templatePath->path))
]);
}
}
+17 -3
View File
@@ -14,7 +14,6 @@ class Controller extends BaseController
/**
* Custom wrapper for generating view.
*
* This method will be used for switching among templates.
*
* @param $template
@@ -25,8 +24,23 @@ class Controller extends BaseController
*/
public static function visitorsView($template, $data = [], $mergeData = [])
{
$view = Template::name($template);
$view = self::getView($template, $data, $mergeData);
return response(view($view, $data, $mergeData))->header('X-Powered-By', strrev('zc.ytiranib.www//:sptth | .o.r.s ytiranib | SMCiniM'));
return response($view)->header('X-Powered-By', strrev('zc.ytiranib.www//:sptth | .o.r.s ytiranib | SMCiniM'));
}
/**
* Get instance of view for passing into response
*
* @param $template
* @param $data
* @param $mergeData
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public static function getView($template, $data = [], $mergeData = [])
{
$view = Template::name($template);
return view($view, $data, $mergeData);
}
}
@@ -26,6 +26,8 @@ class TemplatePathInstaller
// install registered widgets
$registator->saveTemplates();
$registator->deleteNonExistingPaths();
return $next($request);
}
}
+1 -1
View File
@@ -56,6 +56,6 @@ class CreateImageThumbnail implements ShouldQueue
});
// save thumbnail with lower quality
$image->save(config('app.thumbnail_path') . DIRECTORY_SEPARATOR . $file->getFilename(), 75);
$image->save(config('app.thumbnail_path') . DIRECTORY_SEPARATOR . $file->getFilename(), setting('previewQuality', 75));
}
}
+28 -1
View File
@@ -7,6 +7,7 @@ use App\CMS\Helpers\Traits\Nullable;
use App\CMS\Observers\Content as ContentObserver;
use App\Models\FileManager\File;
use App\Models\Module;
use App\Models\Templates\Template;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
@@ -33,6 +34,7 @@ class Content extends Model
'isHomepage',
'title',
'url',
'order',
'metaKeywords',
'metaDescription',
'pageContent',
@@ -63,6 +65,10 @@ class Content extends Model
return $this->hasMany(ContentHistory::class);
}
public function templateModel() {
return $this->belongsTo(Template::class, 'template', 'template_name');
}
/**
* Mark relationship with users table
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
@@ -87,6 +93,10 @@ class Content extends Model
*/
public function category()
{
if (!class_exists(Category::class)) {
throw new \ErrorException('Categories are not installed');
}
return $this->belongsTo(Category::class);
}
@@ -96,7 +106,24 @@ class Content extends Model
*/
public function subpages()
{
return $this->hasMany(Content::class, 'parentId');
return $this->hasMany(Content::class, 'parentId')->orderBy('order')->orderBy('created_at', 'DESC');
}
/**
* Subpages assigned to page
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function publishedSubpages()
{
$query = $this->subpages();
if (\Auth::check()) {
$query = $query->where('status', '!=', ContentContract::STATUS_DRAFT);
} else {
$query = $query->where('status', ContentContract::STATUS_PUBLIC);
}
return $query;
}
/**
-1
View File
@@ -3,7 +3,6 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class Settings extends Model
{
+1 -1
View File
@@ -5,6 +5,7 @@ namespace App\Policies;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
abstract class BasicPolicy
{
@@ -20,7 +21,6 @@ abstract class BasicPolicy
*/
public function before(User $user, $ability)
{
// check if user can operate on given entity
if (!$this->manage($user)) {
return false;
+66 -3
View File
@@ -2,6 +2,7 @@
namespace App\Policies;
use App\CMS\Contracts\Repositories\Content as ContentContract;
use App\Models\Content\Content;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
@@ -35,21 +36,83 @@ class ContentPolicy extends BasicPolicy
*
* @return bool
*/
public function create(User $user) {
public function create(User $user)
{
return $user->hasAbility('create-contents');
}
public function publish(User $user)
/**
* Change page status
*
* @param User $user
* @param Content $page
* @param $status
*
* @return bool
*/
public function changeStatus(User $user, Content $page, $status)
{
switch ($status) {
case ContentContract::STATUS_PUBLIC:
return $this->publish($user, $page);
break;
case ContentContract::STATUS_DRAFT:
return $this->draft($user, $page);
break;
case ContentContract::STATUS_PROTECTED:
return $this->protect($user, $page);
break;
}
return false;
}
/**
* Can user publish given page?
*
* @param User $user
* @param Content $page
*
* @return bool
*/
public function publish(User $user, Content $page)
{
return $user->hasAbility('publish-contents');
}
/**
* Can user make draft from given page?
*
* @param User $user
* @param Content $page
*
* @return bool
*/
public function draft(User $user, Content $page)
{
return $user->hasAbility('draft-contents');
}
/**
* Can user publish page only for protected users?
*
* @param User $user
* @param Content $page
*
* @return bool
*/
public function protect(User $user, Content $page)
{
return $user->hasAbility('protect-contents');
}
public function setHomepage(User $user)
{
return $user->hasAbility('set-homepage-contents');
}
public function viewHistory(User $user) {
public function viewHistory(User $user)
{
return $user->hasAbility('view-history-contents');
}
}
+2 -3
View File
@@ -62,7 +62,6 @@ class AppServiceProvider extends ServiceProvider
$this->app->register(DebugBarServiceProvider::class);
}
// register PingPong module extension
$this->app->register(LaravelLocalizationServiceProvider::class);
// create singletons for registering widgets
@@ -120,7 +119,7 @@ class AppServiceProvider extends ServiceProvider
$registrator->register('basic', 'admin/settings.basic', 'admin.settings.parts.basic');
$registrator->register('meta', 'admin/settings.meta', 'admin.settings.parts.meta');
$registrator->register('social', 'admin/settings.socialSites', 'admin.settings.parts.social');
$registrator->register('widgets', 'admin/settings.widgets.title', 'admin.settings.parts.widgets');
$registrator->register('advanced', 'admin/settings.advanced.title', 'admin.settings.parts.advanced', 999);
}
/**
@@ -139,7 +138,7 @@ class AppServiceProvider extends ServiceProvider
$registrator = $this->app->make('displayPipeline');
$registrator->add(AddViewedToPage::class);
$registrator->add(CompileShortcodes::class);
// $registrator->add(CompileShortcodes::class);
}
private function registerSavePipeline()
+1 -1
View File
@@ -26,7 +26,7 @@ class BladeExtender extends ServiceProvider
$this->extendBlade();
Shortcode::register('widget', Widget::class);
// Shortcode::register('widget', Widget::class);
}
/**
@@ -1,5 +1,6 @@
<?php namespace App\Providers;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
@@ -8,8 +9,19 @@ class LaravelLocalizationServiceProvider extends ServiceProvider
{
public function register()
{
$languages = DB::table('languages')
->get();
try {
$languages = DB::table('languages')
->get();
} catch (QueryException $e) {
$supportedLocales[config('app.locale')] = [
'native' => env('LOCALE_NATIVE_NAME', config('app.locale')),
'script' => env('LOCALE_SCRIPT', 'Latn'),
'name' => env('LOCALE_TRANSLATED_NAME', config('app.locale')),
'code' => config('app.locale'),
];
$this->setSupportedLocales($supportedLocales);
return;
}
$supportedLocales = [];
if (empty($languages)) {
@@ -32,15 +44,20 @@ class LaravelLocalizationServiceProvider extends ServiceProvider
];
}
config([
'laravellocalization.supportedLocales' => $supportedLocales,
'laravellocalization.useAcceptLanguageHeader' => true,
'laravellocalization.hideDefaultLocaleInURL' => true
]);
$this->setSupportedLocales($supportedLocales);
}
public function boot()
{
\App::setLocale(LaravelLocalization::getCurrentLocale());
}
private function setSupportedLocales($supportedLocales)
{
config([
'laravellocalization.supportedLocales' => $supportedLocales,
'laravellocalization.useAcceptLanguageHeader' => true,
'laravellocalization.hideDefaultLocaleInURL' => true
]);
}
}
+6 -1
View File
@@ -31,7 +31,12 @@ class RouteServiceProvider extends ServiceProvider
*/
protected function mapAdminRoutes()
{
Route::namespace($this->namespace.'\\Admin')
// separate route file for Auth::routes()
Route::namespace($this->namespace)
->group(base_path('routes/auth.php'));
// routes for administration
Route::namespace($this->namespace . '\\Admin')
->group(base_path('routes/admin.php'));
}
+7 -7
View File
@@ -6,6 +6,7 @@ use App\CMS\Contracts\Repositories\Template as TemplateContract;
use App\CMS\Handlers\Registrators\TemplateRegistrator;
use App\CMS\Helpers\CurrentTemplate;
use App\CMS\Repositories\Module;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\App;
use Illuminate\Support\ServiceProvider;
@@ -13,7 +14,11 @@ class TemplateServiceProvider extends ServiceProvider
{
public function boot()
{
$template = CurrentTemplate::get();
try {
$template = CurrentTemplate::get();
} catch (QueryException $e) {
return;
}
// ignore running from artisan
if (App::runningInConsole() || App::environment('testing') || !$template) {
@@ -22,12 +27,7 @@ class TemplateServiceProvider extends ServiceProvider
return;
}
// include files
$files = isset($template->moduleSettings->files) ? $template->moduleSettings->files : [];
foreach ($files as $file) {
include_once $file;
}
// service providers and files already registered in ModuleManager
// register templates
$publicTemplates = CurrentTemplate::getPublicTemplatePaths();
+1 -17
View File
@@ -14,21 +14,5 @@ define('LARAVEL_START', microtime(true));
|
*/
require_once __DIR__ . '/../app/CMS/Helpers/functions.php';
require __DIR__.'/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Include The Compiled Class File
|--------------------------------------------------------------------------
|
| To dramatically increase your application's performance, you may use a
| compiled class file which contains all of the classes commonly used
| by a request. The Artisan "optimize" is used to create this file.
|
*/
$compiledPath = __DIR__.'/cache/compiled.php';
if (file_exists($compiledPath)) {
require $compiledPath;
}
+4 -3
View File
@@ -5,8 +5,8 @@
"dependencies": {
"animate.css": "~3.4.0",
"bootstrap": "v4.0.0-alpha.5",
"font-awesome": "~4.5.0",
"jquery": "~2.1.4",
"font-awesome": "~4.7.0",
"jquery": "~3.2.1",
"metisMenu": "~2.0.3",
"nprogress": "~0.2.0",
"responsive-bootstrap-toolkit": "~2.5.0",
@@ -14,6 +14,7 @@
"tether": "~1.3.7",
"tinycolor": "~1.2.1",
"dropzone": "~4.2.0",
"jquery.are-you-sure": "~1.9"
"jquery.are-you-sure": "~1.9",
"chart.js": "^2.5.0"
}
}
+3 -2
View File
@@ -8,13 +8,14 @@
"type": "project",
"require": {
"php": ">=7.0.0",
"laravel/framework": "5.4.*",
"laravel/framework": "5.5.*",
"watson/sitemap": "^2.0",
"mcamara/laravel-localization": "^1.1",
"franzose/closure-table": "5.*",
"intervention/image": "^2.3",
"webwizo/laravel-shortcodes": "1.0.4",
"webwizo/laravel-shortcodes": "1.*",
"greggilbert/recaptcha": "^2.2@dev",
"doctrine/dbal": "^2.7@dev",
"nwidart/laravel-menus": "dev-master"
},
"require-dev": {
Generated
+776 -188
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -160,7 +160,7 @@ return [
Franzose\ClosureTable\ClosureTableServiceProvider::class,
\Watson\Sitemap\SitemapServiceProvider::class,
Intervention\Image\ImageServiceProvider::class,
Webwizo\Shortcodes\ShortcodesServiceProvider::class,
// Webwizo\Shortcodes\ShortcodesServiceProvider::class,
/*
* Application Service Providers...
*/
+3 -5
View File
@@ -3,11 +3,9 @@
return [
'styles' => [
'foundation-drilldown' => App\CMS\MenuPresenters\FoundationDrilldownMenuPresenter::class,
'foundation-dropdown' => App\CMS\MenuPresenters\FoundationDropdownMenuPresenter::class,
'foundation-dropdown-initialized' => App\CMS\MenuPresenters\FoundationInitializedDropdownMenuPresenter::class,
'metismenu' => App\CMS\MenuPresenters\MetismenuPresenter::class,
'profile-menu' => App\CMS\MenuPresenters\ProfileMenuPresenter::class,
'metismenu' => App\CMS\MenuPresenters\MetismenuPresenter::class,
'profile-menu' => App\CMS\MenuPresenters\ProfileMenuPresenter::class,
'top-menu' => \App\CMS\MenuPresenters\TopMenuPresenter::class
],
'ordering' => true,
+2 -1
View File
@@ -4,7 +4,8 @@ return [
'namespace' => 'Modules',
'paths' => [
'modules' => base_path('modules'),
'templates' => base_path('templates'),
'assets' => public_path('modules'),
'stubs' => base_path('app/CMS/Modules/Stubs'),
'stubs' => base_path('app/CMS/Modules/Stubs'),
]
];
+4 -1
View File
@@ -28,10 +28,13 @@ $factory->define(User::class, function (Faker\Generator $faker) {
});
$factory->define(Content::class, function (Faker\Generator $faker) {
$slug = isset($faker->slug) ? $faker->slug : $faker->slug(5);
return [
'title' => $faker->sentence(5),
'userId' => 1,
'url' => $faker->slug(5),
'url' => $slug,
'pageContent' => $faker->text(1500),
'metaDescription' => $faker->text,
'moduleHandler' => config('staticpages.handler'),
@@ -1,5 +1,6 @@
<?php
use App\Models\Widgets\Widget;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
@@ -45,12 +46,16 @@ class AddUniqueCodeToWidgets extends Migration
*/
public function down()
{
Schema::table('widgets', function (Blueprint $table) {
$table->dropUnique('widgets_language_container_id_unique');
});
try {
Schema::table('widgets', function (Blueprint $table) {
$table->dropUnique('widgets_language_container_id_unique');
});
} catch (\Exception $e) {
}
// migrate data
$widgets = \App\Models\Widget::all();
$widgets = Widget::all();
foreach ($widgets as $widget) {
$widget->settings = (object)json_decode($widget->settings);
$widget->settings->containerClass = $widget->container_class;
@@ -27,7 +27,6 @@ class RenameColumnInContents extends Migration
'url',
'meta_keywords',
'meta_description',
'content',
'module_settings',
'status'
];
@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
class DropCustomFieldsTables extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::dropIfExists('content_has_custom_fields');
Schema::dropIfExists('user_has_custom_field');
Schema::dropIfExists('custom_field_resource');
Schema::dropIfExists('custom_fields');
Schema::dropIfExists('custom_field_resources');
Schema::dropIfExists('custom_field_types');
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
//
}
}
@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddOrderToContent extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
Schema::table('contents', function (Blueprint $table) {
$table->integer('order')
->after('viewed')
->default(0);
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::table('contents', function (Blueprint $table) {
$table->dropColumn('order');
});
}
}
+27 -23
View File
@@ -1,6 +1,19 @@
var elixir = require ('laravel-elixir');
require ('laravel-elixir-remove')
elixir (function (mix) {
var defaultColor = "green";
var colors = ["blue", "seagreen", 'orange', "green", 'purple', 'red'];
var outputName;
colors.forEach (function (color) {
outputName = color === defaultColor ? 'app.css' : 'app-' + color + ".css";
mix.copy ('resources/assets/sass/admin/_themes/' + color + '-theme.scss', 'public/css/admin/theme.scss')
.sass ([
'admin/**/!(_imports|_variables|*-theme)*.scss',
'../admin/css'
], 'public/css/admin/' + outputName, null, {includePaths: ['bower_components', 'resources/assets/sass/admin']})
})
// vendor files
mix
@@ -11,28 +24,19 @@ elixir (function (mix) {
'responsive-bootstrap-toolkit/dist/bootstrap-toolkit.js',
'metisMenu/dist/metisMenu.min.js',
'tinycolor/dist/tinycolor-min.js',
'chart.js/dist/Chart.bundle.min.js',
'jquery.are-you-sure/jquery.are-you-sure.js',
'../resources/assets/admin/js/app.js',
], 'public/js/vendor.js', 'bower_components');
var defaultColor = "green";
var colors = ["blue", "seagreen", 'orange', "green", 'purple', 'red'];
var outputName;
colors.forEach (function (color) {
outputName = color == defaultColor ? 'app.css' : 'app-' + color + ".css";
mix.copy ('resources/assets/sass/admin/_themes/' + color + '-theme.scss', 'public/css/admin/theme.scss');
mix.sass ([
'admin/**/!(_imports|_variables|*-theme)*.scss',
'../admin/css/custom.css'
], 'public/css/admin/' + outputName, null, {includePaths: ['bower_components', 'resources/assets/sass/admin']});
})
mix.copy ('bower_components/font-awesome/css/font-awesome.min.css', 'public/css');
mix.copy ('bower_components/font-awesome/fonts', 'public/fonts');
mix.sass (['bootstrap/bootstrap.scss'], 'public/css/admin/bootstrap.css');
mix.styles ([
'../../../public/css/admin/bootstrap.css',
'../../../bower_components/animate.css/animate.css',
], 'public/css/admin/style.css');
'../node_modules/bootstrap-datepicker/dist/js/bootstrap-datepicker.js',
'../resources/assets/admin/js/*.js',
], 'public/js/vendor.js', 'bower_components')
.copy ('bower_components/font-awesome/css/font-awesome.min.css', 'public/css')
.copy ('node_modules/bootstrap-datepicker/dist/css/bootstrap-datepicker.css', 'public/css')
.copy ('bower_components/font-awesome/fonts', 'public/fonts')
.sass (['bootstrap/bootstrap.scss'], 'public/css/admin/bootstrap.css')
.styles ([
'../../../public/css/admin/bootstrap.css',
'../../../public/css/bootstrap-datepicker.css',
'../../../bower_components/animate.css/animate.css',
], 'public/css/admin/style.css')
.remove ('public/css/admin/theme.scss');
});
-1
View File
@@ -16,5 +16,4 @@ if ($uri !== '/' && file_exists(__DIR__ . '/public' . $uri)) {
return false;
}
require_once __DIR__ . '/app/CMS/Helpers/functions.php';
require_once __DIR__ . '/public/index.php';
+5499 -6118
View File
File diff suppressed because it is too large Load Diff
+5 -6
View File
@@ -5,15 +5,14 @@
"dev": "gulp watch"
},
"devDependencies": {
"bootstrap-sass": "^3.3.7",
"bower": "1.8.0",
"gulp": "^3.9.1",
"jquery": "^3.2.1",
"laravel-elixir": "^6.0.0-11",
"laravel-elixir-vue-2": "^0.2.0",
"laravel-elixir-webpack-official": "^1.0.2",
"lodash": "^4.16.2",
"vue": "^2.4.2",
"vue-resource": "^1.3.4"
"lodash": "^4.16.2"
},
"dependencies": {
"bootstrap-datepicker": "^1.7.1",
"laravel-elixir-remove": "^0.2.1"
}
}
+1 -1
View File
@@ -10,7 +10,7 @@
stopOnFailure="false">
<testsuites>
<testsuite name="unit">
<directory>./tests/unit/</directory>
<directory>./tests/Unit/</directory>
</testsuite>
</testsuites>
<filter>
+66
View File
@@ -14,3 +14,69 @@
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
</IfModule>
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>
#
# Leverage Browser Caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType text/html "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType text/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 1 month"
</IfModule>
<IfModule mod_headers.c>
<filesmatch "\.(ico|flv|jpg|jpeg|png|gif|css|swf)$">
Header set Cache-Control "max-age=2678400, public"
</filesmatch>
<filesmatch "\.(html|htm)$">
Header set Cache-Control "max-age=7200, private, must-revalidate"
</filesmatch>
<filesmatch "\.(pdf)$">
Header set Cache-Control "max-age=86400, public"
</filesmatch>
<filesmatch "\.(js)$">
Header set Cache-Control "max-age=2678400, private"
</filesmatch>
</IfModule>
@@ -0,0 +1,46 @@
<html>
<head>
<meta charset="utf-8">
<script src="multiselectcomponent.js"></script>
</head>
<body>
<div style="width: 50%; float: left;" id="left"></div>
<div style="width: 50%; float: right;" id="right"></div>
<script type="application/javascript">
// Sample data.
var data1 = [
{id: 1, name: 'Peter', surname: 'Hrdlica'},
{id: 6, name: 'Vojtěch', surname: 'Hrdlica'},
{id: 2, name: 'Michal', surname: 'Kváček'},
{id: 19, name: 'Miček', surname: 'Je kokot!'},
{id: 13, name: 'Mirek', surname: 'Mráček'},
{id: 11, name: 'Naděžda', surname: 'Zímová'}
];
var data2 = [
{id: 2, name: 'wanna', surname: 'know'},
{id: 6, name: 'Batman', surname: 'insulted'},
{id: 58, name: 'scream', surname: 'pushed'},
{id: 19, name: 'Mob', surname: 'why'},
{id: 63, name: 'eight', surname: 'begin'},
{id: 4, name: 'you', surname: 'emotions'}
];
data1.sort(function(a, b) { return a.id > b.id; }); // Sort by ID, lowest first.
data2.sort(function(a, b) { return a.id > b.id; }); // Sort by ID, lowest first.
// Js component instance
var mscL = new MultiSelectComponent('contacts', data1, 'id', function(item) { return item.name + ' ' + item.surname; });
var mscR = new MultiSelectComponent('users', data2, 'id', function(item) { return item.name + ' ' + item.surname; });
// Generated data added to template
var left = document.getElementById('left');
var right = document.getElementById('right');
left.innerHTML = mscL.createTemplate();
right.innerHTML = mscR.createTemplate();
// Initialization. May be done in more elegant way if the template is created ie. on server.
mscL.init();
mscR.init();
</script>
</body>
</html>
@@ -0,0 +1,121 @@
/**
* Multi-select component
*
* @param identifier Identifier parameter that makes each instance unique and is used in DOM datasets used by this component.
* @param data Data (array of objects)
* @param field Field parameter that will be send as list with form
* @param itemString String that should be shown as selector in select and a item label in item list
*/
function MultiSelectComponent(identifier, data, field, itemString) {
// Private variables
var selectBox, addButton, itemHolder;
/**
* This is the method that generates template for multiselect component.
* This method is easily rewriteable into PHP.
* It is necessary to keep html datasets with prefix data-ms- intact for the javascript component to work.
* ECMAScript 5 version, does not need any compilers, nor jQuery or other framework.
* This method is not required to stay inside the MultiSelectComponent and may be rendered in any way;
*
* identifier is inherited from the instance creation.
* data is inherited from the instance creation.
* field is inherited from the instance creation.
* itemString is inherited from the instance creation.
*
*/
function createTemplate () {
var html = '<select data-ms-select="'+identifier+'">';
for(var idx in data) {
if(data.hasOwnProperty(idx)) {
html += '<option value="'+data[idx][field]+'">'+itemString(data[idx])+'</value>' //createSelectOption(data[idx]);
}
}
return html += '</select><input type="button" data-ms-add="'+identifier+'" value="add"><div data-ms-list="'+identifier+'"></div>';
}
/**
* This method creates an item list item that works as visual representation of selected values.
*/
function createItemListItem (value) {
return html = '<span>'+itemString(getDataItem(value))+
' <span data-ms-remove="'+identifier+'" data-ms-value="'+value+'">x</span>'+
'<input style="display: none" type="checkbox" value="'+value+'" name="'+identifier+'[]" checked>'+
'</span>';
}
/**
* Returns a requested data item that matches <field> (class instance variable field) value of passed value.
*/
function getDataItem (value) {
for(var idx in data) {
if(data.hasOwnProperty(idx)){
if(data[idx][field] == value){
return data[idx];
}
}
}
}
/**
* By selecting an item, that item is removed from list of available items and is added to list of selected items.
* If no more items are available for adding, add button and selectbox are disabled and list gets an informative item.
*/
function selectItem (value) {
selectBox.removeChild(selectBox.querySelector('option[value="' + value + '"]'));
itemHolder.innerHTML += createItemListItem(value);
if(selectBox.children.length === 0) {
selectBox.options.add(new Option('no more items to add', 0));
addButton.setAttribute('disabled', 'disabled');
selectBox.setAttribute('disabled', 'disabled');
}
}
/**
* By deselecting (removing) an item, that item is removed from selected list and added again into select box of available items;
* If add button was disabled (mostly because of no selectable items in list) it and the selectbox are now re-enabled and informative item is removed.
*/
function deselectItem (element) {
var id = element.getAttribute('data-ms-value');
selectBox.options.add(new Option(itemString(getDataItem(id)), id));
itemHolder.removeChild(element.parentNode);
if(addButton.getAttribute('disabled')) {
selectBox.options.remove(0);
addButton.removeAttribute('disabled');
selectBox.removeAttribute('disabled');
}
}
/**
* Initializes javascript part of the component.
*/
function init () {
// Cached elements only for JS to be a little more optimized.
selectBox = document.querySelector('[data-ms-select="'+identifier+'"]');
addButton = document.querySelector('[data-ms-add="'+identifier+'"]');
itemHolder = document.querySelector('[data-ms-list="'+identifier+'"]');
// Add button
addButton.addEventListener('click', function() {
selectItem(selectBox.value);
});
// Remove item button
itemHolder.addEventListener('click', function(e) {
if(e.target.getAttribute('data-ms-remove')) {
deselectItem(e.target);
}
})
}
// Publicly exposed static methods and variables.
return {
init: init,
createTemplate: createTemplate
};
}
Regular → Executable
View File
+52 -30
View File
@@ -18,6 +18,11 @@ a:focus {
opacity: .7;
}
.collapse.in {
margin-bottom: 20px !important;
border-bottom: solid 2px !important;
}
.nav.nav-tabs-bordered + .tab-content {
padding-bottom: 20px !important;
}
@@ -324,7 +329,7 @@ img {
.card.file-preview .card-block {
padding: 0;
height: 6em;
height: 9em;
overflow: hidden;
}
@@ -341,78 +346,95 @@ img {
}
/*.tag {*/
/*display: inline-block;*/
/*padding: 0.25em 0.4em;*/
/*font-size: 75%;*/
/*font-weight: bold;*/
/*line-height: 1;*/
/*color: #FFF;*/
/*text-align: center;*/
/*white-space: nowrap;*/
/*vertical-align: baseline;*/
/*border-radius: 0.25rem;*/
/*display: inline-block;*/
/*padding: 0.25em 0.4em;*/
/*font-size: 75%;*/
/*font-weight: bold;*/
/*line-height: 1;*/
/*color: #FFF;*/
/*text-align: center;*/
/*white-space: nowrap;*/
/*vertical-align: baseline;*/
/*border-radius: 0.25rem;*/
/*}*/
/*.tag:empty {*/
/*display: none;*/
/*display: none;*/
/*}*/
/*.btn .tag {*/
/*position: relative;*/
/*top: -1px;*/
/*position: relative;*/
/*top: -1px;*/
/*}*/
/*a.tag:focus, a.tag:hover {*/
/*color: #FFF;*/
/*text-decoration: none;*/
/*cursor: pointer;*/
/*color: #FFF;*/
/*text-decoration: none;*/
/*cursor: pointer;*/
/*}*/
/*.tag-pill {*/
/*padding-right: 0.6em;*/
/*padding-left: 0.6em;*/
/*border-radius: 10rem;*/
/*padding-right: 0.6em;*/
/*padding-left: 0.6em;*/
/*border-radius: 10rem;*/
/*}*/
/*.tag-default {*/
/*background-color: #818A91;*/
/*background-color: #818A91;*/
/*}*/
/*.tag-default[href]:focus, .tag-default[href]:hover {*/
/*background-color: #687077;*/
/*background-color: #687077;*/
/*}*/
/*.tag-success {*/
/*background-color: #5CB85C;*/
/*background-color: #5CB85C;*/
/*}*/
/*.tag-success[href]:focus, .tag-success[href]:hover {*/
/*background-color: #449D44;*/
/*background-color: #449D44;*/
/*}*/
/*.tag-info {*/
/*background-color: #5BC0DE;*/
/*background-color: #5BC0DE;*/
/*}*/
/*.tag-info[href]:focus, .tag-info[href]:hover {*/
/*background-color: #31B0D5;*/
/*background-color: #31B0D5;*/
/*}*/
/*.tag-warning {*/
/*background-color: #F0AD4E;*/
/*background-color: #F0AD4E;*/
/*}*/
/*.tag-warning[href]:focus, .tag-warning[href]:hover {*/
/*background-color: #EC971F;*/
/*background-color: #EC971F;*/
/*}*/
/*.tag-danger {*/
/*background-color: #D9534F;*/
/*background-color: #D9534F;*/
/*}*/
/*.tag-danger[href]:focus, .tag-danger[href]:hover {*/
/*background-color: #C9302C;*/
/*background-color: #C9302C;*/
/*}*/
.has-subpages:hover {
cursor: pointer;
}
#orderSetup .subpage td:first-child {
padding-left: 35px;
}
.nav-profile .dropdown-menu > li {
width: 100%;
padding: 3px 1.5rem;
clear: both;
font-weight: normal;
color: #373a3c;
text-align: inherit;
white-space: nowrap;
background: none;
border: 0;
}
+25 -434
View File
@@ -1,429 +1,9 @@
var config = window.config = {};
// Config reference element
var $ref = $ ("#ref");
// Configure responsive bootstrap toolkit
config.ResponsiveBootstrapToolkitVisibilityDivs = {
'xs': $ ('<div class="device-xs hidden-sm-up"></div>'),
'sm': $ ('<div class="device-sm hidden-xs-down hidden-md-up"></div>'),
'md': $ ('<div class="device-md hidden-sm-down hidden-lg-up"></div>'),
'lg': $ ('<div class="device-lg hidden-md-down hidden-xl-up"></div>'),
'xl': $ ('<div class="device-xl hidden-lg-down"></div>')
};
ResponsiveBootstrapToolkit.use ('Custom', config.ResponsiveBootstrapToolkitVisibilityDivs);
//validation configuration
config.validations = {
debug: true,
errorClass: 'has-error',
validClass: 'success',
errorElement: "span",
// add error class
highlight: function (element, errorClass, validClass) {
$ (element).parents ("div.form-group")
.addClass (errorClass)
.removeClass (validClass);
},
// add error class
unhighlight: function (element, errorClass, validClass) {
$ (element).parents (".has-error")
.removeClass (errorClass)
.addClass (validClass);
},
// submit handler
submitHandler: function (form) {
form.submit ();
}
};
//delay time configuration
config.delayTime = 50;
// chart configurations
config.chart = {};
/***********************************************
* Animation Settings
***********************************************/
function animate(options) {
var animationName = "animated " + options.name;
var animationEnd = "webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend";
$ (options.selector)
.addClass (animationName)
.one (animationEnd,
function () {
$ (this).removeClass (animationName);
}
);
}
$ (function () {
var $itemActions = $ (".item-actions-dropdown");
$ (document).on ('click', function (e) {
if (!$ (e.target).closest ('.item-actions-dropdown').length) {
$itemActions.removeClass ('active');
}
});
$ ('.item-actions-toggle-btn').on ('click', function (e) {
e.preventDefault ();
var $thisActionList = $ (this).closest ('.item-actions-dropdown');
$itemActions.not ($thisActionList).removeClass ('active');
$thisActionList.toggleClass ('active');
});
});
function setSameHeights($container) {
$container = $container || $ ('.sameheight-container');
var viewport = ResponsiveBootstrapToolkit.current ();
$container.each (function () {
var $items = $ (this).find (".sameheight-item");
// Get max height of items in container
var maxHeight = 0;
$items.each (function () {
$ (this).css ({height: 'auto'});
maxHeight = Math.max (maxHeight, $ (this).innerHeight ());
});
// Set heights of items
$items.each (function () {
// Ignored viewports for item
var excludedStr = $ (this).data ('exclude') || '';
var excluded = excludedStr.split (',');
// Set height of element if it's not excluded on
if (excluded.indexOf (viewport) === -1) {
$ (this).innerHeight (maxHeight);
}
});
});
}
$ (function () {
animate ({
name: 'flipInY',
selector: '.error-card > .error-title-block'
});
setTimeout (function () {
var $el = $ ('.error-card > .error-container');
animate ({
name: 'fadeInUp',
selector: $el
});
$el.addClass ('visible');
}, 500);
});
$ (function () {
$ ('#sidebar-menu, #customize-menu').metisMenu ({
activeClass: 'open'
});
$ ('#sidebar-collapse-btn').on ('click', function (event) {
event.preventDefault ();
$ ("#app").toggleClass ("sidebar-open");
});
$ ("#sidebar-overlay").on ('click', function () {
$ ("#app").removeClass ("sidebar-open");
});
});
$ (function () {
$ ('.actions-list > li').on ('click', '.check', function (e) {
e.preventDefault ();
$ (this).parents ('.tasks-item')
.find ('.checkbox')
.prop ("checked", true);
// removeActionList ();
});
});
$ (function () {
$ ('.nav-profile > li > a').on ('click', function () {
var $el = $ (this).next ();
animate ({
name: 'flipInX',
selector: $el
});
});
});
$ (function () {
// Local storage settings
var themeSettings = getThemeSettings ();
// Elements
var $app = $ ('#app');
var $styleLink = $ ('#theme-style');
var $customizeMenu = $ ('#customize-menu');
// Color switcher
var $customizeMenuColorBtns = $customizeMenu.find ('.color-item');
// Position switchers
var $customizeMenuRadioBtns = $customizeMenu.find ('.radio');
/************************************************
* Initial State
*************************************************/
setThemeSettings ();
setSameHeights();
/************************************************
* Events
*************************************************/
// set theme type
$customizeMenuColorBtns.on ('click', function () {
themeSettings.themeName = $ (this).data ('theme');
setThemeSettings ();
});
$customizeMenuRadioBtns.on ('click', function () {
var optionName = $ (this).prop ('name');
themeSettings[optionName] = $ (this).val ();
setThemeSettings ();
});
function setThemeSettings() {
setThemeState ()
.delay (config.delayTime)
.queue (function (next) {
setThemeColor ();
setThemeControlsState ();
saveThemeSettings ();
$ (document).trigger ("themechange");
next ();
});
}
/************************************************
* Update theme based on options
*************************************************/
function setThemeState() {
// set theme type
if (themeSettings.themeName) {
$styleLink.attr ('href', window.cssPath + '/app-' + themeSettings.themeName + '.css');
}
else {
$styleLink.attr ('href', window.cssPath + '/app.css');
}
// App classes
$app.removeClass ('header-fixed footer-fixed sidebar-fixed');
// set header
$app.addClass (themeSettings.headerPosition);
// set footer
$app.addClass (themeSettings.footerPosition);
// set footer
$app.addClass (themeSettings.sidebarPosition);
return $app;
}
/************************************************
* Update theme controls based on options
*************************************************/
function setThemeControlsState() {
// set color switcher
$customizeMenuColorBtns.each (function () {
if ($ (this).data ('theme') === themeSettings.themeName) {
$ (this).addClass ('active');
}
else {
$ (this).removeClass ('active');
}
});
// set radio buttons
$customizeMenuRadioBtns.each (function () {
var name = $ (this).prop ('name');
var value = $ (this).val ();
if (themeSettings[name] === value) {
$ (this).prop ("checked", true);
}
else {
$ (this).prop ("checked", false);
}
});
}
/************************************************
* Update theme color
*************************************************/
function setThemeColor() {
config.chart.colorPrimary = tinycolor ($ref.find (".chart .color-primary").css ("color"));
config.chart.colorSecondary = tinycolor ($ref.find (".chart .color-secondary").css ("color"));
}
/************************************************
* Storage Functions
*************************************************/
function getThemeSettings() {
var settings = (localStorage.getItem ('themeSettings')) ? JSON.parse (localStorage.getItem ('themeSettings')) : {};
settings.headerPosition = settings.headerPosition || '';
settings.sidebarPosition = settings.sidebarPosition || '';
settings.footerPosition = settings.footerPosition || '';
return settings;
}
function saveThemeSettings() {
localStorage.setItem ('themeSettings', JSON.stringify (themeSettings));
}
});
/**
* Makes slug from input string
*
* @param text
* @param trimSpaces
*
* @returns {string}
*/
function slugify(text, trimSpaces) {
text = text.toString ().toLowerCase ();
if (trimSpaces)
text = text.trim ();
return text.replace (/ /g, '-')
.replace (/[àáâãäå]/g, "a")
.replace (/[čç]/g, "c")
.replace (/[ěèéêë]/g, "e")
.replace (/[ùúûüů]/g, "u")
.replace (/[ìíîï]/g, "i")
.replace (/[ňńñ]/g, "n")
.replace (/[òóôõö]/g, "o")
.replace (/[ýÿ]/g, "y")
.replace (/œ/g, "oe")
.replace (/ď/g, "d")
.replace (/ř/g, "r")
.replace (/š/g, "s")
.replace (/ž/g, "z")
.replace (/ť/g, "t")
.replace (/æ/g, "ae")
.replace (/[^a-z0-9\-]+/g, '')
.replace (/--+/g, '-');
}
// bind some custom methods
$ (document).ready (function () {
$ ("body").addClass ("loaded");
var notification = $ ('.notification');
if (notification.length) {
notification.click (function () {
$ (this).fadeOut ('fast');
});
setTimeout (function () {
notification.fadeOut (1500)
}, 5 * 1000)
}
var previousTitle, previousMessage;
$ ('.confirm').click (function (e) {
var titleElement = $ ('#confirmation-title');
var messageElement = $ ('#confirmation-message');
previousTitle = titleElement.text ();
previousMessage = messageElement.text ();
var confirmTitle = $ (this).data ('title');
var confirmMessage = $ (this).data ('message');
var href = $ (this).attr ('href');
$ ('#confirm-button').attr ('href', href);
if (confirmTitle)
titleElement.text (confirmTitle);
if (confirmMessage)
messageElement.text (confirmMessage);
$ ('#confirm-modal').modal ('show');
$('.main-wrapper').addClass('blur');
e.preventDefault ();
});
$ ('#confirm-modal').on ('hidden.bs.modal', function () {
$ ('#confirmation-title').text (previousTitle);
$ ('#confirmation-message').text (previousMessage);
$('.main-wrapper').removeClass('blur');
});
$ ('#lockUrl').change (function () {
$ ('.slug-source').keyup ();
});
$ ('.slug-target').keyup (function () {
$ (this).val (slugify ($ (this).val (), false));
$ ('#lockUrl').prop ('checked', true);
});
$ ('.slug-source').keyup (function () {
var source = $ (this);
var target = $ ('.slug-target');
var locked = $ ('#lockUrl');
if (!locked.is (':checked'))
target.val (slugify (source.val (), true));
});
$ (function () {
$ ('[data-toggle="tooltip"]').tooltip ()
});
$ ('[data-toggle="tooltip"]').tooltip ()
// find if any error occured and mark tab with that error
$ ('.has-error').each (function () {
@@ -433,24 +13,35 @@ $ (document).ready (function () {
$ ("#" + tabCard.prop ('id') + "-tab").addClass ('tab-with-error');
});
$('#removeTitlePhoto').click(function () {
$('#titlePhotoContainer').remove();
// $('existingTitlePhoto').val(null);
$ ('#removeTitlePhoto').click (function () {
$ ('#titlePhotoContainer').remove ();
});
$('form').areYouSure();
$ ('form').areYouSure ();
});
$('.checkbox').change(function() {
var e = $(this);
var checked = e.is(':checked');
var id = e.data('id');
$ ('.date').datepicker ({
format: 'dd. mm. yyyy'
});
$('.child-'+id).prop('checked', checked);
$ ('.checkbox').change (function () {
var e = $ (this);
var checked = e.is (':checked');
var id = e.data ('id');
$ ('.child-' + id).prop ('checked', checked);
// check also parent
if (e.hasClass('child-checkbox') && checked){
var parent = e.data('parent');
$('#checkbox-parent-'+parent).prop('checked', true);
if (e.hasClass ('child-checkbox') && checked) {
var parent = e.data ('parent');
$ ('#checkbox-parent-' + parent).prop ('checked', true);
}
});
});
$ ('.has-subpages').click (function (e) {
if (!$ (e.target).is ("div"))
return;
var id = $ (this).data ('id');
$ ('.parent-page-' + id).toggleClass ('hidden-xs-up');
})
+43
View File
@@ -0,0 +1,43 @@
var previousTitle, previousMessage;
$ ('.confirm').click (function (e) {
var titleElement = $ ('#confirmation-title');
var messageElement = $ ('#confirmation-message');
previousTitle = titleElement.text ();
previousMessage = messageElement.text ();
var confirmTitle = $ (this).data ('title');
var confirmMessage = $ (this).data ('message');
var tag = $ (this).prop ('tagName');
if (tag === 'A') {
var href = $ (this).attr ('href');
$ ('#confirm-button').attr ('href', href);
} else if (tag === 'BUTTON') {
var form = $ (this).closest ('form');
$ ('#confirm-button').click (function () {
form.submit ();
})
}
if (confirmTitle)
titleElement.text (confirmTitle);
if (confirmMessage)
messageElement.text (confirmMessage);
$ ('#confirm-modal').modal ('show');
$ ('.main-wrapper').addClass ('blur');
e.preventDefault ();
});
$ ('#confirm-modal').on ('hidden.bs.modal', function () {
$ ('#confirmation-title').text (previousTitle);
$ ('#confirmation-message').text (previousMessage);
$ ('.main-wrapper').removeClass ('blur');
});
+11
View File
@@ -0,0 +1,11 @@
var notification = $ ('.notification');
if (notification.length) {
notification.click (function () {
$ (this).fadeOut ('fast');
});
setTimeout (function () {
notification.fadeOut (1500)
}, 5 * 1000)
}
+51
View File
@@ -0,0 +1,51 @@
/**
* Makes slug from input string
*
* @param text
* @param trimSpaces
*
* @returns {string}
*/
function slugify(text, trimSpaces) {
text = text.toString ().toLowerCase ();
if (trimSpaces)
text = text.trim ();
return text.replace (/ /g, '-')
.replace (/[àáâãäå]/g, "a")
.replace (/[čç]/g, "c")
.replace (/[ěèéêë]/g, "e")
.replace (/[ùúûüů]/g, "u")
.replace (/[ìíîï]/g, "i")
.replace (/[ňńñ]/g, "n")
.replace (/[òóôõö]/g, "o")
.replace (/[ýÿ]/g, "y")
.replace (/œ/g, "oe")
.replace (/ď/g, "d")
.replace (/ř/g, "r")
.replace (/š/g, "s")
.replace (/ž/g, "z")
.replace (/ť/g, "t")
.replace (/æ/g, "ae")
.replace (/[^a-z0-9\-]+/g, '')
.replace (/--+/g, '-');
}
$ ('#lockUrl').change (function () {
$ ('.slug-source').keyup ();
});
$ ('.slug-target').keyup (function () {
$ (this).val (slugify ($ (this).val (), false));
$ ('#lockUrl').prop ('checked', true);
});
$ ('.slug-source').keyup (function () {
var source = $ (this);
var target = $ ('.slug-target');
var locked = $ ('#lockUrl');
if (!locked.is (':checked'))
target.val (slugify (source.val (), true));
});
+316
View File
@@ -0,0 +1,316 @@
var config = window.config = {};
// Config reference element
var $ref = $ ("#ref");
// Configure responsive bootstrap toolkit
config.ResponsiveBootstrapToolkitVisibilityDivs = {
'xs': $ ('<div class="device-xs hidden-sm-up"></div>'),
'sm': $ ('<div class="device-sm hidden-xs-down hidden-md-up"></div>'),
'md': $ ('<div class="device-md hidden-sm-down hidden-lg-up"></div>'),
'lg': $ ('<div class="device-lg hidden-md-down hidden-xl-up"></div>'),
'xl': $ ('<div class="device-xl hidden-lg-down"></div>')
};
ResponsiveBootstrapToolkit.use ('Custom', config.ResponsiveBootstrapToolkitVisibilityDivs);
//validation configuration
config.validations = {
debug: true,
errorClass: 'has-error',
validClass: 'success',
errorElement: "span",
// add error class
highlight: function (element, errorClass, validClass) {
$ (element).parents ("div.form-group")
.addClass (errorClass)
.removeClass (validClass);
},
// add error class
unhighlight: function (element, errorClass, validClass) {
$ (element).parents (".has-error")
.removeClass (errorClass)
.addClass (validClass);
},
// submit handler
submitHandler: function (form) {
form.submit ();
}
};
//delay time configuration
config.delayTime = 50;
// chart configurations
config.chart = {};
/***********************************************
* Animation Settings
***********************************************/
function animate(options) {
var animationName = "animated " + options.name;
var animationEnd = "webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend";
$ (options.selector)
.addClass (animationName)
.one (animationEnd,
function () {
$ (this).removeClass (animationName);
}
);
}
$ (function () {
var $itemActions = $ (".item-actions-dropdown");
$ (document).on ('click', function (e) {
if (!$ (e.target).closest ('.item-actions-dropdown').length) {
$itemActions.removeClass ('active');
}
});
$ ('.item-actions-toggle-btn').on ('click', function (e) {
e.preventDefault ();
var $thisActionList = $ (this).closest ('.item-actions-dropdown');
$itemActions.not ($thisActionList).removeClass ('active');
$thisActionList.toggleClass ('active');
});
});
function setSameHeights($container) {
$container = $container || $ ('.sameheight-container');
var viewport = ResponsiveBootstrapToolkit.current ();
$container.each (function () {
var $items = $ (this).find (".sameheight-item");
// Get max height of items in container
var maxHeight = 0;
$items.each (function () {
$ (this).css ({height: 'auto'});
maxHeight = Math.max (maxHeight, $ (this).innerHeight ());
});
// Set heights of items
$items.each (function () {
// Ignored viewports for item
var excludedStr = $ (this).data ('exclude') || '';
var excluded = excludedStr.split (',');
// Set height of element if it's not excluded on
if (excluded.indexOf (viewport) === -1) {
$ (this).innerHeight (maxHeight);
}
});
});
}
$ (function () {
animate ({
name: 'flipInY',
selector: '.error-card > .error-title-block'
});
setTimeout (function () {
var $el = $ ('.error-card > .error-container');
animate ({
name: 'fadeInUp',
selector: $el
});
$el.addClass ('visible');
}, 500);
});
$ (function () {
$ ('#sidebar-menu, #customize-menu').metisMenu ({
activeClass: 'open'
});
$ ('#sidebar-collapse-btn').on ('click', function (event) {
event.preventDefault ();
$ ("#app").toggleClass ("sidebar-open");
});
$ ("#sidebar-overlay").on ('click', function () {
$ ("#app").removeClass ("sidebar-open");
});
});
$ (function () {
$ ('.actions-list > li').on ('click', '.check', function (e) {
e.preventDefault ();
$ (this).parents ('.tasks-item')
.find ('.checkbox')
.prop ("checked", true);
// removeActionList ();
});
});
$ (function () {
$ ('.nav-profile > li > a').on ('click', function () {
var $el = $ (this).next ();
animate ({
name: 'flipInX',
selector: $el
});
});
});
$ (function () {
// Local storage settings
var themeSettings = getThemeSettings ();
// Elements
var $app = $ ('#app');
var $styleLink = $ ('#theme-style');
var $customizeMenu = $ ('#customize-menu');
// Color switcher
var $customizeMenuColorBtns = $customizeMenu.find ('.color-item');
// Position switchers
var $customizeMenuRadioBtns = $customizeMenu.find ('.radio');
/************************************************
* Initial State
*************************************************/
setThemeSettings ();
setSameHeights ();
/************************************************
* Events
*************************************************/
// set theme type
$customizeMenuColorBtns.on ('click', function () {
themeSettings.themeName = $ (this).data ('theme');
setThemeSettings ();
});
$customizeMenuRadioBtns.on ('click', function () {
var optionName = $ (this).prop ('name');
themeSettings[optionName] = $ (this).val ();
setThemeSettings ();
});
function setThemeSettings() {
setThemeState ()
.delay (config.delayTime)
.queue (function (next) {
setThemeColor ();
setThemeControlsState ();
saveThemeSettings ();
$ (document).trigger ("themechange");
next ();
});
}
/************************************************
* Update theme based on options
*************************************************/
function setThemeState() {
// set theme type
if (themeSettings.themeName) {
$styleLink.attr ('href', window.cssPath + '/app-' + themeSettings.themeName + '.css');
}
else {
$styleLink.attr ('href', window.cssPath + '/app.css');
}
// App classes
$app.removeClass ('header-fixed footer-fixed sidebar-fixed');
// set header
$app.addClass (themeSettings.headerPosition);
// set footer
$app.addClass (themeSettings.footerPosition);
// set footer
$app.addClass (themeSettings.sidebarPosition);
return $app;
}
/************************************************
* Update theme controls based on options
*************************************************/
function setThemeControlsState() {
// set color switcher
$customizeMenuColorBtns.each (function () {
if ($ (this).data ('theme') === themeSettings.themeName) {
$ (this).addClass ('active');
}
else {
$ (this).removeClass ('active');
}
});
// set radio buttons
$customizeMenuRadioBtns.each (function () {
var name = $ (this).prop ('name');
var value = $ (this).val ();
if (themeSettings[name] === value) {
$ (this).prop ("checked", true);
}
else {
$ (this).prop ("checked", false);
}
});
}
/************************************************
* Update theme color
*************************************************/
function setThemeColor() {
config.chart.colorPrimary = tinycolor ($ref.find (".chart .color-primary").css ("color"));
config.chart.colorSecondary = tinycolor ($ref.find (".chart .color-secondary").css ("color"));
}
/************************************************
* Storage Functions
*************************************************/
function getThemeSettings() {
var settings = (localStorage.getItem ('themeSettings')) ? JSON.parse (localStorage.getItem ('themeSettings')) : {};
settings.headerPosition = settings.headerPosition || '';
settings.sidebarPosition = settings.sidebarPosition || '';
settings.footerPosition = settings.footerPosition || '';
return settings;
}
function saveThemeSettings() {
localStorage.setItem ('themeSettings', JSON.stringify (themeSettings));
}
});
@@ -24,13 +24,14 @@
display: flex;
flex-flow: column nowrap;
}
&.striped {
& > div {
.striped {
& > div, & tr {
border-bottom: 1px solid $item-list-color-border;
}
& > div:nth-child(2n + 1) {
& > div:nth-child(2n + 1), & tr:nth-child(2n + 1) {
background-color: lighten($color-divider, 12%);
@include media-down(sm) {
@@ -42,13 +43,20 @@
border-bottom: none;
}
}
}
/* *******************************************
* Item general styles
********************************************** */
.item-list {
.thumbnail {
width: 100%;
height: 80px;
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
}
.item {
display: flex;
flex-direction: column;
+4
View File
@@ -16,6 +16,10 @@ body {
overflow-x: hidden;
}
.p-l-25 {
padding-left: 25px;
}
.main-wrapper {
width: 100%;
position: absolute;
+1
View File
@@ -7,5 +7,6 @@ return [
"logoutSuccessfull" => "Odhlášení proběhlo úspěšně",
"no" => "Ne",
"yes" => "Ano",
'empty' => 'Žádná data nebyla nalezena.',
"noSearchEngine" => 'Není dostupný žádný vyhledávač.'
];
+2
View File
@@ -56,4 +56,6 @@ return [
"title" => "Titulek",
"uploadTitleImage" => "Nahrát titulní obrázek",
"viewPage" => "Zobrazit",
'setOrder' => 'Nastavení pořadí stránek',
'orderSuccessfullySet' => 'Pořadí stránek úspěšně nastaveno',
];
+2 -1
View File
@@ -27,5 +27,6 @@ return [
"widgetAreas" => "Plochy pro widgety",
"widgets" => "Widgety",
"widgetsOverview" => "Všechny widgety",
'permissions' => 'Přístupová práva'
'permissions' => 'Přístupová práva',
'contentOrder' => 'Pořadí stránek'
];
+14 -4
View File
@@ -21,11 +21,21 @@ return [
],
"socialSites" => "Sociální sítě",
"successfullySaved" => "Nastavení úspěšně změněno",
'widgets' => [
"title" => 'Widgety',
'useWidgetPreloading' => 'Používat přednačítání widgetů?',
'advanced' => [
"title" => 'Pokročilé',
],
'previews' => [
'title' => 'Nastavení obrázkových náhledů',
'quality' => 'Kvalita',
'size' => 'Velikost (v pixelech)'
],
'widgets' => [
'title' => 'Widgety',
'useWidgetPreloading' => 'Používat přednačítání widgetů?',
'preloadFrequentedWidgetAreasTreshold' => 'Práh pro přednačtení widgetů',
'widgetCacheLifetime' => 'Platnost cache pro widgety'
'widgetCacheLifetime' => 'Platnost cache pro widgety'
]
];
+2 -1
View File
@@ -27,7 +27,8 @@ return [
"positionFixed" => "fixní",
"positionStatic" => "statické",
"sidebar" => "Sidebar",
'no' => 'Ne',
'yes' => 'Ano',
'minutes' => 'minut',
'views' => 'zobrazení'
];
@@ -0,0 +1,16 @@
<tr class="{{$extraClass or ''}}">
<td>
<label class="label-control" for="order-{{$page->id}}">
{{$page->title}}
</label>
</td>
<td>
<input class="form-control" id="order-{{$page->id}}" type="text"
name="page[{{$page->id}}]"
value="{{old('page['.$page->id.']', $page->order)}}" />
@include('admin.snippets.hasError', ['field' => 'page['.$page->id.']'])
</td>
</tr>

Some files were not shown because too many files have changed in this diff Show More