Merge branch 'develop' into media-manager
This commit is contained in:
commit
03c46012dc
|
|
@ -1,6 +1,6 @@
|
|||
* **Build 22x** (2015-03-xx)
|
||||
* **Build 226** (2015-03-16)
|
||||
- Form Tabs now support specifying a default tab using the `defaultTab` option (see Backend > Forms docs).
|
||||
- Improved the Theme management features: Edit properties, download, duplicate and delete.
|
||||
- Improved the Theme management features: Edit properties, import, export, duplicate and delete.
|
||||
|
||||
* **Build 222** (2015-03-11)
|
||||
- Form fields can now use a simpler interface for using the Input preset converter (see Backend > Forms docs).
|
||||
|
|
|
|||
|
|
@ -997,7 +997,7 @@ this.hide()
|
|||
var indicator=$('<div class="loading-indicator"></div>')
|
||||
indicator.append($('<div></div>').text(this.options.text))
|
||||
indicator.append($('<span></span>'))
|
||||
if(this.options.opaque!==undefined&&this.options.opaque){indicator.addClass('is-opaque')}
|
||||
if(this.options.opaque!==undefined){indicator.addClass('is-opaque')}
|
||||
this.$el.prepend(indicator)
|
||||
this.$el.addClass('in-progress')
|
||||
this.tally++}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
var indicator = $('<div class="loading-indicator"></div>')
|
||||
indicator.append($('<div></div>').text(this.options.text))
|
||||
indicator.append($('<span></span>'))
|
||||
if (this.options.opaque !== undefined && this.options.opaque) {
|
||||
if (this.options.opaque !== undefined) {
|
||||
indicator.addClass('is-opaque')
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -317,7 +317,8 @@ class Controller extends Extendable
|
|||
// Execute the action
|
||||
$result = call_user_func_array([$this, $actionName], $parameters);
|
||||
|
||||
if ($result instanceof RedirectResponse) {
|
||||
// Expecting \Response and \RedirectResponse
|
||||
if ($result instanceof \Symfony\Component\HttpFoundation\Response) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
|
@ -402,10 +403,10 @@ class Controller extends Extendable
|
|||
*/
|
||||
if ($result instanceof RedirectResponse) {
|
||||
$responseContents['X_OCTOBER_REDIRECT'] = $result->getTargetUrl();
|
||||
}
|
||||
/*
|
||||
* No redirect is used, look for any flash messages
|
||||
*/
|
||||
}
|
||||
elseif (Flash::check()) {
|
||||
$responseContents['#layout-flash-messages'] = $this->makeLayoutPartial('flash_messages');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ class NavigationManager
|
|||
$this->items[$itemKey] = $item;
|
||||
|
||||
if ($sideMenu !== null) {
|
||||
$this->addSideMenuItems($sideMenu);
|
||||
$this->addSideMenuItems($owner, $code, $sideMenu);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,10 @@
|
|||
.theme-selector-layout .layout-row.links .theme-description {
|
||||
border-bottom: 1px solid #f2f3f4;
|
||||
}
|
||||
.theme-selector-layout .create-new-theme {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.theme-selector-layout .create-new-theme,
|
||||
.theme-selector-layout .find-more-themes {
|
||||
background: #ecf0f1;
|
||||
color: #2b3e50;
|
||||
|
|
@ -105,6 +109,7 @@
|
|||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.theme-selector-layout .create-new-theme:hover,
|
||||
.theme-selector-layout .find-more-themes:hover {
|
||||
background: #1795f1;
|
||||
color: white;
|
||||
|
|
|
|||
|
|
@ -112,6 +112,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
.create-new-theme {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.create-new-theme,
|
||||
.find-more-themes {
|
||||
background: #ecf0f1;
|
||||
color: #2b3e50;
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ class Theme
|
|||
public function writeConfig($values = [], $overwrite = false)
|
||||
{
|
||||
if (!$overwrite) {
|
||||
$values = $values + $this->getConfig();
|
||||
$values = $values + (array) $this->getConfig();
|
||||
}
|
||||
|
||||
$path = $this->getPath().'/theme.yaml';
|
||||
|
|
|
|||
|
|
@ -7,33 +7,41 @@ tabs:
|
|||
fields:
|
||||
|
||||
name:
|
||||
label: Name
|
||||
placeholder: New theme name
|
||||
label: cms::lang.theme.name_label
|
||||
placeholder: cms::lang.theme.name_create_placeholder
|
||||
span: auto
|
||||
required: true
|
||||
attributes:
|
||||
default-focus: 1
|
||||
|
||||
directory_name:
|
||||
label: Directory name
|
||||
dir_name@create:
|
||||
label: cms::lang.theme.dir_name_label
|
||||
placeholder: cms::lang.theme.dir_name_create_label
|
||||
span: auto
|
||||
preset: name
|
||||
required: true
|
||||
|
||||
dir_name@update:
|
||||
label: cms::lang.theme.dir_name_label
|
||||
disabled: true
|
||||
span: auto
|
||||
|
||||
description:
|
||||
label: Description
|
||||
placeholder: Theme description
|
||||
label: cms::lang.theme.description_label
|
||||
placeholder: cms::lang.theme.description_placeholder
|
||||
type: textarea
|
||||
size: tiny
|
||||
|
||||
author:
|
||||
label: Author
|
||||
placeholder: Person or company name
|
||||
label: cms::lang.theme.author_label
|
||||
placeholder: cms::lang.theme.author_placeholder
|
||||
span: auto
|
||||
|
||||
homepage:
|
||||
label: Homepage
|
||||
placeholder: Website URL
|
||||
label: cms::lang.theme.homepage_label
|
||||
placeholder: cms::lang.theme.homepage_placeholder
|
||||
span: auto
|
||||
|
||||
code:
|
||||
label: Code
|
||||
placeholder: A unique code for this theme used for distribution
|
||||
label: cms::lang.theme.code_label
|
||||
placeholder: cms::lang.theme.code_placeholder
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
<?php namespace Cms\Controllers;
|
||||
|
||||
use File;
|
||||
use Yaml;
|
||||
use Flash;
|
||||
use Config;
|
||||
use Backend;
|
||||
use Redirect;
|
||||
use BackendMenu;
|
||||
use ValidationException;
|
||||
use ApplicationException;
|
||||
use Cms\Models\ThemeData;
|
||||
use Backend\Classes\Controller;
|
||||
use Cms\Models\ThemeExport;
|
||||
use Cms\Models\ThemeImport;
|
||||
use Cms\Classes\Theme as CmsTheme;
|
||||
use System\Classes\SettingsManager;
|
||||
use Backend\Classes\Controller;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
|
|
@ -41,6 +46,13 @@ class Themes extends Controller
|
|||
$this->pageTitle = 'cms::lang.theme.settings_menu';
|
||||
BackendMenu::setContext('October.System', 'system', 'settings');
|
||||
SettingsManager::setContext('October.Cms', 'theme');
|
||||
|
||||
/*
|
||||
* Enable AJAX for Form widgets
|
||||
*/
|
||||
if (post('mode') == 'import') {
|
||||
$this->makeImportFormWidget($this->findThemeObject())->bindToController();
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
|
|
@ -57,41 +69,153 @@ class Themes extends Controller
|
|||
];
|
||||
}
|
||||
|
||||
public function index_onDelete()
|
||||
{
|
||||
$theme = $this->findThemeObject();
|
||||
|
||||
if ($theme->isActiveTheme()) {
|
||||
throw new ApplicationException(trans('cms::lang.theme.delete_active_theme_failed'));
|
||||
}
|
||||
|
||||
$themePath = $theme->getPath();
|
||||
if (File::isDirectory($themePath)) {
|
||||
File::deleteDirectory($themePath);
|
||||
}
|
||||
|
||||
Flash::success(trans('cms::lang.theme.delete_theme_success'));
|
||||
return Redirect::refresh();
|
||||
}
|
||||
|
||||
//
|
||||
// Theme properties
|
||||
//
|
||||
|
||||
public function index_onLoadThemeFieldsForm()
|
||||
public function index_onLoadFieldsForm()
|
||||
{
|
||||
$theme = $this->findThemeObject();
|
||||
$this->vars['widget'] = $this->makeThemeFieldsFormWidget($theme);
|
||||
$this->vars['widget'] = $this->makeFieldsFormWidget($theme);
|
||||
$this->vars['themeDir'] = $theme->getDirName();
|
||||
|
||||
return $this->makePartial('theme_fields_form');
|
||||
}
|
||||
|
||||
public function index_onSaveThemeFields()
|
||||
public function index_onSaveFields()
|
||||
{
|
||||
$theme = $this->findThemeObject();
|
||||
$widget = $this->makeThemeFieldsFormWidget($theme);
|
||||
$widget = $this->makeFieldsFormWidget($theme);
|
||||
$theme->writeConfig($widget->getSaveData());
|
||||
|
||||
return ['#themeListItem-'.$theme->getId() => $this->makePartial('theme_list_item', ['theme' => $theme])];
|
||||
}
|
||||
|
||||
protected function makeThemeFieldsFormWidget($theme)
|
||||
protected function makeFieldsFormWidget($theme)
|
||||
{
|
||||
$widgetConfig = $this->makeConfig('~/modules/cms/classes/theme/fields.yaml');
|
||||
$widgetConfig->alias = 'form'.studly_case($theme->getDirName());
|
||||
$widgetConfig->model = $theme;
|
||||
$widgetConfig->data = $theme->getConfig();
|
||||
$widgetConfig->data['directory_name'] = $theme->getDirName();
|
||||
$widgetConfig->data['dir_name'] = $theme->getDirName();
|
||||
$widgetConfig->arrayName = 'Theme';
|
||||
$widgetConfig->context = 'update';
|
||||
|
||||
$widget = $this->makeWidget('Backend\Widgets\Form', $widgetConfig);
|
||||
return $widget;
|
||||
}
|
||||
|
||||
//
|
||||
// Create theme
|
||||
//
|
||||
|
||||
public function index_onLoadCreateForm()
|
||||
{
|
||||
$this->vars['widget'] = $this->makeCreateFormWidget();
|
||||
return $this->makePartial('theme_create_form');
|
||||
}
|
||||
|
||||
public function index_onCreate()
|
||||
{
|
||||
$widget = $this->makeCreateFormWidget();
|
||||
$data = $widget->getSaveData();
|
||||
$newDirName = trim(array_get($data, 'dir_name'));
|
||||
$destinationPath = themes_path().'/'.$newDirName;
|
||||
|
||||
$data = array_except($data, 'dir_name');
|
||||
|
||||
if (!strlen(trim(array_get($data, 'name')))) {
|
||||
throw new ValidationException(['name' => trans('cms::lang.theme.create_theme_required_name')]);
|
||||
}
|
||||
|
||||
if (!preg_match('/^[a-z0-9\_\-]+$/i', $newDirName)) {
|
||||
throw new ValidationException(['dir_name' => trans('cms::lang.theme.dir_name_invalid')]);
|
||||
}
|
||||
|
||||
if (File::isDirectory($destinationPath)) {
|
||||
throw new ValidationException(['dir_name' => trans('cms::lang.theme.dir_name_taken')]);
|
||||
}
|
||||
|
||||
File::makeDirectory($destinationPath);
|
||||
File::makeDirectory($destinationPath.'/assets');
|
||||
File::makeDirectory($destinationPath.'/content');
|
||||
File::makeDirectory($destinationPath.'/layouts');
|
||||
File::makeDirectory($destinationPath.'/pages');
|
||||
File::makeDirectory($destinationPath.'/partials');
|
||||
File::put($destinationPath.'/theme.yaml', '');
|
||||
|
||||
$theme = CmsTheme::load($newDirName);
|
||||
$theme->writeConfig($data);
|
||||
|
||||
Flash::success(trans('cms::lang.theme.create_theme_success'));
|
||||
return Redirect::refresh();
|
||||
}
|
||||
|
||||
protected function makeCreateFormWidget()
|
||||
{
|
||||
$widgetConfig = $this->makeConfig('~/modules/cms/classes/theme/fields.yaml');
|
||||
$widgetConfig->alias = 'formCreateTheme';
|
||||
$widgetConfig->model = new CmsTheme;
|
||||
$widgetConfig->arrayName = 'Theme';
|
||||
$widgetConfig->context = 'create';
|
||||
|
||||
$widget = $this->makeWidget('Backend\Widgets\Form', $widgetConfig);
|
||||
return $widget;
|
||||
}
|
||||
|
||||
//
|
||||
// Duplicate
|
||||
//
|
||||
|
||||
public function index_onLoadDuplicateForm()
|
||||
{
|
||||
$theme = $this->findThemeObject();
|
||||
$this->vars['themeDir'] = $theme->getDirName();
|
||||
|
||||
return $this->makePartial('theme_duplicate_form');
|
||||
}
|
||||
|
||||
public function index_onDuplicateTheme()
|
||||
{
|
||||
$theme = $this->findThemeObject();
|
||||
$newDirName = trim(post('new_dir_name'));
|
||||
$sourcePath = $theme->getPath();
|
||||
$destinationPath = themes_path().'/'.$newDirName;
|
||||
|
||||
if (!preg_match('/^[a-z0-9\_\-]+$/i', $newDirName)) {
|
||||
throw new ValidationException(['new_dir_name' => trans('cms::lang.theme.dir_name_invalid')]);
|
||||
}
|
||||
|
||||
if (File::isDirectory($destinationPath)) {
|
||||
throw new ValidationException(['new_dir_name' => trans('cms::lang.theme.dir_name_taken')]);
|
||||
}
|
||||
|
||||
File::copyDirectory($sourcePath, $destinationPath);
|
||||
$newTheme = CmsTheme::load($newDirName);
|
||||
$newName = $newTheme->getConfigValue('name') . ' - Copy';
|
||||
$newTheme->writeConfig(['name' => $newName]);
|
||||
|
||||
Flash::success(trans('cms::lang.theme.duplicate_theme_success'));
|
||||
return Redirect::refresh();
|
||||
}
|
||||
|
||||
//
|
||||
// Theme customization
|
||||
//
|
||||
|
|
@ -149,6 +273,90 @@ class Themes extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Theme export
|
||||
//
|
||||
|
||||
public function index_onLoadExportForm()
|
||||
{
|
||||
$theme = $this->findThemeObject();
|
||||
$this->vars['widget'] = $this->makeExportFormWidget($theme);
|
||||
$this->vars['themeDir'] = $theme->getDirName();
|
||||
|
||||
return $this->makePartial('theme_export_form');
|
||||
}
|
||||
|
||||
public function index_onExport()
|
||||
{
|
||||
$theme = $this->findThemeObject();
|
||||
$widget = $this->makeExportFormWidget($theme);
|
||||
|
||||
$model = new ThemeExport;
|
||||
$file = $model->export($theme, $widget->getSaveData());
|
||||
|
||||
return Backend::redirect('cms/themes/download/'.$file.'/'.$theme->getDirName().'.zip');
|
||||
}
|
||||
|
||||
public function download($name, $outputName = null)
|
||||
{
|
||||
try {
|
||||
$this->pageTitle = 'Download theme export archive';
|
||||
return ThemeExport::download($name, $outputName);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
$this->handleError($ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected function makeExportFormWidget($theme)
|
||||
{
|
||||
$widgetConfig = $this->makeConfig('~/modules/cms/models/themeexport/fields.yaml');
|
||||
$widgetConfig->alias = 'form'.studly_case($theme->getDirName());
|
||||
$widgetConfig->model = new ThemeExport;
|
||||
$widgetConfig->model->theme = $theme;
|
||||
$widgetConfig->arrayName = 'ThemeExport';
|
||||
|
||||
$widget = $this->makeWidget('Backend\Widgets\Form', $widgetConfig);
|
||||
return $widget;
|
||||
}
|
||||
|
||||
//
|
||||
// Theme import
|
||||
//
|
||||
|
||||
public function index_onLoadImportForm()
|
||||
{
|
||||
$theme = $this->findThemeObject();
|
||||
$this->vars['widget'] = $this->makeImportFormWidget($theme);
|
||||
$this->vars['themeDir'] = $theme->getDirName();
|
||||
|
||||
return $this->makePartial('theme_import_form');
|
||||
}
|
||||
|
||||
public function index_onImport()
|
||||
{
|
||||
$theme = $this->findThemeObject();
|
||||
$widget = $this->makeImportFormWidget($theme);
|
||||
|
||||
$model = new ThemeImport;
|
||||
$model->import($theme, $widget->getSaveData(), $widget->getSessionKey());
|
||||
|
||||
Flash::success(trans('cms::lang.theme.import_theme_success'));
|
||||
return Redirect::refresh();
|
||||
}
|
||||
|
||||
protected function makeImportFormWidget($theme)
|
||||
{
|
||||
$widgetConfig = $this->makeConfig('~/modules/cms/models/themeimport/fields.yaml');
|
||||
$widgetConfig->alias = 'form'.studly_case($theme->getDirName());
|
||||
$widgetConfig->model = new ThemeImport;
|
||||
$widgetConfig->model->theme = $theme;
|
||||
$widgetConfig->arrayName = 'ThemeImport';
|
||||
|
||||
$widget = $this->makeWidget('Backend\Widgets\Form', $widgetConfig);
|
||||
return $widget;
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
<?= Form::ajax('onCreate', [
|
||||
'id' => 'themeCreateForm',
|
||||
'data-popup-load-indicator' => true
|
||||
]) ?>
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
||||
<h4 class="modal-title"><?= e(trans('cms::lang.theme.create_title')) ?></h4>
|
||||
</div>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<div class="modal-body">
|
||||
<?= $widget->render() ?>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('cms::lang.theme.create_button')) ?>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<div class="modal-body">
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.close')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
<script>
|
||||
setTimeout(
|
||||
function(){ $('#themeCreateForm input.form-control:first').focus() },
|
||||
310
|
||||
)
|
||||
</script>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<?= Form::ajax('onDuplicateTheme', [
|
||||
'id' => 'themeDuplicateForm',
|
||||
'data-popup-load-indicator' => true,
|
||||
]) ?>
|
||||
|
||||
<input type="hidden" name="theme" value="<?= $themeDir ?>" />
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
||||
<h4 class="modal-title"><?= e(trans('cms::lang.theme.duplicate_title')) ?>: <?= $themeDir ?></h4>
|
||||
</div>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group text-field span-full">
|
||||
<label for="Form-ThemeDuplicate-newDirName">
|
||||
<?= e(trans('cms::lang.theme.new_directory_name_label')) ?>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="new_dir_name"
|
||||
id="Form-ThemeDuplicate-newDirName"
|
||||
value="<?= $themeDir ?>"
|
||||
placeholder=""
|
||||
class="form-control"
|
||||
autocomplete="off"
|
||||
maxlength="255" />
|
||||
|
||||
<p class="help-block">
|
||||
<?= e(trans('cms::lang.theme.new_directory_name_comment')) ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-success">
|
||||
<?= e(trans('cms::lang.theme.duplicate_button')) ?>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<div class="modal-body">
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.close')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
<script>
|
||||
setTimeout(
|
||||
function(){ $('#themeDuplicateForm input.form-control:first').focus() },
|
||||
310
|
||||
)
|
||||
</script>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
<?= Form::ajax('onExport', [
|
||||
'id' => 'themeExportForm',
|
||||
'data-popup-load-indicator' => true,
|
||||
'data-request-success' => 'closeExportThemePopup()'
|
||||
]) ?>
|
||||
|
||||
<input type="hidden" name="theme" value="<?= $themeDir ?>" />
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
||||
<h4 class="modal-title"><?= e(trans('cms::lang.theme.export_title')) ?></h4>
|
||||
</div>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<div class="modal-body">
|
||||
<?= $widget->render() ?>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-success">
|
||||
<?= e(trans('cms::lang.theme.export_button')) ?>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<div class="modal-body">
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.close')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
<script>
|
||||
setTimeout(
|
||||
function(){ $('#themeExportForm input.form-control:first').focus() },
|
||||
310
|
||||
)
|
||||
|
||||
function closeExportThemePopup() {
|
||||
$('#themeExportForm')
|
||||
.closest('.control-popup')
|
||||
.popup('hideLoading')
|
||||
}
|
||||
</script>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<?= Form::ajax('onSaveThemeFields', [
|
||||
<?= Form::ajax('onSaveFields', [
|
||||
'id' => 'themeFieldsForm',
|
||||
'data-popup-load-indicator' => true
|
||||
]) ?>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
||||
<h4 class="modal-title">Theme: <?= $themeDir ?></h4>
|
||||
<h4 class="modal-title"><?= e(trans('cms::lang.theme.edit_properties_title')) ?>: <?= $themeDir ?></h4>
|
||||
</div>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary">
|
||||
Save properties
|
||||
<?= e(trans('cms::lang.theme.save_properties')) ?>
|
||||
</button>
|
||||
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
<?= Form::ajax('onImport', [
|
||||
'id' => 'themeImportForm',
|
||||
'data-popup-load-indicator' => true,
|
||||
]) ?>
|
||||
|
||||
<input type="hidden" name="theme" value="<?= $themeDir ?>" />
|
||||
<input type="hidden" name="mode" value="import" />
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
||||
<h4 class="modal-title"><?= e(trans('cms::lang.theme.import_title')) ?></h4>
|
||||
</div>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<div class="modal-body">
|
||||
<?= $widget->render() ?>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-success">
|
||||
<?= e(trans('cms::lang.theme.import_button')) ?>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<div class="modal-body">
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.close')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
<script>
|
||||
setTimeout(
|
||||
function(){ $('#themeImportForm input.form-control:first').focus() },
|
||||
310
|
||||
)
|
||||
</script>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
|
@ -14,6 +14,15 @@
|
|||
<!-- Spacer -->
|
||||
</div>
|
||||
<div class="layout-cell theme-description">
|
||||
<a
|
||||
class="create-new-theme"
|
||||
data-control="popup"
|
||||
data-handler="onLoadCreateForm"
|
||||
data-size="huge"
|
||||
href="javascript:;"
|
||||
target="_blank">
|
||||
<?= e(trans('cms::lang.theme.create_new_blank_theme')) ?>
|
||||
</a>
|
||||
<a
|
||||
class="find-more-themes"
|
||||
href="http://octobercms.com/themes"
|
||||
|
|
|
|||
|
|
@ -47,39 +47,57 @@
|
|||
data-toggle="dropdown"
|
||||
class="btn btn-default">
|
||||
<i class="icon-wrench"></i>
|
||||
Manage
|
||||
<?= e(trans('cms::lang.theme.manage_button')) ?>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu" data-dropdown-title="Manage theme">
|
||||
<ul class="dropdown-menu" role="menu" data-dropdown-title="<?= e(trans('cms::lang.theme.manage_title')) ?>">
|
||||
<li role="presentation">
|
||||
<a
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
data-control="popup"
|
||||
data-size="huge"
|
||||
data-handler="onLoadThemeFieldsForm"
|
||||
data-handler="onLoadFieldsForm"
|
||||
data-request-data="theme: '<?= e($theme->getDirName()) ?>'"
|
||||
href="javascript:;"
|
||||
class="oc-icon-pencil">
|
||||
Edit properties
|
||||
</a>
|
||||
</li>
|
||||
<!--
|
||||
<li role="presentation">
|
||||
<a
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
href="javascript:;"
|
||||
class="oc-icon-download">
|
||||
Download
|
||||
<?= e(trans('cms::lang.theme.edit_properties_button')) ?>
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
data-control="popup"
|
||||
data-handler="onLoadDuplicateForm"
|
||||
data-request-data="theme: '<?= e($theme->getDirName()) ?>'"
|
||||
href="javascript:;"
|
||||
class="oc-icon-copy">
|
||||
Duplicate
|
||||
<?= e(trans('cms::lang.theme.duplicate_button')) ?>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
data-control="popup"
|
||||
data-handler="onLoadImportForm"
|
||||
data-request-data="theme: '<?= e($theme->getDirName()) ?>'"
|
||||
href="javascript:;"
|
||||
class="oc-icon-upload">
|
||||
<?= e(trans('cms::lang.theme.import_button')) ?>
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
data-control="popup"
|
||||
data-handler="onLoadExportForm"
|
||||
data-request-data="theme: '<?= e($theme->getDirName()) ?>'"
|
||||
href="javascript:;"
|
||||
class="oc-icon-download">
|
||||
<?= e(trans('cms::lang.theme.export_button')) ?>
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation" class="divider"></li>
|
||||
|
|
@ -87,12 +105,14 @@
|
|||
<a
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
data-request="onDelete"
|
||||
data-request-confirm="<?= e(trans('cms::lang.theme.delete_confirm')) ?>"
|
||||
data-request-data="theme: '<?= e($theme->getDirName()) ?>'"
|
||||
href="javascript:;"
|
||||
class="oc-icon-trash">
|
||||
Delete
|
||||
<?= e(trans('cms::lang.theme.delete_button')) ?>
|
||||
</a>
|
||||
</li>
|
||||
-->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('cms/themes') ?>">Themes</a></li>
|
||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if ($this->fatalError): ?>
|
||||
|
||||
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
|
||||
<p><a href="<?= Backend::url('cms/themes') ?>" class="btn btn-default"><?= e(trans('cms::lang.theme.return')) ?></a></p>
|
||||
|
||||
<?php endif ?>
|
||||
|
|
@ -54,6 +54,6 @@
|
|||
<?php else: ?>
|
||||
|
||||
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
|
||||
<p><a href="<?= Backend::url('cms/themes') ?>" class="btn btn-default">Return to themes list</a></p>
|
||||
<p><a href="<?= Backend::url('cms/themes') ?>" class="btn btn-default"><?= e(trans('cms::lang.theme.return')) ?></a></p>
|
||||
|
||||
<?php endif ?>
|
||||
|
|
@ -25,10 +25,57 @@ return [
|
|||
],
|
||||
'settings_menu' => 'Front-end theme',
|
||||
'settings_menu_description' => 'Preview the list of installed themes and select an active theme.',
|
||||
'find_more_themes' => 'Find more themes on OctoberCMS Theme Marketplace.',
|
||||
'name_label' => 'Name',
|
||||
'name_create_placeholder' => 'New theme name',
|
||||
'author_label' => 'Author',
|
||||
'author_placeholder' => 'Person or company name',
|
||||
'description_label' => 'Description',
|
||||
'description_placeholder' => 'Theme description',
|
||||
'homepage_label' => 'Homepage',
|
||||
'homepage_placeholder' => 'Website URL',
|
||||
'code_label' => 'Code',
|
||||
'code_placeholder' => 'A unique code for this theme used for distribution',
|
||||
'dir_name_label' => 'Directory name',
|
||||
'dir_name_create_label' => 'The destination theme directory',
|
||||
'theme_label' => 'Theme',
|
||||
'activate_button' => 'Activate',
|
||||
'active_button' => 'Activate',
|
||||
'customize_button' => 'Customize'
|
||||
'customize_button' => 'Customize',
|
||||
'duplicate_button' => 'Duplicate',
|
||||
'duplicate_title' => 'Duplicate theme',
|
||||
'duplicate_theme_success' => 'Duplicated theme successfully!',
|
||||
'manage_button' => 'Manage',
|
||||
'manage_title' => 'Manage theme',
|
||||
'edit_properties_title' => 'Theme',
|
||||
'edit_properties_button' => 'Edit properties',
|
||||
'save_properties' => 'Save properties',
|
||||
'import_button' => 'Import',
|
||||
'import_title' => 'Import theme',
|
||||
'import_theme_success' => 'Imported theme successfully!',
|
||||
'import_uploaded_file' => 'Theme archive file',
|
||||
'import_overwrite_label' => 'Overwrite existing files',
|
||||
'import_overwrite_comment' => 'Untick this box to only import new files',
|
||||
'import_folders_label' => 'Folders',
|
||||
'import_folders_comment' => 'Please select the theme folders you would like to import',
|
||||
'export_button' => 'Export',
|
||||
'export_title' => 'Export theme',
|
||||
'export_folders_label' => 'Folders',
|
||||
'export_folders_comment' => 'Please select the theme folders you would like to import',
|
||||
'delete_button' => 'Delete',
|
||||
'delete_confirm' => 'Are you sure you want to delete this theme? It cannot be undone!',
|
||||
'delete_active_theme_failed' => 'Cannot delete the active theme, try making another theme active first.',
|
||||
'delete_theme_success' => 'Deleted theme successfully!',
|
||||
'create_title' => 'Create theme',
|
||||
'create_button' => 'Create',
|
||||
'create_new_blank_theme' => 'Create a new blank theme',
|
||||
'create_theme_success' => 'Created theme successfully!',
|
||||
'create_theme_required_name' => 'Please specify a name for the theme.',
|
||||
'new_directory_name_label' => 'Theme directory',
|
||||
'new_directory_name_comment' => 'Provide a new directory name for the duplicated theme.',
|
||||
'dir_name_invalid' => 'Name can contain only digits, Latin letters and the following symbols: _-',
|
||||
'dir_name_taken' => 'Desired theme directory already exists.',
|
||||
'find_more_themes' => 'Find more themes on OctoberCMS Theme Marketplace',
|
||||
'return' => 'Return to themes list',
|
||||
],
|
||||
'maintenance' => [
|
||||
'settings_menu' => 'Maintenance mode',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,141 @@
|
|||
<?php namespace Cms\Models;
|
||||
|
||||
use File;
|
||||
use Lang;
|
||||
use Model;
|
||||
use Response;
|
||||
use ApplicationException;
|
||||
use October\Rain\Filesystem\Zip;
|
||||
use Cms\Classes\Theme as CmsTheme;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Theme export model
|
||||
*
|
||||
* @package october\cms
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*/
|
||||
class ThemeExport extends Model
|
||||
{
|
||||
use \October\Rain\Database\Traits\Validation;
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'cms_theme_data';
|
||||
|
||||
/**
|
||||
* @var array The rules to be applied to the data.
|
||||
*/
|
||||
public $rules = [];
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* @var array Make the model's attributes public so behaviors can modify them.
|
||||
*/
|
||||
public $attributes = [
|
||||
'theme' => null,
|
||||
'themeName' => null,
|
||||
'dirName' => null,
|
||||
'folders' => [
|
||||
'assets' => true,
|
||||
'pages' => true,
|
||||
'layouts' => true,
|
||||
'partials' => true,
|
||||
'content' => true,
|
||||
]
|
||||
];
|
||||
|
||||
public function getFoldersOptions()
|
||||
{
|
||||
return [
|
||||
'assets' => 'Assets',
|
||||
'pages' => 'Pages',
|
||||
'layouts' => 'Layouts',
|
||||
'partials' => 'Partials',
|
||||
'content' => 'Content',
|
||||
];
|
||||
}
|
||||
|
||||
public function setThemeAttribute($theme)
|
||||
{
|
||||
if (!$theme instanceof CmsTheme) return;
|
||||
|
||||
$this->attributes['themeName'] = $theme->getConfigValue('name', $theme->getDirName());
|
||||
$this->attributes['dirName'] = $theme->getDirName();
|
||||
$this->attributes['theme'] = $theme;
|
||||
}
|
||||
|
||||
public function export($theme, $data = [])
|
||||
{
|
||||
$this->theme = $theme;
|
||||
$this->fill($data);
|
||||
|
||||
try {
|
||||
$themePath = $this->theme->getPath();
|
||||
$tempPath = temp_path() . '/'.uniqid('oc');
|
||||
$zipName = uniqid('oc');
|
||||
$zipPath = temp_path().'/'.$zipName;
|
||||
|
||||
if (!@mkdir($tempPath))
|
||||
throw new ApplicationException('Unable to create directory '.$tempPath);
|
||||
|
||||
if (!@mkdir($metaPath = $tempPath . '/meta'))
|
||||
throw new ApplicationException('Unable to create directory '.$metaPath);
|
||||
|
||||
File::copy($themePath.'/theme.yaml', $tempPath.'/theme.yaml');
|
||||
File::copyDirectory($themePath.'/meta', $metaPath);
|
||||
|
||||
foreach ($this->folders as $folder) {
|
||||
if (!array_key_exists($folder, $this->getFoldersOptions())) continue;
|
||||
File::copyDirectory($themePath.'/'.$folder, $tempPath.'/'.$folder);
|
||||
}
|
||||
|
||||
Zip::make($zipPath, $tempPath);
|
||||
File::deleteDirectory($tempPath);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
|
||||
if (strlen($tempPath) && File::isDirectory($tempPath)) {
|
||||
File::deleteDirectory($tempPath);
|
||||
}
|
||||
|
||||
if (strlen($zipPath) && File::isFile($zipPath)) {
|
||||
File::delete($zipPath);
|
||||
}
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $zipName;
|
||||
}
|
||||
|
||||
public static function download($name, $outputName = null)
|
||||
{
|
||||
if (!preg_match('/^oc[0-9a-z]*$/i', $name)) {
|
||||
throw new ApplicationException('File not found');
|
||||
}
|
||||
|
||||
$zipPath = temp_path() . '/' . $name;
|
||||
if (!file_exists($zipPath)) {
|
||||
throw new ApplicationException('File not found');
|
||||
}
|
||||
|
||||
$headers = Response::download($zipPath, $outputName)->headers->all();
|
||||
$result = Response::make(File::get($zipPath), 200, $headers);
|
||||
|
||||
@unlink($zipPath);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
<?php namespace Cms\Models;
|
||||
|
||||
use File;
|
||||
use Lang;
|
||||
use Model;
|
||||
use ApplicationException;
|
||||
use October\Rain\Filesystem\Zip;
|
||||
use Cms\Classes\Theme as CmsTheme;
|
||||
use FilesystemIterator;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Theme import model
|
||||
*
|
||||
* @package october\cms
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*/
|
||||
class ThemeImport extends Model
|
||||
{
|
||||
use \October\Rain\Database\Traits\Validation;
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'cms_theme_data';
|
||||
|
||||
/**
|
||||
* @var array The rules to be applied to the data.
|
||||
*/
|
||||
public $rules = [];
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
public $attachOne = [
|
||||
'uploaded_file' => ['System\Models\File']
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array Make the model's attributes public so behaviors can modify them.
|
||||
*/
|
||||
public $attributes = [
|
||||
'theme' => null,
|
||||
'themeName' => null,
|
||||
'dirName' => null,
|
||||
'overwrite' => true,
|
||||
'folders' => [
|
||||
'assets' => true,
|
||||
'pages' => true,
|
||||
'layouts' => true,
|
||||
'partials' => true,
|
||||
'content' => true,
|
||||
]
|
||||
];
|
||||
|
||||
public function getFoldersOptions()
|
||||
{
|
||||
return [
|
||||
'assets' => 'Assets',
|
||||
'pages' => 'Pages',
|
||||
'layouts' => 'Layouts',
|
||||
'partials' => 'Partials',
|
||||
'content' => 'Content',
|
||||
];
|
||||
}
|
||||
|
||||
public function setThemeAttribute($theme)
|
||||
{
|
||||
if (!$theme instanceof CmsTheme) return;
|
||||
|
||||
$this->attributes['themeName'] = $theme->getConfigValue('name', $theme->getDirName());
|
||||
$this->attributes['dirName'] = $theme->getDirName();
|
||||
$this->attributes['theme'] = $theme;
|
||||
}
|
||||
|
||||
public function import($theme, $data = [], $sessionKey = null)
|
||||
{
|
||||
@set_time_limit(3600);
|
||||
|
||||
$this->theme = $theme;
|
||||
$this->fill($data);
|
||||
|
||||
try
|
||||
{
|
||||
$file = $this->uploaded_file()->withDeferred($sessionKey)->first();
|
||||
if (!$file) {
|
||||
throw new ApplicationException('There is no file attached to import!');
|
||||
}
|
||||
|
||||
$themePath = $this->theme->getPath();
|
||||
$tempPath = temp_path() . '/'.uniqid('oc');
|
||||
$zipName = uniqid('oc');
|
||||
$zipPath = temp_path().'/'.$zipName;
|
||||
|
||||
File::put($zipPath, $file->getContents());
|
||||
|
||||
if (!@mkdir($tempPath))
|
||||
throw new ApplicationException('Unable to create directory '.$tempPath);
|
||||
|
||||
Zip::extract($zipPath, $tempPath);
|
||||
|
||||
// if (File::isFile($tempPath.'/theme.yaml')) {
|
||||
// File::copy($tempPath.'/theme.yaml', $themePath.'/theme.yaml');
|
||||
// }
|
||||
|
||||
if (File::isDirectory($tempPath.'/meta')) {
|
||||
$this->copyDirectory($tempPath.'/meta', $themePath.'/meta');
|
||||
}
|
||||
|
||||
foreach ($this->folders as $folder) {
|
||||
if (!array_key_exists($folder, $this->getFoldersOptions())) continue;
|
||||
$this->copyDirectory($tempPath.'/'.$folder, $themePath.'/'.$folder);
|
||||
}
|
||||
|
||||
File::deleteDirectory($tempPath);
|
||||
File::delete($zipPath);
|
||||
$file->delete();
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
|
||||
if (!empty($tempPath) && File::isDirectory($tempPath)) {
|
||||
File::deleteDirectory($tempPath);
|
||||
}
|
||||
|
||||
if (!empty($zipPath) && File::isFile($zipPath)) {
|
||||
File::delete($zipPath);
|
||||
}
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for copying directories that supports the ability
|
||||
* to not overwrite existing files. Inherited from File::copyDirectory
|
||||
*
|
||||
* @param string $directory
|
||||
* @param string $destination
|
||||
* @return bool
|
||||
*/
|
||||
protected function copyDirectory($directory, $destination)
|
||||
{
|
||||
// Preference is to overwrite existing files
|
||||
if ($this->overwrite) {
|
||||
return File::copyDirectory($directory, $destination);
|
||||
}
|
||||
|
||||
if (!File::isDirectory($directory)) return false;
|
||||
|
||||
$options = FilesystemIterator::SKIP_DOTS;
|
||||
|
||||
if (!File::isDirectory($destination)) {
|
||||
File::makeDirectory($destination, 0777, true);
|
||||
}
|
||||
|
||||
$items = new FilesystemIterator($directory, $options);
|
||||
|
||||
foreach ($items as $item) {
|
||||
$target = $destination.'/'.$item->getBasename();
|
||||
|
||||
if ($item->isDir()) {
|
||||
$path = $item->getPathname();
|
||||
|
||||
if (!$this->copyDirectory($path, $target)) return false;
|
||||
}
|
||||
else {
|
||||
// Do not overwrite existing files
|
||||
if (File::isFile($target)) continue;
|
||||
|
||||
if (!File::copy($item->getPathname(), $target)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# ===================================
|
||||
# Field Definitions
|
||||
# ===================================
|
||||
|
||||
fields:
|
||||
|
||||
themeName:
|
||||
label: cms::lang.theme.theme_label
|
||||
disabled: true
|
||||
|
||||
folders:
|
||||
label: cms::lang.theme.export_folders_label
|
||||
commentAbove: cms::lang.theme.export_folders_comment
|
||||
type: checkboxlist
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# ===================================
|
||||
# Field Definitions
|
||||
# ===================================
|
||||
|
||||
fields:
|
||||
|
||||
themeName:
|
||||
label: cms::lang.theme.theme_label
|
||||
disabled: true
|
||||
|
||||
uploaded_file:
|
||||
label: cms::lang.theme.import_uploaded_file
|
||||
type: fileupload
|
||||
mode: file
|
||||
fileTypes: zip
|
||||
|
||||
overwrite:
|
||||
label: cms::lang.theme.import_overwrite_label
|
||||
comment: cms::lang.theme.import_overwrite_comment
|
||||
type: checkbox
|
||||
|
||||
folders:
|
||||
label: cms::lang.theme.import_folders_label
|
||||
commentAbove: cms::lang.theme.import_folders_comment
|
||||
type: checkboxlist
|
||||
|
|
@ -13,6 +13,7 @@ return [
|
|||
'fa' => 'Perzsa',
|
||||
'fr' => 'Francia',
|
||||
'hu' => 'Magyar',
|
||||
'id' => 'Indonéz',
|
||||
'it' => 'Olasz',
|
||||
'ja' => 'Japán',
|
||||
'nl' => 'Holland',
|
||||
|
|
@ -160,7 +161,7 @@ return [
|
|||
],
|
||||
'updates' => [
|
||||
'title' => 'Frissítések kezelése',
|
||||
'name' => 'Szoftverfrissítés',
|
||||
'name' => 'Szoftver frissítése',
|
||||
'menu_label' => 'Frissítések',
|
||||
'menu_description' => 'A rendszer és a bővítmények frissítése, valamint új kiegészítők telepítése.',
|
||||
'check_label' => 'Frissítések keresése',
|
||||
|
|
@ -173,9 +174,10 @@ return [
|
|||
'core_build_old' => 'Jelenlegi verzió: :build',
|
||||
'core_build_new' => 'Verzió: :build',
|
||||
'core_build_new_help' => 'Elérhető a legújabb hivatalos kiadás.',
|
||||
'core_downloading' => 'Alkalmazásfájlok letöltése...',
|
||||
'core_extracting' => 'Alkalmazásfájlok kicsomagolása...',
|
||||
'core_downloading' => 'Alkalmazás fájlok letöltése...',
|
||||
'core_extracting' => 'Alkalmazás fájlok kicsomagolása...',
|
||||
'plugins' => 'Bővítmények',
|
||||
'disabled' => 'Letiltva',
|
||||
'plugin_downloading' => 'Bővítmény letöltése: :name',
|
||||
'plugin_extracting' => 'Bővítmény kicsomagolása: :name',
|
||||
'plugin_version_none' => 'Új bővítmény',
|
||||
|
|
|
|||
Loading…
Reference in New Issue