Enhance product management and coupon features
- Added styling for input group add-ons and additional fields in SCSS. - Updated shop coupon view to include a new column for usage count. - Display coupon code and amount in order details if applicable. - Improved product edit template to handle custom fields with required validation. - Modified product save logic to include custom field requirements. - Enhanced decimal normalization function for better input handling. - Implemented checkbox normalization for form submissions. - Updated custom fields in product templates to reflect required status. - Fixed URL for fetching changelog updates.
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -2228,4 +2228,20 @@ textarea.form-control {
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
width: auto;
|
||||
|
||||
label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.additional_fields {
|
||||
input[type="text"] {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,11 @@ $grid -> search = [
|
||||
[ 'name' => 'Wysłany', 'db' => 'send', 'type' => 'select', 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ] ]
|
||||
];
|
||||
$grid -> columns_view = [
|
||||
[
|
||||
[
|
||||
'name' => 'Lp.',
|
||||
'th' => [ 'class' => 'g-lp' ],
|
||||
'td' => [ 'class' => 'g-center' ],
|
||||
'autoincrement' => true
|
||||
'autoincrement' => true
|
||||
], [
|
||||
'name' => 'Aktywny',
|
||||
'db' => 'status',
|
||||
@@ -24,6 +24,11 @@ $grid -> columns_view = [
|
||||
'td' => [ 'class' => 'g-center' ],
|
||||
'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ],
|
||||
'sort' => true
|
||||
], [
|
||||
'name' => 'Użyto X razy',
|
||||
'db' => 'used_count',
|
||||
'td' => [ 'class' => 'g-center' ],
|
||||
'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ],
|
||||
], [
|
||||
'name' => 'Nazwa',
|
||||
'db' => 'name',
|
||||
@@ -60,22 +65,22 @@ $grid -> columns_view = [
|
||||
'db' => 'date_used',
|
||||
'td' => [ 'class' => 'g-center' ],
|
||||
'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ]
|
||||
], [
|
||||
'name' => 'Edytuj',
|
||||
'action' => [ 'type' => 'edit', 'url' => '/admin/shop_coupon/coupon_edit/id=[id]' ],
|
||||
], [
|
||||
'name' => 'Edytuj',
|
||||
'action' => [ 'type' => 'edit', 'url' => '/admin/shop_coupon/coupon_edit/id=[id]' ],
|
||||
'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ],
|
||||
'td' => [ 'class' => 'g-center' ]
|
||||
], [
|
||||
'name' => 'Usuń',
|
||||
'action' => [ 'type' => 'delete', 'url' => '/admin/shop_coupon/coupon_delete/id=[id]' ],
|
||||
], [
|
||||
'name' => 'Usuń',
|
||||
'action' => [ 'type' => 'delete', 'url' => '/admin/shop_coupon/coupon_delete/id=[id]' ],
|
||||
'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ],
|
||||
'td' => [ 'class' => 'g-center' ]
|
||||
]
|
||||
];
|
||||
$grid -> buttons = [
|
||||
[
|
||||
'label' => 'Dodaj kupon',
|
||||
'url' => '/admin/shop_coupon/coupon_edit/',
|
||||
[
|
||||
'label' => 'Dodaj kupon',
|
||||
'url' => '/admin/shop_coupon/coupon_edit/',
|
||||
'icon' => 'fa-plus-circle',
|
||||
'class' => 'btn-success'
|
||||
]
|
||||
|
||||
@@ -44,6 +44,9 @@ ob_start();
|
||||
<div class="panel">
|
||||
<div class="panel-body">
|
||||
<div>Kwota zamówienia <b><?= $this -> order[ 'summary' ];?> zł</b></div>
|
||||
<? if ( $this -> coupon ):?>
|
||||
<div>Kod rabatowy: <span style="color: #cc0000;"><?= $this -> coupon -> name;?> - <?= $this -> coupon -> amount;?> <?= $this -> coupon -> type == 1 ? '%' : 'zł';?></span></div>
|
||||
<? endif;?>
|
||||
<br>
|
||||
<div><?= strip_tags( $this -> order[ 'transport' ] );?>: <b><?= $this -> order[ 'transport_cost' ];?> zł</b></div>
|
||||
<? if ( $this -> order['transport_id'] == 2 and $this -> order[ 'inpost_paczkomat' ] ):?>
|
||||
|
||||
@@ -663,12 +663,19 @@ ob_start();
|
||||
<div>
|
||||
<a href="#" class="btn btn-success" id="add_custom_field"><i class="fa fa-plus"></i> dodaj niestandardowe pole</a>
|
||||
<div class="additional_fields">
|
||||
<? if ( is_array( $this -> product['custom_fields'] ) ) : foreach ( $this -> product['custom_fields'] as $field ):?>
|
||||
<div class="form-group row">
|
||||
<? if ( is_array( $this->product['custom_fields'] ) ) : foreach ( $this->product['custom_fields'] as $field ):?>
|
||||
<? $isRequired = !empty($field['is_required']); ?>
|
||||
<div class="form-group row custom-field-row">
|
||||
<label class="col-lg-4 control-label">Nazwa pola:</label>
|
||||
<div class="col-lg-8">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" name="custom_field_name[]" value="<?= $field['name']; ?>">
|
||||
<input type="text" class="form-control" name="custom_field_name[]" value="<?= htmlspecialchars($field['name']); ?>">
|
||||
<span class="input-group-addon">
|
||||
<label style="margin:0; font-weight:normal;">
|
||||
<input type="checkbox" class="custom-field-required" <?= $isRequired ? 'checked' : '' ?> name="custom_field_required[]" />
|
||||
wymagane
|
||||
</label>
|
||||
</span>
|
||||
<span class="input-group-addon btn btn-info" onclick="remove_custom_filed( $( this ) );">usuń</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -740,17 +747,23 @@ echo $grid->draw();
|
||||
|
||||
$(function() {
|
||||
|
||||
$( 'body' ).on( 'click', '#add_custom_field', function() {
|
||||
$('body').on('click', '#add_custom_field', function() {
|
||||
var html = '';
|
||||
html += '<div class="form-group row">';
|
||||
html += '<div class="form-group row custom-field-row">';
|
||||
html += '<label class="col-lg-4 control-label">Nazwa pola:</label>';
|
||||
html += '<div class="col-lg-8">';
|
||||
html +='<div class="input-group">';
|
||||
html += '<div class="input-group">';
|
||||
html += '<input type="text" class="form-control" name="custom_field_name[]" value="">';
|
||||
html += '<span class="input-group-addon">';
|
||||
html += '<label style="margin:0; font-weight:normal;">';
|
||||
html += '<input type="checkbox" class="custom-field-required" name="custom_field_required[]"> wymagane';
|
||||
html += '</label>';
|
||||
html += '</span>';
|
||||
html += '<span class="input-group-addon btn btn-info" onclick="remove_custom_filed( $( this ) );">usuń</span>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
$( '.additional_fields' ).append( html );
|
||||
$('.additional_fields').append(html);
|
||||
});
|
||||
|
||||
$('body').on('click', '#product-preview', function() {
|
||||
|
||||
@@ -64,7 +64,7 @@ echo $grid -> draw();
|
||||
?>
|
||||
<?
|
||||
ob_start();
|
||||
echo $versions = file_get_contents( 'https://shoppro.project-dc.pl/updates/changelog.php' );
|
||||
echo $versions = file_get_contents( 'http://www.shoppro.project-dc.pl/updates/changelog.php' );
|
||||
$out = ob_get_clean();
|
||||
|
||||
$grid = new \gridEdit;
|
||||
|
||||
@@ -186,7 +186,7 @@ class ShopProduct
|
||||
$values['id'], $values['name'], $values['short_description'], $values['description'], $values['status'], $values['meta_description'], $values['meta_keywords'], $values['seo_link'],
|
||||
$values['copy_from'], $values['categories'], $values['price_netto'], $values['price_brutto'], $values['vat'], $values['promoted'], $values['warehouse_message_zero'], $values['warehouse_message_nonzero'], $values['tab_name_1'],
|
||||
$values['tab_description_1'], $values['tab_name_2'], $values['tab_description_2'], $values['layout_id'], $values['products_related'], (int) $values['set'], $values['price_netto_promo'], $values['price_brutto_promo'],
|
||||
$values['new_to_date'], $values['stock_0_buy'], $values['wp'], $values['custom_label_0'], $values['custom_label_1'], $values['custom_label_2'], $values['custom_label_3'], $values['custom_label_4'], $values['additional_message'], (int)$values['quantity'], $values['additional_message_text'], $values['additional_message_required'] == 'on' ? 1 : 0, $values['canonical'], $values['meta_title'], $values['producer_id'], $values['sku'], $values['ean'], $values['product_unit'], $values['weight'], $values['xml_name'], $values['custom_field_name']
|
||||
$values['new_to_date'], $values['stock_0_buy'], $values['wp'], $values['custom_label_0'], $values['custom_label_1'], $values['custom_label_2'], $values['custom_label_3'], $values['custom_label_4'], $values['additional_message'], (int)$values['quantity'], $values['additional_message_text'], $values['additional_message_required'] == 'on' ? 1 : 0, $values['canonical'], $values['meta_title'], $values['producer_id'], $values['sku'], $values['ean'], $values['product_unit'], $values['weight'], $values['xml_name'], $values['custom_field_name'], $values['custom_field_required']
|
||||
) ) {
|
||||
$response = [ 'status' => 'ok', 'msg' => 'Produkt został zapisany.', 'id' => $id ];
|
||||
}
|
||||
|
||||
@@ -761,7 +761,7 @@ class ShopProduct
|
||||
}
|
||||
|
||||
public static function save(
|
||||
$product_id, $name, $short_description, $description, $status, $meta_description, $meta_keywords, $seo_link, $copy_from, $categories, $price_netto, $price_brutto, $vat, $promoted, $warehouse_message_zero, $warehouse_message_nonzero, $tab_name_1, $tab_description_1, $tab_name_2, $tab_description_2, $layout_id, $products_related, int $set_id, $price_netto_promo, $price_brutto_promo, $new_to_date, $stock_0_buy, $wp, $custom_label_0, $custom_label_1, $custom_label_2, $custom_label_3, $custom_label_4, $additional_message, int $quantity, $additional_message_text, int $additional_message_required, $canonical, $meta_title, $producer_id, $sku, $ean, $product_unit, $weight, $xml_name, $custom_field_name
|
||||
$product_id, $name, $short_description, $description, $status, $meta_description, $meta_keywords, $seo_link, $copy_from, $categories, $price_netto, $price_brutto, $vat, $promoted, $warehouse_message_zero, $warehouse_message_nonzero, $tab_name_1, $tab_description_1, $tab_name_2, $tab_description_2, $layout_id, $products_related, int $set_id, $price_netto_promo, $price_brutto_promo, $new_to_date, $stock_0_buy, $wp, $custom_label_0, $custom_label_1, $custom_label_2, $custom_label_3, $custom_label_4, $additional_message, int $quantity, $additional_message_text, int $additional_message_required, $canonical, $meta_title, $producer_id, $sku, $ean, $product_unit, $weight, $xml_name, $custom_field_name, $custom_field_required
|
||||
)
|
||||
{
|
||||
global $mdb, $user;
|
||||
@@ -941,13 +941,17 @@ class ShopProduct
|
||||
}
|
||||
|
||||
// dodatkowe pola
|
||||
foreach ( $custom_field_name as $custom_field )
|
||||
for ( $i = 0; $i < count( $custom_field_name ); ++$i )
|
||||
{
|
||||
if ( !empty( $custom_field ) )
|
||||
if ( !empty( $custom_field_name[$i] ) )
|
||||
{
|
||||
$custom_field = $custom_field_name[$i];
|
||||
$custom_field_required = isset( $custom_field_required[$i] ) ? 1 : 0;
|
||||
|
||||
$mdb -> insert( 'pp_shop_products_custom_fields', [
|
||||
'id_product' => (int) $id,
|
||||
'name' => $custom_field,
|
||||
'is_required' => $custom_field_required,
|
||||
] );
|
||||
}
|
||||
}
|
||||
@@ -1268,13 +1272,20 @@ class ShopProduct
|
||||
|
||||
$mdb -> delete( 'pp_shop_products_custom_fields', [ 'AND' => [ 'id_product' => $product_id, 'id_additional_field[!]' => $exits_custom_ids ] ] );
|
||||
|
||||
foreach ( $custom_field_name as $custom_field )
|
||||
// $custom_field_name i $custom_field_required
|
||||
foreach ( $custom_field_name as $i => $custom_field )
|
||||
{
|
||||
if ( !empty( $custom_field ) )
|
||||
{
|
||||
$is_required = !empty( $custom_field_required[$i] ) ? 1 : 0;
|
||||
|
||||
if ( !$mdb -> count( 'pp_shop_products_custom_fields', [ 'AND' => [ 'id_product' => $product_id, 'name' => $custom_field ] ] ) )
|
||||
{
|
||||
$mdb -> insert( 'pp_shop_products_custom_fields', [ 'id_product' => $product_id, 'name' => $custom_field ] );
|
||||
$mdb -> insert( 'pp_shop_products_custom_fields', [ 'id_product' => $product_id, 'name' => $custom_field, 'is_required' => $is_required ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$mdb -> update( 'pp_shop_products_custom_fields', [ 'is_required' => $is_required ], [ 'AND' => [ 'id_product' => $product_id, 'name' => $custom_field ] ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,17 +322,42 @@ class S
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function normalize_decimal( $val, $precision = 2 )
|
||||
static public function normalize_decimal($val, int $precision = 2)
|
||||
{
|
||||
$input = str_replace( ' ', '', $val );
|
||||
$number = str_replace( ',', '.', $input );
|
||||
if ( strpos( $number, '.' ) )
|
||||
{
|
||||
$groups = explode( '.', str_replace( ',', '.', $number ) );
|
||||
$lastGroup = array_pop( $groups );
|
||||
$number = implode( '', $groups ) . '.' . $lastGroup;
|
||||
if ($val === null || $val === '') {
|
||||
return number_format(0, $precision, '.', '');
|
||||
}
|
||||
return bcadd( round( $number, $precision ), 0, $precision );
|
||||
|
||||
// 1) wstępne czyszczenie
|
||||
$s = (string)$val;
|
||||
$s = str_replace(["\xC2\xA0", ' ', '’', "'"], '', $s); // spacje (w tym NBSP) i apostrofy
|
||||
$s = preg_replace('/[^0-9.,\-]/', '', $s); // zostaw tylko cyfry, . , i -
|
||||
|
||||
// 2) ustalenie separatora dziesiętnego
|
||||
$lastDot = strrpos($s, '.');
|
||||
$lastComma = strrpos($s, ',');
|
||||
|
||||
if ($lastDot !== false && $lastComma !== false) {
|
||||
// oba występują – prawy znak traktujemy jako dziesiętny
|
||||
if ($lastDot > $lastComma) {
|
||||
$s = str_replace(',', '', $s); // , = tysiące
|
||||
} else {
|
||||
$s = str_replace('.', '', $s); // . = tysiące
|
||||
$s = str_replace(',', '.', $s); // , = dziesiętny
|
||||
}
|
||||
} elseif ($lastComma !== false) {
|
||||
// tylko przecinek – traktuj jako dziesiętny
|
||||
$s = str_replace(',', '.', $s);
|
||||
} elseif (substr_count($s, '.') > 1) {
|
||||
// wiele kropek – ostatnia dziesiętna, pozostałe tysiące
|
||||
$pos = strrpos($s, '.');
|
||||
$s = str_replace('.', '', substr($s, 0, $pos)) . '.' . substr($s, $pos + 1);
|
||||
}
|
||||
// na tym etapie mamy opcjonalny '-' i co najwyżej jedną kropkę dziesiętną
|
||||
|
||||
// 3) zaokrąglenie i normalizacja
|
||||
$rounded = round((float)$s, $precision);
|
||||
return number_format($rounded, $precision, '.', '');
|
||||
}
|
||||
|
||||
public static function decimal( $val, $precision = 2, $dec_point = ',', $thousands_sep = ' ' )
|
||||
|
||||
@@ -485,6 +485,8 @@ jQuery( 'body' ).on( 'click', '#g-cancel', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
jQuery( 'body' ).on( 'click', '#g-save, #g-edit-save', function()
|
||||
{
|
||||
var back_url = jQuery( this ).attr( 'back_url' );
|
||||
@@ -534,6 +536,44 @@ jQuery( 'body' ).on( 'click', '#g-save, #g-edit-save', function()
|
||||
}
|
||||
});
|
||||
|
||||
/* === UNIWERSALNA NORMALIZACJA CHECKBOXÓW TABLICOWYCH ===
|
||||
Dla wszystkich input[type=checkbox] z name="coś[]":
|
||||
- jeśli wartości są typu boolean ('', '1', 'on', 'true', 'yes') → zbuduj pełną tablicę 1/0 w kolejności DOM,
|
||||
tak aby indeksy były ciągłe [0..N-1] nawet gdy część jest odznaczona.
|
||||
- jeśli to lista wyboru (np. categories[] z różnymi ID) → pozostaw jak z serializeArray (tylko zaznaczone).
|
||||
*/
|
||||
(function normalizeCheckboxArrays() {
|
||||
var $form = jQuery('#fg-' + gtable);
|
||||
if (!$form.length) return;
|
||||
|
||||
// zgrupuj checkboxy po pełnej nazwie (z [] na końcu)
|
||||
var groups = {};
|
||||
$form.find('input[type="checkbox"][name$="[]"]').each(function () {
|
||||
var n = this.name; // np. "required[]", "visible[]", "categories[]"
|
||||
(groups[n] = groups[n] || []).push(this);
|
||||
});
|
||||
|
||||
Object.keys(groups).forEach(function (nameWithBrackets) {
|
||||
var inputs = groups[nameWithBrackets];
|
||||
if (!inputs.length) return;
|
||||
|
||||
// sprawdź, czy wszystkie wartości wyglądają „booleanowo”
|
||||
var uniqVals = Array.from(new Set(inputs.map(function (el) {
|
||||
return (el.getAttribute('value') || '').toLowerCase();
|
||||
})));
|
||||
var boolSet = new Set(['', '1', 'on', 'true', 'yes']);
|
||||
var isBooleanLike = uniqVals.every(function (v) { return boolSet.has(v); });
|
||||
|
||||
if (isBooleanLike) {
|
||||
var baseKey = nameWithBrackets.replace(/\[\]$/, ''); // usuń [] → "required", "visible"
|
||||
// pełna tablica 1/0 w kolejności w formularzu
|
||||
formattedValues[baseKey] = inputs.map(function (el) { return el.checked ? '1' : '0'; });
|
||||
}
|
||||
// else: zostawiamy formattedValues tak jak już zbudowane z serializeArray()
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
var url = jQuery( this ).attr( 'url' );
|
||||
|
||||
if ( url !== '' )
|
||||
|
||||
BIN
templates/.DS_Store
vendored
BIN
templates/.DS_Store
vendored
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
<?= $custom_field['name'];?>:
|
||||
</div>
|
||||
<div class="_input">
|
||||
<input type="text" class="form-control" name="custom_field[<?= $custom_field['id_additional_field'];?>]" field_name="<?= $custom_field['name'];?>" value="">
|
||||
<input type="text" class="form-control" name="custom_field[<?= $custom_field['id_additional_field'];?>]" field_name="<?= $custom_field['name'];?>" value="" <? if ( !empty( $custom_field['is_required'] ) ): ?>required<? endif; ?>>
|
||||
</div>
|
||||
</div>
|
||||
<? endforeach; endif;?>
|
||||
@@ -255,22 +255,24 @@
|
||||
<script class="footer" type="text/javascript" src="/libraries/fancybox3/js/wheel.js"></script>
|
||||
<script class="footer" type="text/javascript" src="/plugins/OwlCarousel/owl.carousel.js"></script>
|
||||
<script type="text/javascript">
|
||||
<? if ( $this -> settings['google_tag_manager_id'] ):?>
|
||||
dataLayer.push({ ecommerce: null });
|
||||
dataLayer.push({
|
||||
event: "view_item",
|
||||
ecommerce: {
|
||||
items: [
|
||||
{
|
||||
item_id: "<?= $this -> product -> id;?>",
|
||||
item_name: "<?= str_replace( '"', '', $this -> product -> language['name'] );?>",
|
||||
price: '<? if ( $this -> product -> price_brutto_promo ): echo \S::normalize_decimal( $this -> product -> price_brutto_promo ); else: echo \S::normalize_decimal( $this -> product -> price_brutto ); endif;?>',
|
||||
quantity: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
<? endif;?>
|
||||
$(function(){
|
||||
<? if ( $this -> settings['google_tag_manager_id'] ):?>
|
||||
dataLayer.push({ ecommerce: null });
|
||||
dataLayer.push({
|
||||
event: "view_item",
|
||||
ecommerce: {
|
||||
items: [
|
||||
{
|
||||
item_id: "<?= $this -> product -> id;?>",
|
||||
item_name: "<?= str_replace( '"', '', $this -> product -> language['name'] );?>",
|
||||
price: '<? if ( $this -> product -> price_brutto_promo ): echo \S::normalize_decimal( $this -> product -> price_brutto_promo ); else: echo \S::normalize_decimal( $this -> product -> price_brutto ); endif;?>',
|
||||
quantity: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
<? endif;?>
|
||||
});
|
||||
</script>
|
||||
<script class="footer" type="text/javascript">
|
||||
$( function ()
|
||||
@@ -524,7 +526,7 @@
|
||||
}
|
||||
|
||||
// dodatkowe pola muszą być uzupełnione
|
||||
$( '.custom-field input' ).each( function( index, element )
|
||||
$( '.custom-field input[required]' ).each( function( index, element )
|
||||
{
|
||||
if ( $.trim( $( element ).val() ) == '' )
|
||||
{
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<? if ( is_array( $this -> custom_fields ) ): foreach ( $this -> custom_fields as $custom_field ):?>
|
||||
<div class="custom-field">
|
||||
<div class="_name">
|
||||
<?= $custom_field['name'];?>:
|
||||
<?= $custom_field['name'];?><? if ( !empty( $custom_field['is_required'] ) ): ?>*<? endif; ?>:
|
||||
</div>
|
||||
<div class="_input">
|
||||
<div class="grow-wrap">
|
||||
<textarea name="custom_field[<?= $custom_field['id_additional_field'];?>]" field_name="<?= $custom_field['name'];?>" onInput="this.parentNode.dataset.replicatedValue = this.value"></textarea>
|
||||
<textarea name="custom_field[<?= $custom_field['id_additional_field'];?>]" field_name="<?= $custom_field['name'];?>" onInput="this.parentNode.dataset.replicatedValue = this.value" <? if ( !empty( $custom_field['is_required'] ) ): ?>required<? endif; ?>></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -537,7 +537,7 @@
|
||||
}
|
||||
|
||||
// dodatkowe pola muszą być uzupełnione
|
||||
$( '.custom-field textarea' ).each( function( index, element )
|
||||
$( '.custom-field textarea[required]' ).each( function( index, element )
|
||||
{
|
||||
if ( $.trim( $( element ).val() ) == '' )
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user