CSS3-трансформации

Модель визуального форматирования CSS описывает систему координат внутри каждого позиционированного элемента. Система координат является точкой отсчета для свойств смещения. Положение и размеры в этом координатном пространстве можно рассматривать как заданные в пикселях, относительно точки отсчета, с положительными значениями, идущими вправо и вниз. Это координатное пространство можно изменить с помощью свойства transform.

CSS3-трансформации позволяют сдвигать, поворачивать и масштабировать элементы. Трансформации преобразовывают элемент, не затрагивая остальные элементы веб-страницы, т.е. другие элементы не сдвигаются относительно него.

В HTML трансформируемый элемент это: элемент с display: block; и display: inline-block;, а также элементы, значение свойства displayкоторых вычисляется как table-row, table-row-group, table-header-group, table-footer-group, table-cell или table-caption.

Трансформированным считается элемент с любым установленным значением свойства transform, отличным от none.

В SVG трансформируемый элемент — это элемент, который имеет атрибуты transform, patternTransform или gradientTransform.

Существуют два вида CSS3-трансформаций – 2Dи 3D. 2D-трансформации преобразовывают элементы в двумерном пространстве c помощью 2D-матрицы преобразований. Эта матрица применяется для вычисления новых координат объекта, на основе значений свойств transformи transform-origin. Преобразования влияют только на визуальный рендеринг. В отношении макета страницы они могут отразиться на переполнении содержимого блока. По умолчанию точка трансформации находится в центре элемента.

2D-трансформации элементов

1. Функции 2D-трансформации: свойство transform

Свойство transform задаёт вид преобразования элемента. Свойство описывается с помощью функций трансформации, которые смещают элемент относительно его текущего положения на странице или изменяют его первоначальные размеры и форму.

Свойство не наследуется.

Функция

Описание

none

Значение по умолчанию, означает отсутствие трансформации. Также отменяет трансформацию для элемента из группы трансформируемых элементов.

matrix(a, c, b, d, x, y)

Смещает элементы и задает способ их трансформации, позволяя объединить несколько функций 2D-трансформаций в одной. В качестве трансформации допустимы поворот, масштабирование, наклон и изменение положения.

Значение aизменяет масштаб по горизонтали. Значение от 0 до 1 уменьшает элемент, больше 1 — увеличивает.

Значение cдеформирует (сдвигает) стороны элемента по оси Y, положительное значение — вверх, отрицательное — вниз.

Значение bдеформирует (сдвигает) стороны элемента по оси X, положительное значение — влево, отрицательное — вправо.

Значение dизменяет масштаб по вертикали. Значение меньше 1 уменьшает элемент, больше 1 — увеличивает.

Значение xсмещает элемент по оси X, положительное — вправо, отрицательное — влево.

Значение yсмещает элемент по оси Y, положительное значение — вниз, отрицательное — вверх.

translate(x,y)

Сдвигает элемент на новое место, перемещая относительно обычного положения вправо и вниз, используя координаты X и Y, не затрагивая при этом соседние элементы. Если нужно сдвинуть элемент влево или вверх, то нужно использовать отрицательные значения.

translateX(n)

Сдвигает элемент относительно его обычного положения по оси X.

translateY(n)

Сдвигает элемент относительно его обычного положения по оси Y.

scale(x,y)

Масштабирует элементы, делая их больше или меньше. Значения от 0 до 1 уменьшают элемент. Первое значение масштабирует элемент по ширине, второе — по высоте. Отрицательные значения отображают элемент зеркально.

scaleX(n)

Функция масштабирует элемент по ширине, делая его шире или уже. Если значение больше единицы, элемент становится шире, если значение находится между единицей и нулем, элемент становится уже. Отрицательные значения отображают элемент зеркально по горизонтали.

scaleY(n)

Функция масштабирует элемент по высоте, делая его выше или ниже. Если значение больше единицы, элемент становится выше, если значение находится между единицей и нулем — ниже. Отрицательные значения отображают элемент зеркально по вертикали.

rotate(угол)

Поворачивает элементы на заданное количество градусов, отрицательные значения от -1degдо -360degповорачивают элемент против часовой стрелки, положительные — по часовой стрелке. Значение rotate(720deg)поворачивает элемент на два полных оборота.

skew(x-угол,y-угол)

Используется для деформирования (искажения) сторон элемента относительно координатных осей. Если указано одно значение, второе будет определено браузером автоматически.

skewX(угол)

Деформирует стороны элемента относительно оси X.

skewY(угол)

Деформирует стороны элемента относительно оси Y.

initial

Устанавливает значение свойства в значение по умолчанию.

inherit

Наследует значение свойства от родительского элемента.

Допустимые значения:

matrix()— любое число
translate(), translateX(), translateY()— единицы длины (положительные и отрицательные), %
scale(), scaleX(), scaleY()— любое число
rotate()— угол (deg, grad, radили turn)
skew(), skewX(), skewY()— угол (deg, grad, rad)

Можно объединить несколько трансформаций одного элемента, перечислив их через пробел в порядке проявления.

Синтаксис

transform: none;
transform: matrix(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
transform: rotate(45deg);
transform: translate(12px, 50%);
transform: translateX(2em);
transform: translateY(3in);
transform: scale(2, 0.5);
transform: scaleX(2);
transform: scaleY(0.5);
transform: skew(30deg, 20deg);
transform: skewX(30deg);
transform: skewY(1.07rad);
transform: translateX(10px) rotate(10deg) translateY(5px);
transform: inherit;
transform: initial;

2. Точка трансформации: свойство transform-origin

Свойство transform-origin позволяет сместить центр трансформации, относительно которого происходит изменение положения/размера/формы элемента. Значение по умолчанию — center, или 50% 50%. Задаётся только для трансформированных элементов.

Свойство не наследуется.

transform-origin

Значения:

ось Х(left, center, right, длина, %)

ось Y(top, center, bottom, длина, %)

Пара значений, заданная с помощью ключевых слов, единиц длины или процентов определяет, относительно какой части элемента будет происходить трансформация. Значения больше 100% увеличивают область трансформации элемента.

initial

Устанавливает значение свойства в значение по умолчанию.

inherit

Наследует значение свойства от родительского элемента.

Синтаксис

transform-origin: 2px;
transform-origin: bottom;
transform-origin: 3cm 2px;
transform-origin: left 2px;
transform-origin: right top;
transform-origin: inherit;
transform-origin: initial;

3. Область преобразования: свойство transform-box

Все преобразования, определяемые свойством transform и transform-origin, относятся к положению и размерам опорного блока элемента. Опорный блок элемента это виртуальный прямоугольник вокруг элемента, который формирует систему координат для отрисовки.

В некоторых браузерах опорный блок принимает центр SVG-холста в качестве точки преобразования. Чтобы решить эту проблему, можно задать для элемента transform-box.

Опорный блок добавляет дополнительное смещение к исходной точке, заданной свойством transform-origin.

Свойство не наследуется.

transform-box

Значения:

content-box

В качестве опорного блока выступает область содержимого элемента. Для элемента <table>эта область включает также заголовок таблицы и рамку.

border-box

В качестве опорного блока выступает область рамки элемента. Для элемента <table>эта область включает также заголовок таблицы и рамку.

fill-box

В качестве опорного блока выступает ограничивающая рамка, содержащая только геометрическую форму элемента.

stroke-box

В качестве опорного блока выступает ограничивающая рамка, содержащая геометрическую форму и обводку элемента.

view-box

В качестве опорного блока используется область просмотра на SVG-холсте, которая определяет прямоугольную область, в которую отображается содержимое SVG.

initial

Устанавливает значение свойства в значение по умолчанию.

inherit

Наследует значение свойства от родительского элемента.

Синтаксис

transform-box: content-box;
transform-box: border-box;
transform-box: fill-box;
transform-box: stroke-box;
transform-box: view-box;
transform-box: inherit;
transform-box: initial;

Замена звездочек рейтинга на svg вместо FontAwesome

CSS

В карточке товара в списке товаров
.five-stars-container {
	display: inline-block;
	position: relative;
	text-align: center;
	cursor: default;
	width: 70px;
    height: 14px;
    margin-bottom:10px
}
.five-stars-container .five-stars {
	display: block;
	overflow: hidden;
	position: relative;
	background: #fff;
	padding-left: 1px;
}
.shop-content .five-stars-container .five-stars {
	background: #f9f9f9;
}
.five-stars-container .five-stars:before {
	content: "";
	display:block;
	width:70px;
	height:14px;
	background-image:url(/images/star-red.svg);
	background-repeat:repeat-x;
}
.five-stars-container .five-stars.transparent-bg {
	background: none;
}
.five-stars-container:before {
	display: block;
	position: absolute;
	top: 0;
	left: 0;
	content: "";
	width:70px;
	height:14px;
	background-image:url(/images/star.svg);
	background-repeat:repeat-x;
	z-index: 0;
}
В карточке товара для показа рейтинга в блоке с отзывами
Показ рейтинга
<div class="rating">
                    <span>
                      <img src="/images/star-red.svg">
                      <img src="/images/star-red.svg">
                      <img src="/images/star-red.svg">
                      <img src="/images/star-red.svg">
                      <img src="/images/star.svg">
                    </span>
                  </div>
.rating[data-rating='0'] .rating-star:nth-child(-n + 0):after,
.rating[data-rating='0.5'] .rating-star:nth-child(-n + 0):after,
.rating[data-rating='1'] .rating-star:nth-child(-n + 1):after,
.rating[data-rating='1.5'] .rating-star:nth-child(-n + 1):after,
.rating[data-rating='2'] .rating-star:nth-child(-n + 2):after,
.rating[data-rating='2.5'] .rating-star:nth-child(-n + 2):after,
.rating[data-rating='3'] .rating-star:nth-child(-n + 3):after,
.rating[data-rating='3.5'] .rating-star:nth-child(-n + 3):after,
.rating[data-rating='4'] .rating-star:nth-child(-n + 4):after,
.rating[data-rating='4.5'] .rating-star:nth-child(-n + 4):after,
.rating[data-rating='5'] .rating-star:nth-child(-n + 5):after,
.rating[data-rating='5.5'] .rating-star:nth-child(-n + 5):after {
	content: "";
	display:inline-block;
	width:14px;
	height:14px;
	background-image:url(/images/star-red.svg);
	background-repeat:repeat-x;
}
.rating[data-rating='0.5'] .rating-star:nth-child(1):after,
.rating[data-rating='1.5'] .rating-star:nth-child(2):after,
.rating[data-rating='2.5'] .rating-star:nth-child(3):after,
.rating[data-rating='3.5'] .rating-star:nth-child(4):after,
.rating[data-rating='4.5'] .rating-star:nth-child(5):after,
.rating[data-rating='5.5'] .rating-star:nth-child(6):after {
	display:inline-block;
	width:14px;
	height:14px;
	background-image:url(/images/star.svg);
	background-repeat:repeat-x;
}
.rating {
	margin: 0;
	padding: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	color: #ffd700;
}
.rating-star {
	font-size: 24px;
	display: block;
}
.rating-star::after {
    content: "";
    display:inline-block;
	width:14px;
	height:14px;
	background-image:url(/images/star.svg);
	background-repeat:repeat-x;
}
.product-tabs .comment-stats-wrapper {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
}
.product-tabs .comment-stats-wrapper > div {
	flex: 1 50%;
}
.product-tabs .comment-stats-wrapper .average-rating {
	font-size: 30px;
	padding-bottom: 20px;
	color: @fifth-color;
	text-align: center;
}
.product-tabs .comment-stats-wrapper .average-rating span {
	font-size: 40px;
	color: @color;
}
.product-tabs .comment-stats-wrapper .comment-stats-line {
	display: grid;
	align-items: center;
	grid-template-columns: 30% 50% 20%;
}
.product-tabs .comment-stats-wrapper .comment-stats-line .line {
	border-radius: 5px;
	width: 100%;
	height: 10px;
	background: #e1e1e1;
}
.product-tabs .comment-stats-wrapper .comment-stats-line .line span {
	height: 100%;
	display: block;
	border-radius: 5px;
}
.product-tabs .comment-stats-wrapper .comment-stats-line .count {
	padding-left: 20px;
	color: #a29e8d;
}
.product-tabs .comment-stats-wrapper .comment-stats-line:nth-child(1) .line span {
	background: #329d0f;
}
.product-tabs .comment-stats-wrapper .comment-stats-line:nth-child(2) .line span {
	background: #8ab311;
}
.product-tabs .comment-stats-wrapper .comment-stats-line:nth-child(3) .line span {
	background: #c0c61d;
}
.product-tabs .comment-stats-wrapper .comment-stats-line:nth-child(4) .line span {
	background: #f5bf15;
}
.product-tabs .comment-stats-wrapper .comment-stats-line:nth-child(5) .line span {
	background: #f89e49;
}
В карточке товара для выбора рейтинга в отзыве
.ui-stars-star,
.ui-stars-cancel {
	float: left;
	display: block;
	overflow: hidden;
	text-indent: -999em;
	cursor: pointer;
}
.ui-stars-star a,
.ui-stars-cancel a {
	width: 14px;
	height: 14px;
	display: block;
}
.ui-stars-star a {
	background: url(/images/star.svg) no-repeat 0 0;
}
.ui-stars-cancel a {
    position:relative;
    display:flex;
    justify-content: center;
	align-items: center;
    border:1px solid #FCC136;
    -webkit-border-radius: 50%; 
       -moz-border-radius: 50%; 
            border-radius: 50%;
}
.ui-stars-cancel a:before {
    content:'';
    width:5px;
    height:5px;
    display:block;
    background-color:#FCC136;
}
.ui-stars-star-on a {
	background: url(/images/star.svg) no-repeat 0 0;
}
.ui-stars-star-hover a {
	background: url(/images/star-red.svg) no-repeat 0 0;
}
.ui-stars-cancel-hover a {
	background-position: 0 -16px;
}
.ui-stars-star-disabled,
.ui-stars-star-disabled a,
.ui-stars-cancel-disabled a {
	cursor: default !important;
}
SVG

Информационный блок в карточке товара

Добавляем в карточку товара блок с призывом задать вопрос

1. В XSL шаблон вывода карточки товара в нужном месте размещаем данный код: 

<div class="ask-question">
            <div class="d-flex justify-content-center">
              <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="40px" height="40px">
                <path style="fill:#ccc" d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 7.1 5.8 12 12 12 2.4 0 4.9-.7 7.1-2.4L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64zm32 352c0 17.6-14.4 32-32 32H293.3l-8.5 6.4L192 460v-76H64c-17.6 0-32-14.4-32-32V64c0-17.6 14.4-32 32-32h384c17.6 0 32 14.4 32 32v288zm-224-88c-13.3 0-24 10.7-24 24s10.7 24 24 24 24-10.7 24-24-10.7-24-24-24zm-8.5-24h17c4.2 0 7.7-3.3 8-7.5l7-112c.3-4.6-3.4-8.5-8-8.5h-31c-4.6 0-8.3 3.9-8 8.5l7 112c.3 4.2 3.8 7.5 8 7.5z"></path>
              </svg>
              <span class="ps-3 fs-4 fw-bold title">Есть вопросы?</span>
            </div>
            <div class="text">
						Если у вас есть вопросы по товару, то задавайте их и мы вам с радостью ответим.
					</div>
            <div class="last">
              <button type="button" id="questionModalOpen" data-bs-toggle="modal" data-bs-target="#questionModal" class="btn btn-transparent">Задать вопрос о товаре</button>
            </div>
          </div>

2. В макет добавляем код загрузки формы (в примере код формы с отправкой уведомления Пользователю). Форма будет в модальном окне. Нажатие на кнопку "Задать вопрос" вызовет открытие формы.

<?php
        // ФОРМА ЗАЯВКИ
        $oForm = Core_Entity::factory('Form', 1);  
        $Form_Controller_Show = new Form_Controller_Show($oForm);
       if (!is_null(Core_Array::getPost($oForm->button_name)))
          {
         $Form_Controller_Show
         ->values($_POST + $_FILES)
         // 0 - html, 1- plain text
         ->mailType(0)
         ->mailXsl(
            Core_Entity::factory('Xsl')->getByName('ПисьмоКураторуФормыВФорматеHTML')
         )
         ->mailFromFieldName('euronasos19@gmail.com')
         ->process();

        // Отправляем письмо-подтверждение пользователю
        $Form_Controller_Show1 = clone $Form_Controller_Show;
        $sEmail = Core_Array::get($Form_Controller_Show1->values, 'email');  // здесь указать название поля input для email в форме
        if (Core_Valid::email($sEmail)){
            ob_start();
            $Form_Controller_Show1
                ->xsl(
                    Core_Entity::factory('Xsl')->getByName('ПисьмоПодтверждениеПользователюФормыВФорматеHTML')
                )
                ->show();
            $sMailText = ob_get_clean();
            if (mb_strpos($sMailText, 'ERROR TRUE') === FALSE){
                $subject = 'На сайте site.ru Вами была заполнена форма Заявки';// Тему письма отредактировать
                $oCore_Mail = Core_Mail::instance()
                    ->to($sEmail)
                    ->from('info@site.ru')
                    ->subject($subject)
                    ->message(trim($sMailText))
                    ->contentType('text/html')
                    ->header('X-HostCMS-Reason', 'Form');

                $oCore_Mail->send();
                      }
                  }
              }
                $Form_Controller_Show
                  ->xsl(
                  Core_Entity::factory('Xsl')->getByName('ОтобразитьФормуЗаявкиВМодальномОкне')
                 )
                  ->show();
?>

XSL . ФормаЗаявкиВМодальномОкне

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet SYSTEM "lang://351">
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:hostcms="http://www.hostcms.ru/"
exclude-result-prefixes="hostcms">
<xsl:output xmlns="http://www.w3.org/TR/xhtml1/strict" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" encoding="utf-8" indent="yes" method="html" omit-xml-declaration="no" version="1.0" media-type="text/xml" />
<!-- ОтобразитьФорму -->
<xsl:template match="/">
<xsl:apply-templates select="/form" />
</xsl:template>
<xsl:template match="/form">
<xsl:choose>
<xsl:when test="success/node() and success = 1">
<!--div id="fade" style="display: block;"></div-->
<div class="modal fade form-success-result" id="modalSuccess" tabindex="-1" role="dialog">
<div class="modal-dialog  modal-dialog-centered">
<div class="modal-content p-5">
<div class="modal-header text-center">
<!--div class="modal-title w-100 fs-4 fw-bold">&labelModalTitle1;</div-->
<button class="btn-close" type="button" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<xsl:value-of disable-output-escaping="yes" select="success_text" />
</div>
</div>
</div>
</div>
<script>
let modalSuccess = new bootstrap.Modal(document.getElementById('modalSuccess'));
modalSuccess.show();
</script>
</xsl:when>
<!-- Выводим ошибку (error), если она была передана через внешний параметр -->
<xsl:when test="error != ''">
<div class="modal fade form-success-result" id="modalError" tabindex="-1" role="dialog">
<div class="modal-dialog  modal-dialog-centered">
<div class="modal-content p-5">
<div class="modal-header text-center">
<div class="modal-title w-100 fs-3 fw-bold">ОШИБКА!</div>
<button class=" " type="button" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body"><b><xsl:value-of disable-output-escaping="yes" select="error" /></b></div>
</div>
</div>
</div>
<script>
let modalError = new bootstrap.Modal(document.getElementById('modalError'));
modalError.show();
</script>
</xsl:when>
<xsl:when test="errorId/node()">
<div class="modal fade form-success-result" id="modalError" tabindex="-1" role="dialog">
<div class="modal-dialog  modal-dialog-centered">
<div class="modal-content p-5">
<div class="modal-header text-center">
<div class="modal-title w-100 fs-3 fw-bold">&labelERROR;</div>
<button class="btn-close" type="button" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<xsl:choose>
<xsl:when test="errorId = 0">
&labelTextErrorId0;
</xsl:when>
<xsl:when test="errorId = 1">
&labelTextErrorId1;
</xsl:when>
<xsl:when test="errorId = 2">
&labelTextErrorId2;
</xsl:when>
</xsl:choose>
</div>
</div>
</div>
</div>
<script>
let modalError = new bootstrap.Modal(document.getElementById('modalError'));
modalError.show();
</script>
</xsl:when>
<xsl:otherwise>
 <div class="modal fade" id="questionModal" tabindex="-1" aria-labelledby="questionModalLabel_{@id}" aria-hidden="true">
<div class="modal-dialog  modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header justify-content-center">
<div class="h2 m-0 modal-title" id="questionModalLabel_{@id}"><xsl:value-of disable-output-escaping="yes" select="name" /></div>
<button class="btn-close" type="button" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<xsl:if test="description !=''">
<xsl:value-of disable-output-escaping="yes" select="description" />
</xsl:if>
<div id="add-text" class="text-center"> </div>
<!-- Параметр action формы должен быть "./", если обработчик на этой же странице, либо "./form/", если обработчик на другой странице, например ./form/ -->
<form name="form{@id}" id="form{@id}" class="validate" action="./" method="post" enctype="multipart/form-data" >
<!-- Вывод разделов формы 0-го уровня -->
<xsl:apply-templates select="form_field_dir" />
<!-- Вывод списка полей формы 0-го уровня -->
<xsl:apply-templates select="form_field" />
<!-- Код подтверждения -->
<xsl:if test="captcha_id != 0">
<div class="form-group mb-3">
<div class="row">
<div class="col-6 caption">
<input type="hidden" name="captcha_id" value="{/form/captcha_id}"/>
<input type="text" name="captcha" size="15" class="form-control required" minlength="4" title="Введите число, которое указано на картинке."/>
<div class="padding-5">&labelCheckNumber1;<sup><font color="red">*</font></sup></div>
</div>
<div class="col-6 field">
<img id="formCaptcha_{/form/@id}_{/form/captcha_id}" src="/captcha.php?id={captcha_id}&amp;height=30&amp;width=100" class="captcha" name="captcha" />
<div class="captcha">
<img src="/images/refresh.png" /> <span class="small" onclick="$('#formCaptcha_{/form/@id}_{/form/captcha_id}').updateCaptcha('{/form/captcha_id}', 30); return false" style="cursor:pointer">&labelCheckNumber2;</span>
</div>
</div>
</div>
</div>
</xsl:if>
<!--div class="margin-bottom-10">
<div class="g-recaptcha" data-sitekey="6LfemXMiAAAAAPtn9tHaYj5z-0yKJq4Tmi3Ph1Cw"></div>
</div-->
<xsl:if test="csrf_token/node() and csrf_token != ''">
<input type="hidden" name="{csrf_field}" value="{csrf_token}" />
</xsl:if>
<div class="form-group">
<input type="hidden" name="{button_name}" value="submit"/>
<button id="submit_{@id}" value="submit" name="{button_name}" type="submit" class="btn btn-black mt-4 w-100"><xsl:value-of select="button_value" /></button>
</div>
</form>
<div class="mt-4">
<div class="form-check">
<input id="checkbox{@id}" class="form-check-input" type="checkbox" name="checkbox" checked="checked" onchange="document.getElementById('submit_{@id}').disabled = !this.checked;"/>
<label for="checkbox{@id}" class="form-check-label small" style="text-align:justify">Я соглашаюсь на обработку своих персональных данных в соответствии с <a href="/private" class="link-border"> Политикой конфиденциальности</a></label>
</div>
</div>
</div>
</div>
</div>
</div>
<SCRIPT>
<xsl:comment>
<xsl:text disable-output-escaping="yes">
    <![CDATA[
    $(function() {
    $("#fileUpload").on('change', function () {
 
     //Get count of selected files
     var countFiles = $(this)[0].files.length;
     var imgPath = $(this)[0].value;
     var extn = imgPath.substring(imgPath.lastIndexOf('.') + 1).toLowerCase();
     var image_holder = $("#image-holder");
     image_holder.empty();
 
     if (extn == "png" || extn == "jpg" || extn == "jpeg" || extn == "webp") {
         if (typeof (FileReader) != "undefined") {
 
             //loop for each file selected for uploaded.
             for (var i = 0; i < countFiles; i++) {
 
                 var reader = new FileReader();
                 reader.onload = function (e) {
                     $("<img />", {
                         "src": e.target.result,
                             "class": "thumb-image"
                     }).appendTo(image_holder);
                 }
 
                 image_holder.show();
                 reader.readAsDataURL($(this)[0].files[i]);
             }
 
         } else {
             alert("Ваш брузер не поддерживает FileReader!");
         }
     } else {
         alert("Выберите файл в формате JPG, JPEG, PNG или WEBP!");
     }
    });
    });
]]>
</xsl:text>
</xsl:comment>
</SCRIPT>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="form_field_dir">
<!--fieldset class="maillist_fieldset"-->
<!--legend><xsl:value-of select="name" /></legend-->
<!-- Вывод списка полей формы -->
<xsl:apply-templates select="form_field" />
<!-- Вывод разделов формы -->
<xsl:apply-templates select="form_field_dir" />
<!--/fieldset-->
</xsl:template>
<xsl:template match="form_field">
<!-- Не скрытое поле и не надпись -->
<xsl:if test="type != 7 and type != 8">
<div class="form-group mb-3">
<xsl:if test="type = 2">
<xsl:attribute name="class">form-group mb-2 me-4</xsl:attribute>
</xsl:if>
<xsl:variable name="caption">
<xsl:choose>
<xsl:when test="obligatory = 1">
<xsl:value-of select="caption" />*
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="caption" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<!-- Радиокнопки -->
<xsl:when test="type = 3 or type = 9">
<xsl:apply-templates select="list/list_item" />
</xsl:when>
<!-- Checkbox -->
<xsl:when test="type = 4">
<div class="pretty p-default p-pulse">
<input type="checkbox" name="{name}">
<xsl:if test="checked = 1 or value = 1">
<xsl:attribute name="checked">checked</xsl:attribute>
</xsl:if>
</input>
<div class="state p-danger-o">
<label><xsl:value-of select="value" /></label>
</div>
</div>
</xsl:when>
<!-- Textarea -->
<xsl:when test="type = 5">
<textarea class="form-control" name="{name}" cols="{cols}" rows="{rows}" placeholder="{$caption}">
<xsl:if test="obligatory = 1">
<xsl:attribute name="class">form-control required</xsl:attribute>
</xsl:if>
<xsl:value-of select="value" />
</textarea>
</xsl:when>
<!-- Список -->
<xsl:when test="type = 6">
<select name="{name}" class="wide">
<xsl:if test="obligatory = 1">
<xsl:attribute name="class">wide required</xsl:attribute>
<xsl:attribute name="title"><xsl:value-of select="caption" /></xsl:attribute>
</xsl:if>
<option value="">...</option>
<xsl:apply-templates select="list/list_item" />
</select>
</xsl:when>
<!-- Текстовые поля -->
<xsl:otherwise>
<xsl:if test="type = 2">
<label for="fileUpload" class="download-file">
<i class="svg_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="21px" height="21px" ><path style="fill:#797979" d="M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm16 336c0 8.822-7.178 16-16 16H48c-8.822 0-16-7.178-16-16V112c0-8.822 7.178-16 16-16h416c8.822 0 16 7.178 16 16v288zM112 232c30.928 0 56-25.072 56-56s-25.072-56-56-56-56 25.072-56 56 25.072 56 56 56zm0-80c13.234 0 24 10.766 24 24s-10.766 24-24 24-24-10.766-24-24 10.766-24 24-24zm207.029 23.029L224 270.059l-31.029-31.029c-9.373-9.373-24.569-9.373-33.941 0l-88 88A23.998 23.998 0 0 0 64 344v28c0 6.627 5.373 12 12 12h360c6.627 0 12-5.373 12-12v-92c0-6.365-2.529-12.47-7.029-16.971l-88-88c-9.373-9.372-24.569-9.372-33.942 0zM416 352H96v-4.686l80-80 48 48 112-112 80 80V352z"/></svg>
</i>
<span class="download-file-text ps-2">Выберите сразу несколько фото</span>
</label>
</xsl:if>
<input class="form-control" type="text" name="{name}" value="{value}" size="{size}" placeholder="{$caption}">
<xsl:choose>
<!-- Поле для ввода пароля -->
<xsl:when test="type = 1">
<xsl:attribute name="type">password</xsl:attribute>
</xsl:when>
<!-- Поле загрузки файла -->
<xsl:when test="type = 2">
<xsl:attribute name="type">file</xsl:attribute>
<xsl:attribute name="multiple">true</xsl:attribute>
<xsl:attribute name="class">photo</xsl:attribute>
<xsl:attribute name="name">files[]</xsl:attribute>
<xsl:attribute name="id">fileUpload</xsl:attribute>
<xsl:attribute name="accept">image/jpg,image/jpeg,image/png,image/webp</xsl:attribute>
<div id="image-holder" class="d-flex flex-wrap"></div>
</xsl:when>
<!-- HTML5: Дата -->
<xsl:when test="type = 10">
<xsl:attribute name="type">date</xsl:attribute>
</xsl:when>
<!-- HTML5: Цвет -->
<xsl:when test="type = 11">
<xsl:attribute name="type">color</xsl:attribute>
</xsl:when>
<!-- HTML5: Месяц -->
<xsl:when test="type = 12">
<xsl:attribute name="type">month</xsl:attribute>
</xsl:when>
<!-- HTML5: Неделя -->
<xsl:when test="type = 13">
<xsl:attribute name="type">week</xsl:attribute>
</xsl:when>
<!-- HTML5: Время -->
<xsl:when test="type = 14">
<xsl:attribute name="type">time</xsl:attribute>
</xsl:when>
<!-- HTML5: Дата-Время -->
<xsl:when test="type = 15">
<xsl:attribute name="type">datetime</xsl:attribute>
</xsl:when>
<!-- HTML5: E-mail -->
<xsl:when test="type = 16">
<xsl:attribute name="type">email</xsl:attribute>
</xsl:when>
<!-- HTML5: Поиск -->
<xsl:when test="type = 17">
<xsl:attribute name="type">search</xsl:attribute>
</xsl:when>
<!-- HTML5: Телефон -->
<xsl:when test="type = 18">
<xsl:attribute name="type">tel</xsl:attribute>
</xsl:when>
<!-- HTML5: URL -->
<xsl:when test="type = 19">
<xsl:attribute name="type">url</xsl:attribute>
</xsl:when>
<!-- Текстовое поле -->
<xsl:otherwise>
<xsl:attribute name="type">text</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="obligatory = 1">
<xsl:attribute name="class">form-control required</xsl:attribute>
</xsl:if>
<!--xsl:if test="@id = 15">
<xsl:attribute name="disabled">disabled</xsl:attribute>
</xsl:if-->
</input>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:if>
<!-- скрытое поле -->
<xsl:if test="type = 7">
<input type="hidden" name="{name}" value="{value}" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
//
//
//
Код DTD для языка "ru"

<!ENTITY labelModalTitle1 "Благодарим вас за заявку!">
<!ENTITY labelModalTitle2 "Заявка получена.">
<!ENTITY labelSuccessText "Мы свяжемся с вами в ближайшее время">
<!ENTITY labelSuccessText2 "Наш менеджер ответит на все ваши вопросы">

<!ENTITY labelERROR "ОШИБКА!">
<!ENTITY labelTextErrorId0 "Вы неправильно ввели код подтверждения отправки формы!">
<!ENTITY labelTextErrorId1 "Заполните все обязательные поля!">
<!ENTITY labelTextErrorId2 "С момента отправки последней формы прошло слишком мало времени!">

<!ENTITY labelTextError1 "Это поле пустое">
<!ENTITY labelTextError2 "E-mail должен иметь вид name@domain.com">

<!ENTITY labelText1 "Обязательное поле">

<!ENTITY labelCheckNumber1 "Проверочный код">
<!ENTITY labelCheckNumber2 "показать другой код">

Стили CSS

/******************************/

.ask-question {
    padding:20px;
    background-color: #f0f0f0;
    max-width:450px;
    text-align: center;
}
.ask-question > div:not(.last) {
     margin-bottom:15px;   
}

.btn.btn-transparent {

background: transparent;

border: 1px solid #212529;

color: #212529;

/******************************/