diff --git a/_build/data/transport.menu.php b/_build/data/transport.menu.php index 9a6859a97..ae476147b 100644 --- a/_build/data/transport.menu.php +++ b/_build/data/transport.menu.php @@ -36,6 +36,12 @@ 'menuindex' => 3, 'action' => 'mgr/help', ], + 'ms2_utilites' => [ + 'description' => 'ms2_utilites_desc', + 'parent' => 'minishop2', + 'menuindex' => 4, + 'action' => 'mgr/utilites', + ], ]; foreach ($tmp as $k => $v) { diff --git a/assets/components/minishop2/css/mgr/utilites/gallery.css b/assets/components/minishop2/css/mgr/utilites/gallery.css new file mode 100644 index 000000000..e7b9736ee --- /dev/null +++ b/assets/components/minishop2/css/mgr/utilites/gallery.css @@ -0,0 +1,36 @@ +#ms-utility-gallery-range_outer{ + position: relative; + padding: 20px 0 0; + visibility: hidden; +} + +.ms-utility-gallery-labels{ + position: absolute; + top: 0; + right: 0; + left: 0; + + font-weight: bold; +} + +#ms-utility-gallery-iteration{ + position: absolute; + top: 0; + right: 0; +} + +#ms-utility-gallery-progress{ + position: relative; + height: 5px; + background-color: #ddd; +} + +#ms-utility-gallery-progress-bar{ + position: absolute; + top: 0; + left: 0; + + height: 100%; + + background-color: #32AB9A; +} \ No newline at end of file diff --git a/assets/components/minishop2/js/mgr/utilites/gallery/panel.js b/assets/components/minishop2/js/mgr/utilites/gallery/panel.js new file mode 100644 index 000000000..1ef65dd75 --- /dev/null +++ b/assets/components/minishop2/js/mgr/utilites/gallery/panel.js @@ -0,0 +1,135 @@ +miniShop2.panel.UtilitesGallery = function (config) { + config = config || {}; + + Ext.apply(config, { + cls: 'container form-with-labels', + autoHeight: true, + url: miniShop2.config.connector_url, + saveMsg: _('ms2_utilites_gallery_updating'), + + progress:true, + baseParams: { + action: 'mgr/utilites/gallery/update' + }, + items: [{ + layout: 'form', + cls: 'main-wrapper', + labelWidth: 200, + labelAlign: 'left', + border: false, + buttonAlign: 'left', + style: 'padding: 0 0 0 7px', + items: [ + { + html: String.format( + _('ms2_utilites_gallery_information'), + miniShop2.config.utility_gallery_source_name, + miniShop2.config.utility_gallery_source_id, + miniShop2.config.utility_gallery_total_products, + miniShop2.config.utility_gallery_total_products_files + ), + }, + { + xtype: 'fieldset', + title: _('ms2_utilites_params'), + id: 'ms2-utilites-gallery-params', + cls: 'x-fieldset-checkbox-toggle', + style: 'margin: 5px 0 15px ', + collapsible: true, + collapsed: true, + stateful: true, + labelAlign: 'top', + stateEvents: ['collapse', 'expand'], + items: [ + { + html: miniShop2.config.utility_gallery_thumbnails + }, + ] + }, + { + name: 'limit', + xtype: 'numberfield', + value: 10, + width: 80, + fieldLabel: _('ms2_utilites_gallery_for_step') + }, + { + name: 'offset', + xtype: 'numberfield', + value: 0, + hidden: true, + }, + { + xtype: 'button', + style: 'margin: 15px 0 0 2px', + text: '  ' + _('ms2_utilites_gallery_refresh'), + handler: function() { + var form = this.getForm(); + form.setValues({ + offset: 0 + }); + this.submit(this); + }, scope: this + }, + { + style: 'padding: 15px 0', + html: '\ + \ + ' + } + ] + }], + listeners: { + success: {fn: function(response) { + var data = response.result.object; + var form = this.getForm(); + this.updateProgress(data); + + if (!data.done) { + form.setValues({ + offset: Number(data.offset) + }); + this.submit(this); + } + else { + MODx.msg.status({ + title: _('ms2_utilites_gallery_done'), + message: _('ms2_utilites_gallery_done_message'), + delay: 5 + }); + } + },scope: this} + } + }); + miniShop2.panel.UtilitesGallery.superclass.constructor.call(this, config); +}; + +Ext.extend(miniShop2.panel.UtilitesGallery, MODx.FormPanel,{ + + updateProgress: function (data) { + const progressblock = document.getElementById('ms-utility-gallery-range_outer'); + const progresslabel = document.getElementById('ms-utility-gallery-label'); + const progressbar = document.getElementById('ms-utility-gallery-progress-bar'); + const progressiteration = document.getElementById('ms-utility-gallery-iteration'); + progressblock.style.visibility = 'visible'; + + if(data.done) { + progresslabel.innerHTML = '100%'; + progressbar.style.width = '100%'; + progressiteration.style.visibility = 'hidden'; + } else { + let progress = (parseFloat((data.offset/data.total) * 100)).toFixed(2); + progresslabel.innerHTML = progress + '%'; + progressbar.style.width = progress + '%'; + + // count iterations + const totalIterations = Math.ceil(data.total/data.limit); + const currentIteration = data.offset/data.limit; + progressiteration.innerHTML = currentIteration + "/" + totalIterations; + } + } +}); +Ext.reg('minishop2-utilites-gallery', miniShop2.panel.UtilitesGallery); diff --git a/assets/components/minishop2/js/mgr/utilites/panel.js b/assets/components/minishop2/js/mgr/utilites/panel.js new file mode 100644 index 000000000..8c13cd0c0 --- /dev/null +++ b/assets/components/minishop2/js/mgr/utilites/panel.js @@ -0,0 +1,51 @@ +miniShop2.panel.Utilites = function (config) { + config = config || {}; + Ext.apply(config, { + cls: 'container', + items: [{ + html: '

' + _('minishop2') + ' :: ' + _('ms2_utilites') + '

', + cls: 'modx-page-header', + }, { + xtype: 'modx-tabs', + id: 'minishop2-utilites-tabs', + stateful: true, + stateId: 'minishop2-utilites-tabs', + stateEvents: ['tabchange'], + cls: 'minishop2-panel', + getState: function () { + return { + activeTab: this.items.indexOf(this.getActiveTab()) + }; + }, + items: [{ + title: _('ms2_utilites_gallery'), + layout: 'anchor', + items: [{ + html: _('ms2_utilites_gallery_intro'), + bodyCssClass: 'panel-desc', + }, { + xtype: 'minishop2-utilites-gallery', + cls: 'main-wrapper', + }] + }, + /* + // todo + { + title: _('ms2_utilites_import'), + layout: 'anchor', + items: [{ + html: _('ms2_utilites_import_intro'), + bodyCssClass: 'panel-desc', + }, { + xtype: 'minishop2-utilites-import', + cls: 'main-wrapper', + }] + }*/ + ] + }] + + }); + miniShop2.panel.Utilites.superclass.constructor.call(this, config); +}; +Ext.extend(miniShop2.panel.Utilites, MODx.Panel); +Ext.reg('minishop2-utilites', miniShop2.panel.Utilites); diff --git a/core/components/minishop2/controllers/mgr/utilites.class.php b/core/components/minishop2/controllers/mgr/utilites.class.php new file mode 100644 index 000000000..e6c6c1ef9 --- /dev/null +++ b/core/components/minishop2/controllers/mgr/utilites.class.php @@ -0,0 +1,67 @@ +modx->lexicon('ms2_utilites') . ' | miniShop2'; + } + + /** + * @return array + */ + public function getLanguageTopics() + { + return ['minishop2:default', 'minishop2:product', 'minishop2:manager']; + } + + /** + * + */ + public function loadCustomCssJs() + { + + $this->addCss($this->miniShop2->config['cssUrl'] . 'mgr/utilites/gallery.css'); + + $this->addJavascript($this->miniShop2->config['jsUrl'] . 'mgr/minishop2.js'); + $this->addJavascript($this->miniShop2->config['jsUrl'] . 'mgr/utilites/panel.js'); + $this->addJavascript($this->miniShop2->config['jsUrl'] . 'mgr/utilites/gallery/panel.js'); + + $config = $this->miniShop2->config; + + // get source properties + $productSource = $this->getOption('ms2_product_source_default', null, 1); + if ($source = $this->modx->getObject('modMediaSource', $productSource)) { + $config['utility_gallery_source_id'] = $productSource; + $config['utility_gallery_source_name'] = $source->get('name'); + + $properties = $source->get('properties'); + $propertiesString = ''; + foreach (json_decode($properties['thumbnails']['value'], true) as $key => $value) { + $propertiesString .= "$key: " . json_encode($value) . "
"; + } + $config['utility_gallery_thumbnails'] = $propertiesString; + } + + // get information about products and files + $config['utility_gallery_total_products'] = $this->modx->getCount('msProduct', ['class_key' => 'msProduct']); + $config['utility_gallery_total_products_files'] = $this->modx->getCount('msProductFile', ['parent' => 0]); + + $this->addHtml( + '' + ); + } +} diff --git a/core/components/minishop2/lexicon/ru/default.inc.php b/core/components/minishop2/lexicon/ru/default.inc.php index dc2de2ca6..72994762c 100644 --- a/core/components/minishop2/lexicon/ru/default.inc.php +++ b/core/components/minishop2/lexicon/ru/default.inc.php @@ -165,5 +165,7 @@ $_lang['ms2_system_settings'] = 'Системные настройки'; $_lang['ms2_system_settings_desc'] = 'Системные настройки miniShop2'; $_lang['ms2_type'] = 'Тип'; +$_lang['ms2_utilites'] = 'Утилиты'; +$_lang['ms2_utilites_desc'] = 'Инструменты разработчика'; $_lang['ms2_vendors'] = 'Производители товаров'; $_lang['ms2_vendors_intro'] = 'Список возможных производителей товаров. То, что вы сюда добавите, можно выбрать в поле "vendor" товара.'; diff --git a/core/components/minishop2/lexicon/ru/manager.inc.php b/core/components/minishop2/lexicon/ru/manager.inc.php index ddb7d7836..0b44e8d4b 100644 --- a/core/components/minishop2/lexicon/ru/manager.inc.php +++ b/core/components/minishop2/lexicon/ru/manager.inc.php @@ -152,6 +152,16 @@ $_lang['ms2_updatedon'] = 'Дата изменения'; $_lang['ms2_user'] = 'Пользователь'; $_lang['ms2_username'] = 'Логин'; +$_lang['ms2_utilites_gallery'] = 'Галерея'; +$_lang['ms2_utilites_gallery_done'] = 'Завершено'; +$_lang['ms2_utilites_gallery_done_message'] = 'Обновление превью изображений успешно завершено.'; +$_lang['ms2_utilites_gallery_err_noproducts'] = 'В каталоге нет товаров'; +$_lang['ms2_utilites_gallery_for_step'] = 'Обработать товаров за 1 шаг'; +$_lang['ms2_utilites_gallery_information'] = 'Выбранный источник файлов: {0}
Всего товаров: {2} шт.
Изображений: {3} шт. '; +$_lang['ms2_utilites_gallery_intro'] = 'Обновление всех изображений товаров согласно указанным параметрам.
Данная операция является трудозатратной, поэтому не указывайте большое число для одной итерации.'; +$_lang['ms2_utilites_gallery_refresh'] = 'Обновить'; +$_lang['ms2_utilites_gallery_updating'] = 'Обновлению превью'; +$_lang['ms2_utilites_params'] = 'Параметры '; $_lang['ms2_weight'] = 'Вес'; $_lang['ms2_weight_price'] = 'Стоимость ед/вес'; $_lang['ms2_weight_price_help'] = 'Добавочная стоимость доставки за единицу веса.
Может быть использовано в кастомных классах.'; diff --git a/core/components/minishop2/processors/mgr/utilites/gallery/update.class.php b/core/components/minishop2/processors/mgr/utilites/gallery/update.class.php new file mode 100644 index 000000000..d192ae470 --- /dev/null +++ b/core/components/minishop2/processors/mgr/utilites/gallery/update.class.php @@ -0,0 +1,122 @@ +modx->hasPermission($this->permission)) { + return $this->modx->lexicon('access_denied'); + } + + return parent::initialize(); + } + + + /** + * {@inheritDoc} + */ + public function getLanguageTopics() + { + return $this->languageTopics; + } + + + /** + * {@inheritDoc} + */ + public function process() + { + $this->limit = (int)$this->getProperty('limit', 10); + $this->offset = (int)$this->getProperty('offset', 0); + + $c = $this->modx->newQuery('msProduct'); + $c->sortby('id', 'ASC'); + $c->where(['class_key' => 'msProduct']); + $c->select('msProduct.id'); + + $this->total = $this->modx->getCount('msProduct', $c); + $c->limit($this->limit, $this->offset); + + $products = []; + if ($c->prepare() && $c->stmt->execute()) { + $products = $c->stmt->fetchAll(PDO::FETCH_ASSOC); + } + + if (!is_array($products) || empty($products)) { + return $this->failure($this->modx->lexicon('ms2_utilites_gallery_err_noproducts')); + } + + $i = 0; + foreach ($products as $product) { + $this->generateThumbnails($product['id']); + $i++; + } + + $offset = $this->offset + $this->limit; + $done = $offset >= $this->total; + + return $this->success('', [ + 'updated' => $i, + 'offset' => $done ? 0 : $offset, + 'done' => $done, + 'total' => $this->total, + 'limit' => $this->limit, + ]); + } + + + public function generateThumbnails($product_id) + { + if (empty($product_id)) { + return $this->failure($this->modx->lexicon('ms2_gallery_err_ns')); + } + + $files = $this->modx->getCollection('msProductFile', ['product_id' => $product_id, 'parent' => 0]); + /** @var msProductFile $file */ + foreach ($files as $file) { + $children = $file->getMany('Children'); + /** @var msProductFile $child */ + foreach ($children as $child) { + $child->remove(); + } + $file->generateThumbnails(); + } + + /** @var msProductData $product */ + $product = $this->modx->getObject('msProductData', ['id' => $product_id]); + if ($product) { + $thumb = $product->updateProductImage(); + /** @var miniShop2 $miniShop2 */ + if (empty($thumb) && $miniShop2 = $this->modx->getService('miniShop2')) { + $thumb = $miniShop2->config['defaultThumb']; + } + return $this->success('', ['thumb' => $thumb]); + } + + return $this->success(); + } +} + +return 'msUtilityGalleryUpdateProcessor';