feat: VivesPOS landing on Winter CMS 1.2 — theme + plugin + Dockerfile
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run

- Base: wintercms/winter branch 1.2 (full framework)
- Theme vivespos: Canvas 7 + Bootstrap 5 CDN, custom CSS
- Layout: deferred GTM/GA4 tracking, JSON-LD SoftwareApplication
- Partials: hero (offline-first), features, modes (offline/nube toggle),
  screenshots, pricing (3 planes), comparison, FAQ, CTA
- Plugin VivesPOS.Site with ContactForm
- Dockerfile: PHP 8.2 Apache, port 80, healthcheck
- Added winter/wn-pages, blog, sitemap, seo plugins
- Active theme set to vivespos
This commit is contained in:
2026-08-21 19:29:00 -06:00
commit 1f72193a64
3266 changed files with 531480 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
<?php namespace Backend\Behaviors\ImportExportController;
use php_user_filter;
stream_filter_register(TranscodeFilter::FILTER_NAME . "*", TranscodeFilter::class);
/**
* Transcode stream filter.
*
* Convert CSV source files from one encoding to another.
*/
class TranscodeFilter extends php_user_filter
{
const FILTER_NAME = 'winter.csv.transcode.';
protected $encodingFrom = 'auto';
protected $encodingTo;
public function filter($in, $out, &$consumed, $closing)
{
while ($resource = stream_bucket_make_writeable($in)) {
if (in_array($this->encodingFrom, mb_list_encodings())) {
$resource->data = @mb_convert_encoding(
$resource->data,
$this->encodingTo,
$this->encodingFrom
);
} else {
$resource->data = @iconv(
$this->encodingFrom,
$this->encodingTo,
$resource->data
);
}
$consumed += $resource->datalen;
stream_bucket_append($out, $resource);
}
return PSFS_PASS_ON;
}
public function onCreate()
{
if (strpos($this->filtername, self::FILTER_NAME) !== 0) {
return false;
}
$params = substr($this->filtername, strlen(self::FILTER_NAME));
if (!preg_match('/^([-\w]+)(:([-\w]+))?$/', $params, $matches)) {
return false;
}
if (isset($matches[1])) {
$this->encodingFrom = $matches[1];
}
$this->encodingTo = mb_internal_encoding();
if (isset($matches[3])) {
$this->encodingTo = $matches[3];
}
$this->params['locale'] = setlocale(LC_CTYPE, '0');
if (stripos($this->params['locale'], 'UTF-8') === false) {
setlocale(LC_CTYPE, 'en_US.UTF-8');
}
return true;
}
public function onClose()
{
setlocale(LC_CTYPE, $this->params['locale']);
}
}

View File

@@ -0,0 +1,7 @@
.export-behavior .export-columns {
max-height: 400px;
background: #f0f0f0;
padding: 20px;
padding-bottom: 0;
overflow: auto;
}

View File

@@ -0,0 +1,164 @@
.import-behavior ul {
margin: 0;
padding: 0;
list-style: none;
}
.import-behavior ul li {
font-size: 13px;
}
.import-behavior ul li.placeholder {
display: block;
position: relative;
}
.import-behavior ul li.dragged {
position: absolute;
z-index: 2000;
-webkit-box-shadow: 0 3px 6px rgba(0, 0, 0, 0.075);
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.075);
}
.import-behavior .import-file-columns,
.import-behavior .import-db-columns {
height: 400px;
background: #f0f0f0;
padding: 5px;
overflow: auto;
}
.import-behavior .import-file-columns .upload-prompt {
display: block;
text-align: center;
position: absolute;
top: 50%;
left: 0;
right: 0;
margin-top: -10px;
}
.import-behavior .import-column-bindings > ul > li,
.import-behavior .import-db-columns > ul > li {
cursor: pointer;
}
.import-behavior ul li.dragged,
.import-behavior .import-file-columns > ul > li,
.import-behavior .import-db-columns > ul > li {
background: #ffffff;
border: 1px solid #cccccc;
border-radius: 3px;
margin-bottom: 5px;
}
.import-behavior ul li.dragged div.import-column-name > span,
.import-behavior .import-file-columns > ul > li div.import-column-name > span,
.import-behavior .import-db-columns > ul > li div.import-column-name > span,
.import-behavior ul li.dragged > span,
.import-behavior .import-file-columns > ul > li > span,
.import-behavior .import-db-columns > ul > li > span {
display: block;
padding: 8px;
padding-left: 12px;
}
.import-behavior .import-db-columns > ul > li .column-icon {
color: #ccc;
position: relative;
left: -3px;
}
.import-behavior .import-db-columns > ul > li:hover .column-icon {
color: #4da7e8;
}
.import-behavior .import-db-columns > ul > li.is-required .column-icon {
color: #ab2a1c;
}
.import-behavior .import-file-columns > ul > li:before,
.import-behavior .import-file-columns > ul > li:after {
content: " ";
display: table;
}
.import-behavior .import-file-columns > ul > li:after {
clear: both;
}
.import-behavior .import-file-columns > ul > li.is-ignored {
display: none;
}
.import-behavior .import-file-columns > ul > li .column-success-icon {
display: none;
position: relative;
left: -2px;
width: 15px;
}
.import-behavior .import-file-columns > ul > li.is-matched .column-success-icon {
display: inline-block;
}
.import-behavior .import-file-columns > ul > li.is-matched .column-ignore-button {
display: none !important;
}
.import-behavior .import-file-columns > ul div.import-column-name {
float: left;
width: 45%;
}
.import-behavior .import-file-columns > ul div.import-column-name > span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.import-behavior .import-file-columns > ul div.import-column-name a.column-label {
color: #333;
}
.import-behavior .import-file-columns > ul div.import-column-name a.column-ignore-button {
color: #fff;
background: #ccc;
font-size: 10px;
border-radius: 15px;
display: inline-block;
text-decoration: none;
width: 15px;
height: 15px;
text-align: center;
position: relative;
top: -1px;
left: -3px;
}
.import-behavior .import-file-columns > ul div.import-column-name a.column-ignore-button:hover {
background: #ab2a1c;
}
.import-behavior .import-file-columns > ul .import-column-bindings > ul {
float: right;
width: 55%;
}
.import-behavior .import-column-bindings > ul {
background: #dadedf;
position: relative;
min-height: 34px;
}
.import-behavior .import-column-bindings > ul:after {
content: '';
display: block;
width: 0;
height: 0;
border-top: 17px solid transparent;
border-bottom: 17px solid transparent;
border-left: 18px solid #ffffff;
position: absolute;
top: 0;
left: 0;
}
.import-behavior .import-column-bindings > ul:before {
position: absolute;
padding: 8px;
padding-left: 28px;
content: attr(data-empty-text);
color: rgba(0, 0, 0, 0.5);
}
.import-behavior .import-column-bindings > ul > li .column-icon {
color: #595959;
float: right;
margin: 3px;
}
.import-behavior .import-column-bindings > ul > li:hover .column-icon {
color: #333333;
}
.import-behavior .import-column-bindings > ul > li:not(.dragged) {
background: #e8eaeb;
position: relative;
}
.import-behavior .import-column-bindings > ul > li:not(.dragged) > span {
display: block;
padding: 8px;
padding-left: 28px;
}

View File

@@ -0,0 +1,22 @@
/*
* Scripts for the Export controller behavior.
*/
+function ($) { "use strict";
var ExportBehavior = function() {
this.processExport = function () {
var $form = $('#exportColumns').closest('form')
$form.request('onExport', {
success: function(data) {
$('#exportContainer').html(data.result)
$(document).trigger('render')
}
})
}
}
$.wn.exportBehavior = new ExportBehavior;
}(window.jQuery);

View File

@@ -0,0 +1,149 @@
/*
* Scripts for the Import controller behavior.
*/
+function ($) { "use strict";
var ImportBehavior = function() {
this.processImport = function () {
var $form = $('#importFileColumns').closest('form')
$form.request('onImport', {
success: function(data) {
$('#importContainer').html(data.result)
$(document).trigger('render')
}
})
}
this.loadFileColumnSample = function(el) {
var $el = $(el),
$column = $el.closest('[data-column-id]'),
columnId = $column.data('column-id')
$el.popup({
handler: 'onImportLoadColumnSampleForm',
extraData: {
file_column_id: columnId
}
})
}
this.bindColumnSorting = function() {
/*
* Unbind existing
*/
$('#importDbColumns > ul, .import-column-bindings > ul').each(function(){
var $this = $(this)
if ($this.data('oc.sortable')) {
$this.sortable('destroyGroup')
$this.sortable('destroy')
}
})
var sortableOptions = {
group: 'import-fields',
usePlaceholderClone: true,
nested: false,
onDrop: $.proxy(this.onDropColumn, this)
}
$('#importDbColumns > ul, .import-column-bindings > ul').sortable(sortableOptions)
}
this.onDropColumn = function ($dbItem, container, _super, event) {
var
$fileColumns = $('#importFileColumns'),
$fileItem,
isMatch = $.contains($fileColumns.get(0), $dbItem.get(0)),
matchColumnId
/*
* Has a previous match?
*/
matchColumnId = $dbItem.data('column-matched-id')
if (matchColumnId !== null) {
$fileItem = $('[data-column-id='+matchColumnId+']', $fileColumns)
this.toggleMatchState($fileItem)
}
/*
* Is a new match?
*/
if (isMatch) {
$fileItem = $dbItem.closest('[data-column-id]'),
this.matchColumn($dbItem, $fileItem)
}
else {
this.unmatchColumn($dbItem)
}
if (_super) {
_super($dbItem, container)
}
}
this.toggleMatchState = function ($container) {
var hasItems = !!$('.import-column-bindings li', $container).length
$container.toggleClass('is-matched', hasItems)
}
this.ignoreFileColumn = function(el) {
var $el = $(el),
$column = $el.closest('[data-column-id]')
$column.addClass('is-ignored')
$('#showIgnoredColumnsButton').removeClass('disabled')
}
this.showIgnoredColumns = function() {
$('#importFileColumns li.is-ignored').removeClass('is-ignored')
$('#showIgnoredColumnsButton').addClass('disabled')
}
this.autoMatchColumns = function() {
var self = this,
fileColumns = {},
$this,
name
$('#importFileColumns li').each(function() {
$this = $(this)
name = $.trim($('.column-label', $this).text())
fileColumns[name] = $this
})
$('#importDbColumns li').each(function() {
$this = $(this)
name = $.trim($('> span', $this).text())
if (fileColumns[name]) {
$this.appendTo($('.import-column-bindings > ul', fileColumns[name]))
self.matchColumn($this, fileColumns[name])
}
})
}
this.matchColumn = function($dbItem, $fileItem) {
var matchColumnId = $fileItem.data('column-id'),
dbColumnName = $dbItem.data('column-name'),
$dbItemMatchInput = $('[data-column-match-input]', $dbItem)
this.toggleMatchState($fileItem)
$dbItem.data('column-matched-id', matchColumnId)
$dbItemMatchInput.attr('name', 'column_match['+matchColumnId+'][]')
$dbItemMatchInput.attr('value', dbColumnName)
}
this.unmatchColumn = function($dbItem) {
var $dbItemMatchInput = $('[data-column-match-input]', $dbItem)
$dbItem.removeData('column-matched-id')
$dbItemMatchInput.attr('name', '');
$dbItemMatchInput.attr('value', '');
}
}
$.wn.importBehavior = new ImportBehavior;
}(window.jQuery);

View File

@@ -0,0 +1,13 @@
@import "../../../../assets/less/core/boot.less";
.export-behavior {
.export-columns {
max-height: 400px;
background: #f0f0f0;
padding: @padding-standard;
padding-bottom: 0;
overflow: auto;
}
}

View File

@@ -0,0 +1,201 @@
@import "../../../../assets/less/core/boot.less";
@color-import-column-bg: #fff;
@color-import-column-border: #ccc;
@color-import-bound-bg: #e8eaeb;
@import-column-padding: 8px;
@import-column-font-size: 13px;
.import-behavior {
ul {
margin: 0;
padding: 0;
list-style: none;
li {
font-size: @import-column-font-size;
}
li.placeholder {
display: block;
position: relative;
}
li.dragged {
position: absolute;
z-index: 2000;
.box-shadow(0 3px 6px rgba(0,0,0,.075));
}
}
.import-file-columns,
.import-db-columns {
height: 400px;
background: #f0f0f0;
padding: 5px;
overflow: auto;
}
.import-file-columns {
.upload-prompt {
display: block;
text-align: center;
position: absolute;
top: 50%;
left: 0;
right: 0;
margin-top: -10px;
}
}
.import-column-bindings > ul > li,
.import-db-columns > ul > li {
cursor: pointer;
}
ul li.dragged,
.import-file-columns > ul > li,
.import-db-columns > ul > li {
background: @color-import-column-bg;
border: 1px solid @color-import-column-border;
border-radius: 3px;
margin-bottom: 5px;
div.import-column-name > span,
> span {
display: block;
padding: @import-column-padding;
padding-left: (@import-column-padding * 1.5);
}
}
.import-db-columns > ul {
> li {
.column-icon {
color: #ccc;
position: relative;
left: -3px;
}
&:hover .column-icon {
color: #4da7e8;
}
&.is-required {
.column-icon {
color: @brand-danger;
}
}
}
}
.import-file-columns > ul {
> li {
.clearfix;
&.is-ignored {
display: none;
}
.column-success-icon {
display: none;
position: relative;
left: -2px;
width: 15px;
}
&.is-matched {
.column-success-icon {
display: inline-block;
}
.column-ignore-button {
display: none !important;
}
}
}
div.import-column-name {
float: left;
width: 45%;
> span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
a.column-label {
color: #333;
}
a.column-ignore-button {
color: #fff;
background: #ccc;
font-size: 10px;
border-radius: 15px;
display: inline-block;
text-decoration: none;
width: 15px;
height: 15px;
text-align: center;
position: relative;
top: -1px;
left: -3px;
&:hover {
background: @brand-danger;
}
}
}
.import-column-bindings > ul {
float: right;
width: 55%;
}
}
.import-column-bindings > ul {
background: darken(@color-import-bound-bg, 5%);
position: relative;
min-height: (@import-column-padding * 2) + 18px;
&:after {
.triangle(right, 18px, (@import-column-padding * 2) + 18px, @color-import-column-bg);
position: absolute;
top: 0;
left: 0;
}
&:before {
position: absolute;
padding: @import-column-padding;
padding-left: 28px;
content: attr(data-empty-text);
color: rgba(0,0,0,.5);
}
> li {
.column-icon {
color: #595959;
float: right;
margin: 3px;
}
&:hover {
.column-icon {
color: #333333;
}
}
}
> li:not(.dragged) {
background: @color-import-bound-bg;
position: relative;
> span {
display: block;
padding: @import-column-padding;
padding-left: 28px;
}
}
}
}

View File

@@ -0,0 +1,29 @@
<div class="modal-header">
<button type="button" class="close" data-dismiss="popup">&times;</button>
<h4 class="modal-title"><?= e(trans('backend::lang.import_export.column_preview')) ?></h4>
</div>
<div class="modal-body">
<p>
<?= e(trans('backend::lang.import_export.column')) ?>:
<strong><?= $columnName ?></strong>
</p>
<div class="list-preview">
<div class="control-simplelist is-divided is-scrollable size-small" data-control="simplelist">
<ul>
<?php foreach ($columnData as $sample): ?>
<li class="wn-icon-file-o">
<?= e($sample) ?>
</li>
<?php endforeach ?>
</ul>
</div>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-default"
data-dismiss="popup">
<?= e(trans('backend::lang.form.close')) ?>
</button>
</div>

View File

@@ -0,0 +1,9 @@
<div class="export-behavior">
<?= $exportFormatFormWidget->render() ?>
<?php if ($exportOptionsFormWidget): ?>
<?= $exportOptionsFormWidget->render() ?>
<?php endif ?>
</div>

View File

@@ -0,0 +1,9 @@
<div class="import-behavior">
<?= $importUploadFormWidget->render() ?>
<?php if ($importOptionsFormWidget): ?>
<?= $importOptionsFormWidget->render() ?>
<?php endif ?>
</div>

View File

@@ -0,0 +1,27 @@
<div class="export-columns" id="exportColumns">
<div class="control-simplelist with-checkboxes is-sortable" data-control="simplelist">
<ul>
<?php foreach ($exportColumns as $key => $column): ?>
<li>
<div class="checkbox custom-checkbox">
<input
type="hidden"
name="export_columns[]"
value="<?= $key ?>" />
<input
id="<?= $this->getId('exportCheckbox-'.$key) ?>"
name="visible_columns[<?= $key ?>]"
value="1"
checked="checked"
type="checkbox" />
<label
class="choice"
for="<?= $this->getId('exportCheckbox-'.$key) ?>">
<?= e(trans($column)) ?>
</label>
</div>
</li>
<?php endforeach ?>
</ul>
</div>
</div>

View File

@@ -0,0 +1,50 @@
<div id="exportFormPopup">
<?php if (!$this->fatalError): ?>
<?= Form::open(['id' => 'exportForm']) ?>
<div class="modal-header">
<h4 class="modal-title"><?= e(trans('backend::lang.import_export.export_progress')) ?></h4>
</div>
<div id="exportContainer">
<div class="modal-body">
<div class="loading-indicator-container">
<p>&nbsp;</p>
<div class="loading-indicator transparent">
<div><?= e(trans('backend::lang.import_export.processing')) ?></div>
<span></span>
</div>
</div>
<p>&nbsp;</p>
</div>
</div>
<?= Form::close() ?>
<script>
$('#exportFormPopup').on('popupComplete', function() {
$.wn.exportBehavior.processExport()
})
</script>
<?php else: ?>
<div class="modal-header">
<button type="button" class="close" data-dismiss="popup">&times;</button>
<h4 class="modal-title"><?= e(trans('backend::lang.import_export.export_error')) ?></h4>
</div>
<div class="modal-body">
<p class="flash-message static error"><?= e($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 ?>
</div>

View File

@@ -0,0 +1,34 @@
<?php if (!$this->fatalError): ?>
<div class="modal-body">
<p>
<?= e(trans('backend::lang.import_export.processing_successful_line1')) ?>
<?= e(trans('backend::lang.import_export.processing_successful_line2')) ?>
</p>
</div>
<div class="modal-footer">
<a
href="<?= $returnUrl ?>"
class="btn btn-success"
data-dismiss="popup">
<?= e(trans('backend::lang.form.complete')) ?>
</a>
</div>
<script> window.location = '<?= $fileUrl ?>' </script>
<?php else: ?>
<div class="modal-body">
<p class="flash-message static error"><?= e($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 ?>

View File

@@ -0,0 +1,23 @@
<div class="import-db-columns" id="importDbColumns">
<ul>
<?php foreach ($importDbColumns as $column => $label): ?>
<?php
$isRequired = $this->importIsColumnRequired($column);
$iconName = $isRequired ? 'icon-asterisk' : 'icon-link';
?>
<li
class="<?= $isRequired ? 'is-required' : '' ?>"
data-column-name="<?= e($column) ?>">
<span>
<i class="column-icon <?= $iconName ?>"></i>
<?= e(trans($label)) ?>
</span>
<input type="hidden" data-column-match-input />
</li>
<?php endforeach ?>
</ul>
</div>
<script>
$.wn.importBehavior.bindColumnSorting()
</script>

View File

@@ -0,0 +1,44 @@
<div class="import-file-columns" id="importFileColumns">
<?php if ($importFileColumns): ?>
<ul>
<?php foreach ($importFileColumns as $index => $column): ?>
<li data-column-id="<?= $index ?>">
<div class="import-column-name">
<span>
<i class="column-success-icon text-success icon-check"></i>
<a
href="javascript:;"
class="column-ignore-button"
data-toggle="tooltip"
data-delay="300"
data-placement="right"
title="<?= e(trans('backend::lang.import_export.ignore_this_column')) ?>"
onclick="$.wn.importBehavior.ignoreFileColumn(this)"
>
<i class="icon-close"></i>
</a>
<a
href="javascript:;"
class="column-label"
onclick="$.wn.importBehavior.loadFileColumnSample(this)"
>
<?= e($column) ?>
</a>
</span>
</div>
<div class="import-column-bindings">
<ul data-empty-text="<?= e(trans('backend::lang.import_export.drop_column_here')) ?>"></ul>
</div>
</li>
<?php endforeach ?>
</ul>
<?php else: ?>
<p class="upload-prompt">
<?= e(trans('backend::lang.import_export.upload_valid_csv')) ?>
</p>
<?php endif ?>
</div>
<script>
$.wn.importBehavior.bindColumnSorting()
</script>

View File

@@ -0,0 +1,50 @@
<div id="importFormPopup">
<?php if (!$this->fatalError): ?>
<?= Form::open(['id' => 'importForm']) ?>
<div class="modal-header">
<h4 class="modal-title"><?= e(trans('backend::lang.import_export.import_progress')) ?></h4>
</div>
<div id="importContainer">
<div class="modal-body">
<div class="loading-indicator-container">
<p>&nbsp;</p>
<div class="loading-indicator transparent">
<div><?= e(trans('backend::lang.import_export.processing')) ?></div>
<span></span>
</div>
</div>
<p>&nbsp;</p>
</div>
</div>
<?= Form::close() ?>
<script>
$('#importFormPopup').on('popupComplete', function() {
$.wn.importBehavior.processImport()
})
</script>
<?php else: ?>
<div class="modal-header">
<button type="button" class="close" data-dismiss="popup">&times;</button>
<h4 class="modal-title"><?= e(trans('backend::lang.import_export.import_error')) ?></h4>
</div>
<div class="modal-body">
<p class="flash-message static error"><?= e($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 ?>
</div>

View File

@@ -0,0 +1,107 @@
<?php if (!$this->fatalError): ?>
<div class="modal-body">
<div class="scoreboard">
<div data-control="toolbar">
<div class="scoreboard-item title-value">
<h4><?= e(trans('backend::lang.import_export.created')) ?></h4>
<p><?= $importResults->created ?></p>
</div>
<div class="scoreboard-item title-value">
<h4><?= e(trans('backend::lang.import_export.updated')) ?></h4>
<p><?= $importResults->updated ?></p>
</div>
<?php if ($importResults->skippedCount): ?>
<div class="scoreboard-item title-value">
<h4><?= e(trans('backend::lang.import_export.skipped')) ?></h4>
<p><?= $importResults->skippedCount ?></p>
</div>
<?php endif ?>
<?php if ($importResults->warningCount): ?>
<div class="scoreboard-item title-value">
<h4><?= e(trans('backend::lang.import_export.warnings')) ?></h4>
<p><?= $importResults->warningCount ?></p>
</div>
<?php endif ?>
<div class="scoreboard-item title-value">
<h4><?= e(trans('backend::lang.import_export.errors')) ?></h4>
<p><?= $importResults->errorCount ?></p>
</div>
</div>
</div>
<?php if ($importResults->hasMessages): ?>
<?php
$tabs = [
'skipped' => trans('backend::lang.import_export.skipped_rows'),
'warnings' => trans('backend::lang.import_export.warnings'),
'errors' => trans('backend::lang.import_export.errors'),
];
if (!$importResults->skippedCount) {
unset($tabs['skipped']);
}
if (!$importResults->warningCount) {
unset($tabs['warnings']);
}
if (!$importResults->errorCount) {
unset($tabs['errors']);
}
?>
<div class="control-tabs secondary-tabs" data-control="tab">
<ul class="nav nav-tabs">
<?php $count = 0; foreach ($tabs as $code => $tab): ?>
<li class="<?= $count++ == 0 ? 'active' : '' ?>">
<a href="#importTab<?= $code ?>">
<?= $tab ?>
</a>
</li>
<?php endforeach ?>
</ul>
<div class="tab-content">
<?php $count = 0; foreach ($tabs as $code => $tab): ?>
<div class="tab-pane <?= $count++ == 0 ? 'active' : '' ?>">
<div class="list-preview">
<div class="control-simplelist is-divided is-scrollable size-small" data-control="simplelist">
<ul>
<?php foreach ($importResults->{$code} as $row => $message): ?>
<li>
<strong><?= e(trans('backend::lang.import_export.row', ['row' => $row + $sourceIndexOffset])) ?></strong>
- <?= e($message) ?>
</li>
<?php endforeach ?>
</ul>
</div>
</div>
</div>
<?php endforeach ?>
</div>
</div>
<?php endif ?>
</div>
<div class="modal-footer">
<a
href="<?= $returnUrl ?>"
class="btn btn-success"
data-dismiss="popup">
<?= e(trans('backend::lang.form.complete')) ?>
</a>
</div>
<?php else: ?>
<div class="modal-body">
<p class="flash-message static error"><?= e($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 ?>

View File

@@ -0,0 +1,16 @@
<div data-control="toolbar">
<a
href="javascript:;"
id="showIgnoredColumnsButton"
class="btn btn-sm btn-secondary wn-icon-eye disabled"
onclick="$.wn.importBehavior.showIgnoredColumns()">
<?= e(trans('backend::lang.import_export.show_ignored_columns')) ?>
</a>
<a
href="javascript:;"
id="autoMatchColumnsButton"
class="btn btn-sm btn-secondary wn-icon-bullseye"
onclick="$.wn.importBehavior.autoMatchColumns()">
<?= e(trans('backend::lang.import_export.auto_match_columns')) ?>
</a>
</div>

View File

@@ -0,0 +1,58 @@
# ===================================
# Field Definitions
# ===================================
fields:
step1_section:
label: backend::lang.import_export.export_output_format
type: section
format_preset:
label: backend::lang.import_export.file_format
type: dropdown
default: standard
options:
standard: backend::lang.import_export.standard_format
custom: backend::lang.import_export.custom_format
span: left
format_delimiter:
label: backend::lang.import_export.delimiter_char
default: ','
span: left
trigger:
action: show
condition: value[custom]
field: format_preset
format_enclosure:
label: backend::lang.import_export.enclosure_char
span: auto
default: '"'
trigger:
action: show
condition: value[custom]
field: format_preset
format_escape:
label: backend::lang.import_export.escape_char
span: auto
default: '\'
trigger:
action: show
condition: value[custom]
field: format_preset
step2_section:
label: backend::lang.import_export.select_columns
type: section
export_columns:
label: backend::lang.import_export.columns
type: partial
path: ~/modules/backend/behaviors/importexportcontroller/partials/_export_columns.php
span: left
step3_section:
label: backend::lang.import_export.set_export_options
type: section

View File

@@ -0,0 +1,95 @@
# ===================================
# Field Definitions
# ===================================
fields:
step1_section:
label: backend::lang.import_export.upload_csv_file
type: section
import_file:
label: backend::lang.import_export.import_file
type: fileupload
mode: file
span: left
fileTypes: csv
useCaption: false
format_preset:
label: backend::lang.import_export.file_format
type: dropdown
default: standard
options:
standard: backend::lang.import_export.standard_format
custom: backend::lang.import_export.custom_format
span: right
format_delimiter:
label: backend::lang.import_export.delimiter_char
default: ','
span: left
trigger:
action: show
condition: value[custom]
field: format_preset
format_enclosure:
label: backend::lang.import_export.enclosure_char
span: auto
default: '"'
trigger:
action: show
condition: value[custom]
field: format_preset
format_escape:
label: backend::lang.import_export.escape_char
span: auto
default: '\'
trigger:
action: show
condition: value[custom]
field: format_preset
format_encoding:
label: backend::lang.import_export.encoding_format
span: auto
default: UTF-8
type: dropdown
trigger:
action: show
condition: value[custom]
field: format_preset
first_row_titles:
label: backend::lang.import_export.first_row_contains_titles
comment: backend::lang.import_export.first_row_contains_titles_desc
type: checkbox
default: true
span: left
step2_section:
label: backend::lang.import_export.match_columns
type: section
column_control_panel:
type: partial
path: ~/modules/backend/behaviors/importexportcontroller/partials/_import_toolbar.php
import_file_columns:
label: backend::lang.import_export.file_columns
type: partial
path: ~/modules/backend/behaviors/importexportcontroller/partials/_import_file_columns.php
dependsOn: [import_file, first_row_titles, format_delimiter, format_enclosure, format_escape, format_encoding]
span: left
import_db_columns:
label: backend::lang.import_export.database_fields
type: partial
path: ~/modules/backend/behaviors/importexportcontroller/partials/_import_db_columns.php
dependsOn: [import_file, first_row_titles, format_delimiter, format_enclosure, format_escape, format_encoding]
span: right
step3_section:
label: backend::lang.import_export.set_import_options
type: section

View File

@@ -0,0 +1,24 @@
<?php Block::put('breadcrumb') ?>
<?= $this->makeLayoutPartial('breadcrumb') ?>
<?php Block::endPut() ?>
<?= Form::open(['class' => 'layout']) ?>
<div class="layout-row">
<?= $this->exportRender() ?>
</div>
<div class="form-buttons">
<div class="loading-indicator-container">
<button
type="submit"
data-control="popup"
data-handler="onExportLoadForm"
data-keyboard="false"
class="btn btn-primary">
<?= e(trans('backend::lang.import_export.export')) ?>
</button>
</div>
</div>
<?= Form::close() ?>

View File

@@ -0,0 +1,24 @@
<?php Block::put('breadcrumb') ?>
<?= $this->makeLayoutPartial('breadcrumb') ?>
<?php Block::endPut() ?>
<?= Form::open(['class' => 'layout']) ?>
<div class="layout-row">
<?= $this->importRender() ?>
</div>
<div class="form-buttons">
<div class="loading-indicator-container">
<button
type="submit"
data-control="popup"
data-handler="onImportLoadForm"
data-keyboard="false"
class="btn btn-primary">
<?= e(trans('backend::lang.import_export.import')) ?>
</button>
</div>
</div>
<?= Form::close() ?>