Compare commits
No commits in common. "b07d60d8e53ec282d4d0a291e96326aecc881e9b" and "140e40e79a82f0423161edd75982bd3af74045cd" have entirely different histories.
b07d60d8e5
...
140e40e79a
|
@ -6,10 +6,8 @@ namespace mirzaev\arming_bot\controllers;
|
||||||
|
|
||||||
// Files of the project
|
// Files of the project
|
||||||
use mirzaev\arming_bot\controllers\core,
|
use mirzaev\arming_bot\controllers\core,
|
||||||
mirzaev\arming_bot\models\cart as model,
|
|
||||||
mirzaev\arming_bot\models\product,
|
mirzaev\arming_bot\models\product,
|
||||||
mirzaev\arming_bot\models\menu,
|
mirzaev\arming_bot\models\cart as model;
|
||||||
mirzaev\arming_bot\models\enumerations\language;
|
|
||||||
|
|
||||||
// Framework for ArangoDB
|
// Framework for ArangoDB
|
||||||
use mirzaev\arangodb\document;
|
use mirzaev\arangodb\document;
|
||||||
|
@ -30,74 +28,9 @@ final class cart extends core
|
||||||
protected array $errors = [
|
protected array $errors = [
|
||||||
'session' => [],
|
'session' => [],
|
||||||
'account' => [],
|
'account' => [],
|
||||||
'cart' => [],
|
'cart' => []
|
||||||
'menu' => [],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* Cart
|
|
||||||
*
|
|
||||||
* @param array $parameters Parameters of the request (POST + GET)
|
|
||||||
*/
|
|
||||||
public function index(array $parameters = []): ?string
|
|
||||||
{
|
|
||||||
if (isset($menu)) {
|
|
||||||
//
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Not received ... menu
|
|
||||||
|
|
||||||
// Search for filters and write to the buffer of global variables of view templater
|
|
||||||
$this->view->menu = menu::_read(
|
|
||||||
return: 'MERGE(d, { name: d.name.@language })',
|
|
||||||
sort: 'd.style.order ASC, d.created DESC, d._key DESC',
|
|
||||||
amount: 4,
|
|
||||||
parameters: ['language' => $this->language->name],
|
|
||||||
errors: $this->errors['menu']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|
||||||
// GET request
|
|
||||||
|
|
||||||
// Exit (success)
|
|
||||||
return $this->view->render('cart/page.html', [
|
|
||||||
'h2' => $this->language === language::ru ? 'Корзина' : 'Cart' // @see https://git.mirzaev.sexy/mirzaev/huesos/issues/1
|
|
||||||
]);
|
|
||||||
} else if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
||||||
// POST request
|
|
||||||
|
|
||||||
// Initializing a response headers
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
header('Content-Encoding: none');
|
|
||||||
header('X-Accel-Buffering: no');
|
|
||||||
|
|
||||||
// Initializing of the output buffer
|
|
||||||
ob_start();
|
|
||||||
|
|
||||||
// Generating the reponse
|
|
||||||
echo json_encode(
|
|
||||||
[
|
|
||||||
'main' => '',
|
|
||||||
'errors' => $this->errors
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Initializing a response headers
|
|
||||||
header('Content-Length: ' . ob_get_length());
|
|
||||||
|
|
||||||
// Sending and deinitializing of the output buffer
|
|
||||||
ob_end_flush();
|
|
||||||
flush();
|
|
||||||
|
|
||||||
// Exit (success)
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit (fail)
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Product
|
* Product
|
||||||
*
|
*
|
||||||
|
@ -118,7 +51,7 @@ final class cart extends core
|
||||||
|
|
||||||
// Validating @todo add throwing errors
|
// Validating @todo add throwing errors
|
||||||
$identifier = null;
|
$identifier = null;
|
||||||
if (isset($parameters['identifier']) && preg_match('/[\d]+/', urldecode($parameters['identifier']), $matches)) $identifier = (int) $matches[0];
|
if (!empty($parameters['identifier']) && preg_match('/[\d]+/', urldecode($parameters['identifier']), $matches)) $identifier = (int) $matches[0];
|
||||||
|
|
||||||
if (isset($identifier)) {
|
if (isset($identifier)) {
|
||||||
// Received and validated identfier of the product
|
// Received and validated identfier of the product
|
||||||
|
@ -143,7 +76,7 @@ final class cart extends core
|
||||||
|
|
||||||
// Validating @todo add throwing errors
|
// Validating @todo add throwing errors
|
||||||
$type = null;
|
$type = null;
|
||||||
if (isset($parameters['type']) && preg_match('/[\w]+/', urldecode($parameters['type']), $matches)) $type = $matches[0];
|
if (!empty($parameters['type']) && preg_match('/[\w]+/', urldecode($parameters['type']), $matches)) $type = $matches[0];
|
||||||
|
|
||||||
if (isset($type)) {
|
if (isset($type)) {
|
||||||
// Received and validated type of action with the product
|
// Received and validated type of action with the product
|
||||||
|
@ -173,7 +106,7 @@ final class cart extends core
|
||||||
|
|
||||||
// Validating @todo add throwing errors
|
// Validating @todo add throwing errors
|
||||||
$_amount = null;
|
$_amount = null;
|
||||||
if (isset($parameters['amount']) && preg_match('/[\d]+/', urldecode($parameters['amount']), $matches)) $_amount = (int) $matches[0];
|
if (!empty($parameters['amount']) && preg_match('/[\d]+/', urldecode($parameters['amount']), $matches)) $_amount = (int) $matches[0];
|
||||||
|
|
||||||
if (isset($_amount)) {
|
if (isset($_amount)) {
|
||||||
// Received and validated amount parameter for action with the product
|
// Received and validated amount parameter for action with the product
|
||||||
|
@ -181,26 +114,20 @@ final class cart extends core
|
||||||
if ($type === 'write') {
|
if ($type === 'write') {
|
||||||
// Increase amount of the product in the cart
|
// Increase amount of the product in the cart
|
||||||
|
|
||||||
if ($amount + $_amount < 101) {
|
if (101 > $amount += $_amount) {
|
||||||
// Validated amount to wrting
|
// Validated amount to wrting
|
||||||
|
|
||||||
// Writing the product to the cart
|
// Writing the product to the cart
|
||||||
$this->cart->write(product: $product, amount: $_amount, errors: $this->errors['cart']);
|
$this->cart->write(product: $product, amount: $_amount, errors: $this->errors['cart']);
|
||||||
|
|
||||||
// Reinitialize the buffer with amount of the product in the cart
|
|
||||||
$amount += $_amount;
|
|
||||||
}
|
}
|
||||||
} else if ($type === 'delete') {
|
} else if ($type === 'delete') {
|
||||||
// Decrease amount of the product in the cart
|
// Decrease amount of the product in the cart
|
||||||
|
|
||||||
if ($amount - $_amount > -1) {
|
if (-1 < $amount -= $_amount) {
|
||||||
// Validated amount to deleting
|
// Validated amount to deleting
|
||||||
|
|
||||||
// Deleting the product from the cart
|
// Deleting the product from the cart
|
||||||
$this->cart->delete(product: $product, amount: $_amount, errors: $this->errors['cart']);
|
$this->cart->delete(product: $product, amount: $_amount, errors: $this->errors['cart']);
|
||||||
|
|
||||||
// Reinitialize the buffer with amount of the product in the cart
|
|
||||||
$amount -= $_amount;
|
|
||||||
}
|
}
|
||||||
} else if ($type === 'set') {
|
} else if ($type === 'set') {
|
||||||
// Set amount of the product in the cart
|
// Set amount of the product in the cart
|
||||||
|
@ -261,49 +188,4 @@ final class cart extends core
|
||||||
// Exit (fail)
|
// Exit (fail)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Summary
|
|
||||||
*
|
|
||||||
* @param array $parameters Parameters of the request (POST + GET)
|
|
||||||
*/
|
|
||||||
public function summary(array $parameters = []): ?string
|
|
||||||
{
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
||||||
// POST request
|
|
||||||
|
|
||||||
// Initializing summary data of the cart
|
|
||||||
$summary = $this->cart?->summary(currency: $this->currency, errors: $this->errors['cart']);
|
|
||||||
|
|
||||||
// Initializing response headers
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
header('Content-Encoding: none');
|
|
||||||
header('X-Accel-Buffering: no');
|
|
||||||
|
|
||||||
// Initializing of the output buffer
|
|
||||||
ob_start();
|
|
||||||
|
|
||||||
// Generating the reponse
|
|
||||||
echo json_encode(
|
|
||||||
[
|
|
||||||
'cost' => $summary['cost'] ?? 0,
|
|
||||||
'amount' => $summary['amount'] ?? 0,
|
|
||||||
'errors' => $this->errors
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Initializing a response headers
|
|
||||||
header('Content-Length: ' . ob_get_length());
|
|
||||||
|
|
||||||
// Sending and deinitializing of the output buffer
|
|
||||||
ob_end_flush();
|
|
||||||
flush();
|
|
||||||
|
|
||||||
// Exit (success)
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit (fail)
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,22 +43,22 @@ final class catalog extends core
|
||||||
public function index(array $parameters = []): ?string
|
public function index(array $parameters = []): ?string
|
||||||
{
|
{
|
||||||
// validating
|
// validating
|
||||||
if (isset($parameters['product']) && preg_match('/[\d]+/', $parameters['product'], $matches)) $product = (int) $matches[0];
|
if (!empty($parameters['product']) && preg_match('/[\d]+/', $parameters['product'], $matches)) $product = (int) $matches[0];
|
||||||
|
|
||||||
if (isset($product)) {
|
if (isset($product)) {
|
||||||
// Received and validated identifier of the product
|
// received and validated identifier of the product
|
||||||
|
|
||||||
// Search for the product data and write to the buffer of global variables of view templater
|
// Search for the product data and write to the buffer of global variables of view templater
|
||||||
$this->view->product = product::read(
|
$this->view->product = product::read(
|
||||||
filter: "d.identifier == @identifier && d.deleted != true && d.hidden != true",
|
filter: "d.identifier == @identifier && d.deleted != true && d.hidden != true",
|
||||||
sort: 'd.created DESC',
|
sort: 'd.created DESC',
|
||||||
amount: 1,
|
amount: 1,
|
||||||
return: '{identifier: d.identifier, name: d.name.@language, description: d.description.@language, cost: d.cost, weight: d.weight, dimensions: d.dimensions, brand: d.brand.@language, compatibility: d.compatibility.@language, cost: d.cost.@currency, images: d.images[*].storage}',
|
return: '{name: d.name.@language, description: d.description.@language, cost: d.cost, weight: d.weight, dimensions: d.dimensions, brand: d.brand.@language, compatibility: d.compatibility.@language, cost: d.cost.@currency, images: d.images[*].storage}',
|
||||||
language: $this->language,
|
language: $this->language,
|
||||||
currency: $this->currency,
|
currency: $this->currency,
|
||||||
parameters: ['identifier' => $product],
|
parameters: ['identifier' => $product],
|
||||||
errors: $this->errors['catalog']
|
errors: $this->errors['catalog']
|
||||||
)?->getAll();
|
)[0]?->getAll() ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intializing buffer of query parameters
|
// Intializing buffer of query parameters
|
||||||
|
@ -68,7 +68,7 @@ final class catalog extends core
|
||||||
$_filters = 'd.deleted != true && d.hidden != true';
|
$_filters = 'd.deleted != true && d.hidden != true';
|
||||||
|
|
||||||
// Validating
|
// Validating
|
||||||
if (isset($parameters['brand']) && preg_match('/[\w\s]+/u', urldecode($parameters['brand']), $matches)) $brand = $matches[0];
|
if (!empty($parameters['brand']) && preg_match('/[\w\s]+/u', urldecode($parameters['brand']), $matches)) $brand = $matches[0];
|
||||||
|
|
||||||
if (isset($brand)) {
|
if (isset($brand)) {
|
||||||
// Received and validated filter by brand
|
// Received and validated filter by brand
|
||||||
|
@ -130,7 +130,7 @@ final class catalog extends core
|
||||||
$_sort = 'd.position ASC, d.name ASC, d.created DESC';
|
$_sort = 'd.position ASC, d.name ASC, d.created DESC';
|
||||||
|
|
||||||
// Validating
|
// Validating
|
||||||
if (isset($parameters['sort']) && preg_match('/[\w\s]+/u', $parameters['sort'], $matches)) $sort = $matches[0];
|
if (!empty($parameters['sort']) && preg_match('/[\w\s]+/u', $parameters['sort'], $matches)) $sort = $matches[0];
|
||||||
|
|
||||||
if (isset($sort)) {
|
if (isset($sort)) {
|
||||||
// Received and validated sort
|
// Received and validated sort
|
||||||
|
@ -181,7 +181,7 @@ final class catalog extends core
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validating @todo add throwing errors
|
// Validating @todo add throwing errors
|
||||||
if (isset($parameters['text']) && preg_match('/[\w\s]+/u', urldecode($parameters['text']), $matches) && mb_strlen($matches[0]) > 2) $text = $matches[0];
|
if (!empty($parameters['text']) && preg_match('/[\w\s]+/u', urldecode($parameters['text']), $matches) && mb_strlen($matches[0]) > 2) $text = $matches[0];
|
||||||
|
|
||||||
if (isset($text)) {
|
if (isset($text)) {
|
||||||
// Received and validated text
|
// Received and validated text
|
||||||
|
@ -234,7 +234,7 @@ final class catalog extends core
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validating
|
// Validating
|
||||||
if (isset($parameters['category']) && preg_match('/[\d]+/', $parameters['category'], $matches)) $category = (int) $matches[0];
|
if (!empty($parameters['category']) && preg_match('/[\d]+/', $parameters['category'], $matches)) $category = (int) $matches[0];
|
||||||
|
|
||||||
if (isset($category)) {
|
if (isset($category)) {
|
||||||
// Received and validated identifier of the category
|
// Received and validated identifier of the category
|
||||||
|
@ -296,23 +296,19 @@ final class catalog extends core
|
||||||
) ?? null;
|
) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($brand) || (isset($this->view->products) && count($this->view->products) > 0)) {
|
// Search among products in the $category
|
||||||
// Received and validated at least one of filters or amount of rendered products is more than 0
|
if (isset($this->view->products) && count($this->view->products) > 0) {
|
||||||
|
// Amount of rendered products is more than 0
|
||||||
|
|
||||||
// Search for filters and write to the buffer of global variables of view templater
|
// Search for filters and write to the buffer of global variables of view templater
|
||||||
$this->view->filters = [
|
$this->view->filters = [
|
||||||
'brands' => product::collect(
|
'brands' => product::collect(
|
||||||
return: 'd.brand.@language',
|
return: 'd.brand.@language',
|
||||||
products: array_map(fn(_document $document): string => $document->getId(), $this->view->products ?? []),
|
products: array_map(fn(_document $document): string => $document->getId(), $this->view->products),
|
||||||
language: $this->language,
|
language: $this->language,
|
||||||
errors: $this->errors['catalog']
|
errors: $this->errors['catalog']
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
// Search among products in the $category
|
|
||||||
if (isset($text) || isset($this->view->products) && count($this->view->products) > 0) {
|
|
||||||
// Amount of rendered products is more than 0
|
|
||||||
|
|
||||||
// Search for products and write to the buffer of global variables of view templater
|
// Search for products and write to the buffer of global variables of view templater
|
||||||
$this->view->products = product::read(
|
$this->view->products = product::read(
|
||||||
|
@ -337,7 +333,7 @@ final class catalog extends core
|
||||||
// Search for filters and write to the buffer of global variables of view templater
|
// Search for filters and write to the buffer of global variables of view templater
|
||||||
$this->view->menu = menu::_read(
|
$this->view->menu = menu::_read(
|
||||||
return: 'MERGE(d, { name: d.name.@language })',
|
return: 'MERGE(d, { name: d.name.@language })',
|
||||||
sort: 'd.style.order ASC, d.created DESC, d._key DESC',
|
sort: 'd.position ASC, d.created DESC, d._key DESC',
|
||||||
amount: 4,
|
amount: 4,
|
||||||
parameters: ['language' => $this->language->name],
|
parameters: ['language' => $this->language->name],
|
||||||
errors: $this->errors['menu']
|
errors: $this->errors['menu']
|
||||||
|
@ -351,16 +347,11 @@ final class catalog extends core
|
||||||
// Initialized the product data
|
// Initialized the product data
|
||||||
|
|
||||||
// Writing javascript code that has been executed after core and damper has been loaded
|
// Writing javascript code that has been executed after core and damper has been loaded
|
||||||
$this->view->javascript = [
|
$this->view->javascript = [<<<javascript
|
||||||
sprintf(
|
|
||||||
<<<javascript
|
|
||||||
if (typeof _window === 'undefined') {
|
if (typeof _window === 'undefined') {
|
||||||
_window = setTimeout(() => core.catalog.product_system('%s'), 500);
|
_window = setTimeout(() => core.catalog.product_system('$product'), 500);
|
||||||
}
|
}
|
||||||
javascript,
|
javascript] + ($this->view->javascript ?? []);
|
||||||
$this->view->product['identifier']
|
|
||||||
)
|
|
||||||
] + ($this->view->javascript ?? []);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
|
|
|
@ -52,7 +52,7 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
*
|
*
|
||||||
* @return array|null Array with implementing objects of documents from ArangoDB, if found
|
* @return array|null Array with implementing objects of documents from ArangoDB, if found
|
||||||
*/
|
*/
|
||||||
public function products(
|
public function all(
|
||||||
?language $language = language::en,
|
?language $language = language::en,
|
||||||
?currency $currency = currency::usd,
|
?currency $currency = currency::usd,
|
||||||
array &$errors = []
|
array &$errors = []
|
||||||
|
@ -72,7 +72,7 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
RETURN {
|
RETURN {
|
||||||
[d._id]: {
|
[d._id]: {
|
||||||
amount,
|
amount,
|
||||||
document: MERGE(d, {
|
product: MERGE(d, {
|
||||||
name: d.name.@language,
|
name: d.name.@language,
|
||||||
description: d.description.@language,
|
description: d.description.@language,
|
||||||
compatibility: d.compatibility.@language,
|
compatibility: d.compatibility.@language,
|
||||||
|
@ -124,64 +124,6 @@ final class cart extends core implements document_interface, collection_interfac
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for summary of all products
|
|
||||||
*
|
|
||||||
* Search for summary of all products in the cart
|
|
||||||
*
|
|
||||||
* @param currency|null $currency Currency
|
|
||||||
* @param array &$errors Registry of errors
|
|
||||||
*
|
|
||||||
* @return array|null Array with implementing objects of documents from ArangoDB, if found
|
|
||||||
*/
|
|
||||||
public function summary(
|
|
||||||
?currency $currency = currency::usd,
|
|
||||||
array &$errors = []
|
|
||||||
): ?array {
|
|
||||||
try {
|
|
||||||
if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
|
|
||||||
if (collection::initialize(reservation::COLLECTION, reservation::TYPE, errors: $errors)) {
|
|
||||||
if (collection::initialize(product::COLLECTION, product::TYPE, errors: $errors)) {
|
|
||||||
// Initialized collections
|
|
||||||
|
|
||||||
// Search for all products in the cart
|
|
||||||
$result = @collection::execute(
|
|
||||||
<<<AQL
|
|
||||||
FOR v IN 1..1 INBOUND @cart GRAPH @graph
|
|
||||||
FILTER IS_SAME_COLLECTION(@collection, v._id)
|
|
||||||
COLLECT AGGREGATE amount = COUNT(v), cost = SUM(v.cost.@currency)
|
|
||||||
RETURN { amount, cost }
|
|
||||||
AQL,
|
|
||||||
[
|
|
||||||
'graph' => 'catalog',
|
|
||||||
'cart' => $this->getId(),
|
|
||||||
'collection' => product::COLLECTION,
|
|
||||||
'currency' => $currency->name
|
|
||||||
],
|
|
||||||
flat: true,
|
|
||||||
errors: $errors
|
|
||||||
);
|
|
||||||
|
|
||||||
// Exit (success)
|
|
||||||
return $result;
|
|
||||||
} else throw new exception('Failed to initialize ' . product::TYPE . ' collection: ' . product::COLLECTION);
|
|
||||||
} else throw new exception('Failed to initialize ' . reservation::TYPE . ' collection: ' . reservation::COLLECTION);
|
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
|
||||||
} catch (exception $e) {
|
|
||||||
// Writing to the registry of errors
|
|
||||||
$errors[] = [
|
|
||||||
'text' => $e->getMessage(),
|
|
||||||
'file' => $e->getFile(),
|
|
||||||
'line' => $e->getLine(),
|
|
||||||
'stack' => $e->getTrace()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit (fail)
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Count
|
* Count
|
||||||
*
|
*
|
||||||
|
|
|
@ -205,7 +205,7 @@ final class product extends core implements document_interface, collection_inter
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($amount === 1 && $result instanceof _document) {
|
if ($amount === 1 && $result instanceof _document) {
|
||||||
// Found the product @todo need to rebuild this
|
// Found product @todo need to rebuild this
|
||||||
|
|
||||||
// Initializing the object
|
// Initializing the object
|
||||||
$product = new static;
|
$product = new static;
|
||||||
|
@ -219,12 +219,10 @@ final class product extends core implements document_interface, collection_inter
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return $product;
|
return $product;
|
||||||
} else throw new exception('Class ' . static::class . ' does not implement a document from ArangoDB');
|
} else throw new exception('Class ' . static::class . ' does not implement a document from ArangoDB');
|
||||||
} else if (!empty($result)) {
|
}
|
||||||
// Found products
|
|
||||||
|
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return is_array($result) ? $result : [$result];
|
return is_array($result) ? $result : [$result];
|
||||||
}
|
|
||||||
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Writing to the registry of errors
|
// Writing to the registry of errors
|
||||||
|
|
|
@ -43,7 +43,6 @@ $router
|
||||||
->write('/cart', 'cart', 'index', 'GET')
|
->write('/cart', 'cart', 'index', 'GET')
|
||||||
->write('/cart', 'cart', 'index', 'POST')
|
->write('/cart', 'cart', 'index', 'POST')
|
||||||
->write('/cart/product', 'cart', 'product', 'POST')
|
->write('/cart/product', 'cart', 'product', 'POST')
|
||||||
->write('/cart/summary', 'cart', 'summary', 'POST')
|
|
||||||
->write('/account/write', 'account', 'write', 'POST')
|
->write('/account/write', 'account', 'write', 'POST')
|
||||||
->write('/session/write', 'session', 'write', 'POST')
|
->write('/session/write', 'session', 'write', 'POST')
|
||||||
->write('/session/connect/telegram', 'session', 'telegram', 'POST')
|
->write('/session/connect/telegram', 'session', 'telegram', 'POST')
|
||||||
|
|
|
@ -39,26 +39,17 @@ import("/js/core.js").then(() =>
|
||||||
*
|
*
|
||||||
* Toggle the product in the cart (interface)
|
* Toggle the product in the cart (interface)
|
||||||
*
|
*
|
||||||
* @param {HTMLButtonElement|HTMLInputElement} element Handler elememnt of the product
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
* @param {HTMLElement} product The product
|
|
||||||
* @param {bool} remove Remove the product element if json.amount === 0?
|
|
||||||
* @param {bool} force Ignore the damper? (false)
|
* @param {bool} force Ignore the damper? (false)
|
||||||
*
|
*
|
||||||
* @return {bool} True if an error occurs to continue the event execution
|
* @return {bool} True if an error occurs to continue the event execution
|
||||||
*/
|
*/
|
||||||
static toggle(element, product, remove = false, force = false) {
|
static toggle(button, force = false) {
|
||||||
// Blocking the element
|
// Blocking the button
|
||||||
element.setAttribute("disabled", "true");
|
button.setAttribute("disabled", "true");
|
||||||
|
|
||||||
// Execute under damper
|
// Execute under damper
|
||||||
this.toggle_damper(
|
this.toggle_damper(button, force);
|
||||||
element,
|
|
||||||
product,
|
|
||||||
"toggle",
|
|
||||||
undefined,
|
|
||||||
remove,
|
|
||||||
force,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Exit (success)
|
// Exit (success)
|
||||||
return false;
|
return false;
|
||||||
|
@ -69,249 +60,49 @@ import("/js/core.js").then(() =>
|
||||||
*
|
*
|
||||||
* Toggle the product in the cart (damper)
|
* Toggle the product in the cart (damper)
|
||||||
*
|
*
|
||||||
* @param {HTMLButtonElement|HTMLInputElement} element Handler elememnt of the product
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
* @param {HTMLElement} product The product
|
|
||||||
* @param {bool} remove Remove the product element if json.amount === 0?
|
|
||||||
* @param {bool} force Ignore the damper? (false)
|
* @param {bool} force Ignore the damper? (false)
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
static toggle_damper = core.damper(
|
static toggle_damper = core.damper(
|
||||||
(...variables) => this.product(...variables).then(this.summary),
|
(...variables) => this.toggle_system(...variables),
|
||||||
300,
|
300,
|
||||||
6,
|
2,
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write
|
* Toggle
|
||||||
*
|
*
|
||||||
* Write the product in the cart (interface)
|
* Toggle the product in the cart (system)
|
||||||
*
|
*
|
||||||
* @param {HTMLButtonElement|HTMLInputElement} element Handler elememnt of the product
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
* @param {HTMLElement} product The product
|
|
||||||
* @param {number} amount Amount of writings
|
|
||||||
* @param {bool} remove Remove the product element if json.amount === 0?
|
|
||||||
* @param {bool} force Ignore the damper? (false)
|
|
||||||
*
|
*
|
||||||
* @return {bool} True if an error occurs to continue the event execution
|
* @return {Promise} Request to the server
|
||||||
|
*
|
||||||
|
* @todo add unblocking button by timer + everywhere
|
||||||
*/
|
*/
|
||||||
static write(
|
static async toggle_system(button) {
|
||||||
element,
|
if (button instanceof HTMLElement) {
|
||||||
product,
|
|
||||||
amount = 1,
|
|
||||||
remove = false,
|
|
||||||
force = false,
|
|
||||||
) {
|
|
||||||
// Blocking the element
|
|
||||||
element.setAttribute("disabled", "true");
|
|
||||||
|
|
||||||
// Execute under damper
|
|
||||||
this.write_damper(element, product, "write", amount, remove, force);
|
|
||||||
|
|
||||||
// Exit (success)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write
|
|
||||||
*
|
|
||||||
* Write the product in the cart (damper)
|
|
||||||
*
|
|
||||||
* @param {HTMLButtonElement|HTMLInputElement} element Handler elememnt of the product
|
|
||||||
* @param {HTMLElement} product The product
|
|
||||||
* @param {number} amount Amount of writings
|
|
||||||
* @param {bool} remove Remove the product element if json.amount === 0?
|
|
||||||
* @param {bool} force Ignore the damper? (false)
|
|
||||||
*
|
|
||||||
* @return {Promise}
|
|
||||||
*/
|
|
||||||
static write_damper = core.damper(
|
|
||||||
(...variables) => this.product(...variables).then(this.summary),
|
|
||||||
300,
|
|
||||||
6,
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete
|
|
||||||
*
|
|
||||||
* Delete the product from the cart (interface)
|
|
||||||
*
|
|
||||||
* @param {HTMLButtonElement|HTMLInputElement} element Handler elememnt of the product
|
|
||||||
* @param {HTMLElement} product The product
|
|
||||||
* @param {number} amount Amount of deletings
|
|
||||||
* @param {bool} remove Remove the product element if json.amount === 0?
|
|
||||||
* @param {bool} force Ignore the damper? (false)
|
|
||||||
*
|
|
||||||
* @return {bool} True if an error occurs to continue the event execution
|
|
||||||
*/
|
|
||||||
static delete(
|
|
||||||
element,
|
|
||||||
product,
|
|
||||||
amount = 1,
|
|
||||||
remove = false,
|
|
||||||
force = false,
|
|
||||||
) {
|
|
||||||
// Blocking the element
|
|
||||||
element.setAttribute("disabled", "true");
|
|
||||||
|
|
||||||
// Execute under damper
|
|
||||||
this.delete_damper(
|
|
||||||
element,
|
|
||||||
product,
|
|
||||||
"delete",
|
|
||||||
amount,
|
|
||||||
remove,
|
|
||||||
force,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Exit (success)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete
|
|
||||||
*
|
|
||||||
* Delete the product from the cart (damper)
|
|
||||||
*
|
|
||||||
* @param {HTMLButtonElement|HTMLInputElement} element Handler elememnt of the product
|
|
||||||
* @param {number} amount Amount of deletings
|
|
||||||
* @param {bool} remove Remove the product element if json.amount === 0?
|
|
||||||
* @param {bool} force Ignore the damper? (false)
|
|
||||||
*
|
|
||||||
* @return {Promise}
|
|
||||||
*/
|
|
||||||
static delete_damper = core.damper(
|
|
||||||
(...variables) => this.product(...variables).then(this.summary),
|
|
||||||
300,
|
|
||||||
6,
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set
|
|
||||||
*
|
|
||||||
* Set amount of the product in the cart (interface)
|
|
||||||
*
|
|
||||||
* @param {HTMLButtonElement|HTMLInputElement} element Handler elememnt of the product
|
|
||||||
* @param {HTMLElement} product The product
|
|
||||||
* @param {number} amount Amount of the product in the cart to be setted
|
|
||||||
* @param {bool} remove Remove the product element if json.amount === 0?
|
|
||||||
* @param {bool} force Ignore the damper? (false)
|
|
||||||
*
|
|
||||||
* @return {bool} True if an error occurs to continue the event execution
|
|
||||||
*/
|
|
||||||
static set(
|
|
||||||
element,
|
|
||||||
product,
|
|
||||||
amount = 1,
|
|
||||||
remove = false,
|
|
||||||
force = false,
|
|
||||||
) {
|
|
||||||
// Blocking the element
|
|
||||||
element.setAttribute("disabled", "true");
|
|
||||||
|
|
||||||
// Execute under damper
|
|
||||||
this.set_damper(element, product, "set", amount, remove, force);
|
|
||||||
|
|
||||||
// Exit (success)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set
|
|
||||||
*
|
|
||||||
* Set the product in the cart (damper)
|
|
||||||
*
|
|
||||||
* @param {HTMLButtonElement|HTMLInputElement} element Handler elememnt of the product
|
|
||||||
* @param {HTMLElement} product The product
|
|
||||||
* @param {number} amount Amount of the product in the cart to be setted
|
|
||||||
* @param {bool} remove Remove the product element if json.amount === 0?
|
|
||||||
* @param {bool} force Ignore the damper? (false)
|
|
||||||
*
|
|
||||||
* @return {Promise}
|
|
||||||
*/
|
|
||||||
static set_damper = core.damper(
|
|
||||||
(...parameters) => this.product(...parameters).then(this.summary),
|
|
||||||
300,
|
|
||||||
6,
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The product
|
|
||||||
*
|
|
||||||
* Handle the product in the cart (system)
|
|
||||||
*
|
|
||||||
* @param {HTMLButtonElement|HTMLInputElement} element Handler element of the product
|
|
||||||
* @param {HTMLElement} product The product element
|
|
||||||
* @param {string} type Type of action with the product
|
|
||||||
* @param {number} amount Amount of product to handle
|
|
||||||
* @param {bool} remove Remove the product element if json.amount === 0?
|
|
||||||
*
|
|
||||||
* @return {Promise|null}
|
|
||||||
*/
|
|
||||||
static async product(
|
|
||||||
element,
|
|
||||||
product,
|
|
||||||
type,
|
|
||||||
amount = null,
|
|
||||||
remove = false,
|
|
||||||
resolve = () => {},
|
|
||||||
reject = () => {},
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
(element instanceof HTMLButtonElement ||
|
|
||||||
element instanceof HTMLInputElement) &&
|
|
||||||
product instanceof HTMLElement
|
|
||||||
) {
|
|
||||||
// Validated
|
// Validated
|
||||||
|
|
||||||
// Initializing the buffer of request body
|
// Initializing of the wrap of buttons
|
||||||
let request = "";
|
const wrap = button.parentElement;
|
||||||
|
|
||||||
|
// Initializing of the product
|
||||||
|
const product = wrap.parentElement;
|
||||||
|
|
||||||
// Initializing of identifier of the product
|
// Initializing of identifier of the product
|
||||||
const identifier = +product.getAttribute(
|
const identifier = product.getAttribute(
|
||||||
"data-product-identifier",
|
"data-product-identifier",
|
||||||
);
|
);
|
||||||
|
|
||||||
if (typeof identifier === "number") {
|
if (typeof identifier === "string" && identifier.length > 0) {
|
||||||
// Validated identifier
|
// Validated identifier
|
||||||
|
|
||||||
// Writing to the buffer of request body
|
|
||||||
request += "&identifier=" + identifier;
|
|
||||||
|
|
||||||
if (
|
|
||||||
type === "toggle" ||
|
|
||||||
type === "write" ||
|
|
||||||
type === "delete" ||
|
|
||||||
type === "set"
|
|
||||||
) {
|
|
||||||
// Validated type
|
|
||||||
|
|
||||||
// Writing to the buffer of request body
|
|
||||||
request += "&type=" + type;
|
|
||||||
|
|
||||||
if (
|
|
||||||
(type === "toggle" &&
|
|
||||||
typeof amount === "undefined") ||
|
|
||||||
(type === "set" &&
|
|
||||||
amount === 0 ||
|
|
||||||
amount === 100) ||
|
|
||||||
typeof amount === "number" &&
|
|
||||||
amount > 0 &&
|
|
||||||
amount < 100
|
|
||||||
) {
|
|
||||||
// Validated amount
|
|
||||||
|
|
||||||
if (type !== "toggle") {
|
|
||||||
// Not a toggle request
|
|
||||||
|
|
||||||
// Writing to the buffer of request body
|
|
||||||
request += "&amount=" + amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request
|
|
||||||
return await core.request(
|
return await core.request(
|
||||||
"/cart/product",
|
"/cart/product",
|
||||||
request,
|
`identifier=${identifier}&type=toggle`,
|
||||||
)
|
)
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
if (
|
if (
|
||||||
|
@ -323,21 +114,13 @@ import("/js/core.js").then(() =>
|
||||||
} else {
|
} else {
|
||||||
// Success (not received errors)
|
// Success (not received errors)
|
||||||
|
|
||||||
if (remove && json.amount === 0) {
|
// Unblocking the button
|
||||||
// Requested deleting of the product element when there is no the product in the cart
|
button.removeAttribute("disabled");
|
||||||
|
|
||||||
// Deleting the product element
|
|
||||||
product.remove();
|
|
||||||
} else {
|
|
||||||
// Not requested deleting the product element when there is no the product in the cart
|
|
||||||
|
|
||||||
// Unblocking the element
|
|
||||||
element.removeAttribute("disabled");
|
|
||||||
|
|
||||||
// Writing offset of hue-rotate to indicate that the product is in the cart
|
// Writing offset of hue-rotate to indicate that the product is in the cart
|
||||||
product.style.setProperty(
|
wrap.style.setProperty(
|
||||||
"--hue-rotate-offset",
|
"--hue-rotate-offset",
|
||||||
json.amount + "0deg",
|
json.amount + '0deg',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Writing attribute with amount of the product in the cart
|
// Writing attribute with amount of the product in the cart
|
||||||
|
@ -347,50 +130,100 @@ import("/js/core.js").then(() =>
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initializing the amount <span> element
|
// Initializing the amount <span> element
|
||||||
const amounts = product.querySelectorAll(
|
const amount = wrap.querySelector(
|
||||||
'[data-product-parameter="amount"]',
|
'span[data-product-button-text="amount"]',
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const amount of amounts) {
|
if (amount instanceof HTMLElement) {
|
||||||
// Iterating over an amount elements
|
// Initialized the amount <span> element
|
||||||
|
|
||||||
if (amount instanceof HTMLInputElement) {
|
|
||||||
// The <input> element
|
|
||||||
|
|
||||||
// Writing amount of the product in the cart
|
|
||||||
amount.value = json.amount;
|
|
||||||
} else {
|
|
||||||
// Not the <input> element
|
|
||||||
|
|
||||||
// Writing amount of the product in the cart
|
// Writing amount of the product in the cart
|
||||||
amount.innerText = json.amount;
|
amount.innerText = json.amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exit (success)
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Exit (fail)
|
/**
|
||||||
reject();
|
* Write
|
||||||
|
*
|
||||||
|
* Write the product in the cart (interface)
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
|
* @param {number} amount Amount of writings
|
||||||
|
* @param {bool} force Ignore the damper? (false)
|
||||||
|
*
|
||||||
|
* @return {bool} True if an error occurs to continue the event execution
|
||||||
|
*/
|
||||||
|
static write(button, amount = 1, force = false) {
|
||||||
|
// Blocking the button
|
||||||
|
button.setAttribute("disabled", "true");
|
||||||
|
|
||||||
|
// Execute under damper
|
||||||
|
this.write_damper(button, amount, force);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Summary
|
* Write
|
||||||
*
|
*
|
||||||
* Initialize summary of products the cart (system)
|
* Write the product in the cart (damper)
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
|
* @param {number} amount Amount of writings
|
||||||
|
* @param {bool} force Ignore the damper? (false)
|
||||||
*
|
*
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
static async summary() {
|
static write_damper = core.damper(
|
||||||
// Request
|
(...variables) => this.write_system(...variables),
|
||||||
return await core.request("/cart/summary")
|
300,
|
||||||
|
3,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write
|
||||||
|
*
|
||||||
|
* Write the product in the cart (system)
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
|
* @param {number} amount Amount of writings
|
||||||
|
*
|
||||||
|
* @return {Promise} Request to the server
|
||||||
|
*
|
||||||
|
* @todo add unblocking button by timer + everywhere
|
||||||
|
*/
|
||||||
|
static async write_system(button, amount = 1) {
|
||||||
|
if (
|
||||||
|
button instanceof HTMLElement &&
|
||||||
|
typeof amount === "number" &&
|
||||||
|
amount > -1 &&
|
||||||
|
amount < 100
|
||||||
|
) {
|
||||||
|
// Validated
|
||||||
|
|
||||||
|
// Initializing of the wrap of buttons
|
||||||
|
const wrap = button.parentElement;
|
||||||
|
|
||||||
|
// Initializing of the product
|
||||||
|
const product = wrap.parentElement;
|
||||||
|
|
||||||
|
// Initializing of identifier of the product
|
||||||
|
const identifier = product.getAttribute(
|
||||||
|
"data-product-identifier",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (typeof identifier === "string" && identifier.length > 0) {
|
||||||
|
// Validated identifier
|
||||||
|
|
||||||
|
return await core.request(
|
||||||
|
"/cart/product",
|
||||||
|
`identifier=${identifier}&type=write&amount=${amount}`,
|
||||||
|
)
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
if (
|
if (
|
||||||
json.errors !== null &&
|
json.errors !== null &&
|
||||||
|
@ -401,28 +234,277 @@ import("/js/core.js").then(() =>
|
||||||
} else {
|
} else {
|
||||||
// Success (not received errors)
|
// Success (not received errors)
|
||||||
|
|
||||||
// Initializing the summary amount <span> element
|
// Unblocking the button
|
||||||
const amount = document.getElementById("amount");
|
button.removeAttribute("disabled");
|
||||||
|
|
||||||
// Initializing the summary cost <span> element
|
// Writing offset of hue-rotate to indicate that the product is in the cart
|
||||||
const cost = document.getElementById("cost");
|
wrap.style.setProperty(
|
||||||
|
"--hue-rotate-offset",
|
||||||
|
json.amount + '0deg',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Writing attribute with amount of the product in the cart
|
||||||
|
product.setAttribute(
|
||||||
|
"data-product-amount",
|
||||||
|
json.amount,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Initializing the amount <span> element
|
||||||
|
const amount = wrap.querySelector(
|
||||||
|
'span[data-product-button-text="amount"]',
|
||||||
|
);
|
||||||
|
|
||||||
if (amount instanceof HTMLElement) {
|
if (amount instanceof HTMLElement) {
|
||||||
// Initialized the summary amount element
|
// Initialized the amount <span> element
|
||||||
|
|
||||||
// Writing summmary amount into the summary amount element
|
// Writing amount of the product in the cart
|
||||||
amount.innerText = json.amount;
|
amount.innerText = json.amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cost instanceof HTMLElement) {
|
|
||||||
// Initialized the summary cost element
|
|
||||||
|
|
||||||
// Writing summmary cost into the summary cost element
|
|
||||||
cost.innerText = json.cost;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete
|
||||||
|
*
|
||||||
|
* Delete the product from the cart (interface)
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
|
* @param {number} amount Amount of deletings
|
||||||
|
* @param {bool} force Ignore the damper? (false)
|
||||||
|
*
|
||||||
|
* @return {bool} True if an error occurs to continue the event execution
|
||||||
|
*/
|
||||||
|
static delete(button, amount = 1, force = false) {
|
||||||
|
// Blocking the button
|
||||||
|
button.setAttribute("disabled", "true");
|
||||||
|
|
||||||
|
// Execute under damper
|
||||||
|
this.delete_damper(button, amount, force);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete
|
||||||
|
*
|
||||||
|
* Delete the product from the cart (damper)
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
|
* @param {number} amount Amount of deletings
|
||||||
|
* @param {bool} force Ignore the damper? (false)
|
||||||
|
*
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
static delete_damper = core.damper(
|
||||||
|
(...variables) => this.delete_system(...variables),
|
||||||
|
300,
|
||||||
|
3,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete
|
||||||
|
*
|
||||||
|
* Delete the product from the cart (system)
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
|
* @param {number} amount Amount of deletings
|
||||||
|
*
|
||||||
|
* @return {Promise} Request to the server
|
||||||
|
*
|
||||||
|
* @todo add unblocking button by timer + everywhere
|
||||||
|
*/
|
||||||
|
static async delete_system(button, amount = 1) {
|
||||||
|
if (
|
||||||
|
button instanceof HTMLElement &&
|
||||||
|
typeof amount === "number" &&
|
||||||
|
amount > 0 &&
|
||||||
|
amount < 101
|
||||||
|
) {
|
||||||
|
// Validated
|
||||||
|
|
||||||
|
// Initializing of the wrap of buttons
|
||||||
|
const wrap = button.parentElement;
|
||||||
|
|
||||||
|
// Initializing of the product
|
||||||
|
const product = wrap.parentElement;
|
||||||
|
|
||||||
|
// Initializing of identifier of the product
|
||||||
|
const identifier = product.getAttribute(
|
||||||
|
"data-product-identifier",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (typeof identifier === "string" && identifier.length > 0) {
|
||||||
|
// Validated identifier
|
||||||
|
|
||||||
|
return await core.request(
|
||||||
|
"/cart/product",
|
||||||
|
`identifier=${identifier}&type=delete&amount=${amount}`,
|
||||||
|
)
|
||||||
|
.then((json) => {
|
||||||
|
if (
|
||||||
|
json.errors !== null &&
|
||||||
|
typeof json.errors === "object" &&
|
||||||
|
json.errors.length > 0
|
||||||
|
) {
|
||||||
|
// Fail (received errors)
|
||||||
|
} else {
|
||||||
|
// Success (not received errors)
|
||||||
|
|
||||||
|
// Unblocking the button
|
||||||
|
button.removeAttribute("disabled");
|
||||||
|
|
||||||
|
// Writing offset of hue-rotate to indicate that the product is in the cart
|
||||||
|
wrap.style.setProperty(
|
||||||
|
"--hue-rotate-offset",
|
||||||
|
json.amount + '0deg',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Writing attribute with amount of the product in the cart
|
||||||
|
product.setAttribute(
|
||||||
|
"data-product-amount",
|
||||||
|
json.amount,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Initializing the amount <span> element
|
||||||
|
const amount = wrap.querySelector(
|
||||||
|
'span[data-product-button-text="amount"]',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (amount instanceof HTMLElement) {
|
||||||
|
// Initialized the amount <span> element
|
||||||
|
|
||||||
|
// Writing amount of the product in the cart
|
||||||
|
amount.innerText = json.amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set
|
||||||
|
*
|
||||||
|
* Set amount of the product in the cart (interface)
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
|
* @param {number} amount Amount of the product in the cart to be setted
|
||||||
|
* @param {bool} force Ignore the damper? (false)
|
||||||
|
*
|
||||||
|
* @return {bool} True if an error occurs to continue the event execution
|
||||||
|
*/
|
||||||
|
static set(button, amount = 1, force = false) {
|
||||||
|
// Blocking the button
|
||||||
|
button.setAttribute("disabled", "true");
|
||||||
|
|
||||||
|
// Execute under damper
|
||||||
|
this.set_damper(button, amount, force);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set
|
||||||
|
*
|
||||||
|
* Set the product in the cart (damper)
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
|
* @param {number} amount Amount of the product in the cart to be setted
|
||||||
|
* @param {bool} force Ignore the damper? (false)
|
||||||
|
*
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
static set_damper = core.damper(
|
||||||
|
(...variables) => this.set_system(...variables),
|
||||||
|
300,
|
||||||
|
3,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set
|
||||||
|
*
|
||||||
|
* Set the product in the cart (system)
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} button Button of the product <a>
|
||||||
|
* @param {number} amount Amount of the product in the cart to be setted
|
||||||
|
*
|
||||||
|
* @return {Promise} Request to the server
|
||||||
|
*
|
||||||
|
* @todo add unblocking button by timer + everywhere
|
||||||
|
*/
|
||||||
|
static async set_system(button, amount = 1) {
|
||||||
|
if (
|
||||||
|
button instanceof HTMLElement &&
|
||||||
|
typeof amount === "number" &&
|
||||||
|
amount > -1 &&
|
||||||
|
amount < 101
|
||||||
|
) {
|
||||||
|
// Validated
|
||||||
|
|
||||||
|
// Initializing of the wrap of buttons
|
||||||
|
const wrap = button.parentElement;
|
||||||
|
|
||||||
|
// Initializing of the product
|
||||||
|
const product = wrap.parentElement;
|
||||||
|
|
||||||
|
// Initializing of identifier of the product
|
||||||
|
const identifier = product.getAttribute(
|
||||||
|
"data-product-identifier",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (typeof identifier === "string" && identifier.length > 0) {
|
||||||
|
// Validated identifier
|
||||||
|
|
||||||
|
return await core.request(
|
||||||
|
"/cart/product",
|
||||||
|
`identifier=${identifier}&type=set&amount=${amount}`,
|
||||||
|
)
|
||||||
|
.then((json) => {
|
||||||
|
if (
|
||||||
|
json.errors !== null &&
|
||||||
|
typeof json.errors === "object" &&
|
||||||
|
json.errors.length > 0
|
||||||
|
) {
|
||||||
|
// Fail (received errors)
|
||||||
|
} else {
|
||||||
|
// Success (not received errors)
|
||||||
|
|
||||||
|
// Unblocking the button
|
||||||
|
button.removeAttribute("disabled");
|
||||||
|
|
||||||
|
// Writing offset of hue-rotate to indicate that the product is in the cart
|
||||||
|
wrap.style.setProperty(
|
||||||
|
"--hue-rotate-offset",
|
||||||
|
json.amount + '0deg',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Writing attribute with amount of the product in the cart
|
||||||
|
product.setAttribute(
|
||||||
|
"data-product-amount",
|
||||||
|
json.amount,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Initializing the amount <span> element
|
||||||
|
const amount = wrap.querySelector(
|
||||||
|
'span[data-product-button-text="amount"]',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (amount instanceof HTMLElement) {
|
||||||
|
// Initialized the amount <span> element
|
||||||
|
|
||||||
|
// Writing amount of the product in the cart
|
||||||
|
amount.innerText = json.amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,9 +50,8 @@ import("/js/core.js").then(() =>
|
||||||
this.element_search.getElementsByTagName("input")[0];
|
this.element_search.getElementsByTagName("input")[0];
|
||||||
|
|
||||||
// Categories <section>
|
// Categories <section>
|
||||||
static element_categories = document.getElementById(
|
static element_categories =
|
||||||
"categories",
|
document.getElementById("categories");
|
||||||
);
|
|
||||||
|
|
||||||
// Filters <section>
|
// Filters <section>
|
||||||
static element_filters = document.getElementById("filters");
|
static element_filters = document.getElementById("filters");
|
||||||
|
@ -76,7 +75,7 @@ import("/js/core.js").then(() =>
|
||||||
[
|
[
|
||||||
"category",
|
"category",
|
||||||
new URLSearchParams(document.location.search).get(
|
new URLSearchParams(document.location.search).get(
|
||||||
"category",
|
"category"
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -129,12 +128,6 @@ import("/js/core.js").then(() =>
|
||||||
if (event.keyCode === 13) {
|
if (event.keyCode === 13) {
|
||||||
// Executed by "enter" button
|
// Executed by "enter" button
|
||||||
|
|
||||||
// Blocking the search <input> element
|
|
||||||
this.element_search_input.setAttribute(
|
|
||||||
"disabled",
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
this.search_system();
|
this.search_system();
|
||||||
} else if (this.element_search_input.value.length < 3) {
|
} else if (this.element_search_input.value.length < 3) {
|
||||||
|
@ -176,7 +169,7 @@ import("/js/core.js").then(() =>
|
||||||
static search_damper = core.damper(
|
static search_damper = core.damper(
|
||||||
(...variables) => this.search_system(...variables),
|
(...variables) => this.search_system(...variables),
|
||||||
1400,
|
1400,
|
||||||
1,
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -189,11 +182,14 @@ import("/js/core.js").then(() =>
|
||||||
* @todo add animations of errors
|
* @todo add animations of errors
|
||||||
*/
|
*/
|
||||||
static async search_system() {
|
static async search_system() {
|
||||||
|
// Blocking the search <input> element
|
||||||
|
this.element_search_input.setAttribute("disabled", true);
|
||||||
|
|
||||||
// @todo add timeout to unblock
|
// @todo add timeout to unblock
|
||||||
|
|
||||||
// Initialize the buffer of URN parameters
|
// Initialize the buffer of URN parameters
|
||||||
const parameters = new URLSearchParams(
|
const parameters = new URLSearchParams(
|
||||||
window.location.search,
|
window.location.search
|
||||||
);
|
);
|
||||||
|
|
||||||
// Iterate parameters
|
// Iterate parameters
|
||||||
|
@ -254,7 +250,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the title <h2> element before the first element in the <main> element
|
// Writing the title <h2> element before the first element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_title,
|
this.element_title,
|
||||||
first,
|
first
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,16 +289,14 @@ import("/js/core.js").then(() =>
|
||||||
this.element_search.outerHTML = json.search;
|
this.element_search.outerHTML = json.search;
|
||||||
|
|
||||||
// Reinitializing the parameter with the search <search> element
|
// Reinitializing the parameter with the search <search> element
|
||||||
this.element_search = document.getElementById(
|
this.element_search =
|
||||||
"search",
|
document.getElementById("search");
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Not found the search <search> element
|
// Not found the search <search> element
|
||||||
|
|
||||||
// Initialize the search <search> element
|
// Initialize the search <search> element
|
||||||
this.element_search = document.createElement(
|
this.element_search =
|
||||||
"search",
|
document.createElement("search");
|
||||||
);
|
|
||||||
|
|
||||||
if (core.main instanceof HTMLElement) {
|
if (core.main instanceof HTMLElement) {
|
||||||
// Found the <main> element
|
// Found the <main> element
|
||||||
|
@ -313,7 +307,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the search <search> element after the title <h2> element in the <main> element
|
// Writing the search <search> element after the title <h2> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_search,
|
this.element_search,
|
||||||
this.element_title.nextSibling,
|
this.element_title.nextSibling
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Not initialized the title <h2> element in the <main> element
|
// Not initialized the title <h2> element in the <main> element
|
||||||
|
@ -327,7 +321,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the search <search> element before the first element in the <main> element
|
// Writing the search <search> element before the first element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_search,
|
this.element_search,
|
||||||
first,
|
first
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,14 +330,13 @@ import("/js/core.js").then(() =>
|
||||||
this.element_search.outerHTML = json.search;
|
this.element_search.outerHTML = json.search;
|
||||||
|
|
||||||
// Reinitializing the parameter with the search <search> element
|
// Reinitializing the parameter with the search <search> element
|
||||||
this.element_search = document.getElementById(
|
this.element_search =
|
||||||
"search",
|
document.getElementById("search");
|
||||||
);
|
|
||||||
|
|
||||||
// Reinitializing the parameter with the search <input> element
|
// Reinitializing the parameter with the search <input> element
|
||||||
this.element_search_input =
|
this.element_search_input =
|
||||||
this.element_search.getElementsByTagName(
|
this.element_search.getElementsByTagName(
|
||||||
"input",
|
"input"
|
||||||
)[0];
|
)[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,16 +371,14 @@ import("/js/core.js").then(() =>
|
||||||
this.element_categories.outerHTML = json.categories;
|
this.element_categories.outerHTML = json.categories;
|
||||||
|
|
||||||
// Reinitializing the parameter with the categories <section> element
|
// Reinitializing the parameter with the categories <section> element
|
||||||
this.element_categories = document.getElementById(
|
this.element_categories =
|
||||||
"categories",
|
document.getElementById("categories");
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Not found the categories <section> element
|
// Not found the categories <section> element
|
||||||
|
|
||||||
// Initialize the categories <section> element
|
// Initialize the categories <section> element
|
||||||
this.element_categories = document.createElement(
|
this.element_categories =
|
||||||
"section",
|
document.createElement("section");
|
||||||
);
|
|
||||||
|
|
||||||
if (core.main instanceof HTMLElement) {
|
if (core.main instanceof HTMLElement) {
|
||||||
// Found the <main> element
|
// Found the <main> element
|
||||||
|
@ -398,7 +389,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the categories <section> element after the search <search> element in the <main> element
|
// Writing the categories <section> element after the search <search> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_categories,
|
this.element_categories,
|
||||||
this.element_search.nextSibling,
|
this.element_search.nextSibling
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
this.element_title instanceof HTMLElement
|
this.element_title instanceof HTMLElement
|
||||||
|
@ -408,7 +399,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the categories <section> element after the title <h2> element in the <main> element
|
// Writing the categories <section> element after the title <h2> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_categories,
|
this.element_categories,
|
||||||
this.element_title.nextSibling,
|
this.element_title.nextSibling
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Not initialized the title <h2> element in the <main> element
|
// Not initialized the title <h2> element in the <main> element
|
||||||
|
@ -422,7 +413,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the categories <section> before the first element in the <main> element
|
// Writing the categories <section> before the first element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_categories,
|
this.element_categories,
|
||||||
first,
|
first
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -432,9 +423,8 @@ import("/js/core.js").then(() =>
|
||||||
json.categories;
|
json.categories;
|
||||||
|
|
||||||
// Reinitializing the parameter with the categories <section> element
|
// Reinitializing the parameter with the categories <section> element
|
||||||
this.element_categories = document.getElementById(
|
this.element_categories =
|
||||||
"categories",
|
document.getElementById("categories");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -464,16 +454,14 @@ import("/js/core.js").then(() =>
|
||||||
this.element_filters.outerHTML = json.filters;
|
this.element_filters.outerHTML = json.filters;
|
||||||
|
|
||||||
// Reinitializing the parameter with the filters <section> element
|
// Reinitializing the parameter with the filters <section> element
|
||||||
this.element_filters = document.getElementById(
|
this.element_filters =
|
||||||
"filters",
|
document.getElementById("filters");
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Not found the filters <section> element
|
// Not found the filters <section> element
|
||||||
|
|
||||||
// Initialize the filters <section> element
|
// Initialize the filters <section> element
|
||||||
this.element_filters = document.createElement(
|
this.element_filters =
|
||||||
"section",
|
document.createElement("section");
|
||||||
);
|
|
||||||
|
|
||||||
if (core.main instanceof HTMLElement) {
|
if (core.main instanceof HTMLElement) {
|
||||||
// Found the <main> element
|
// Found the <main> element
|
||||||
|
@ -486,7 +474,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the filters <section> element after the categories <section> element in the <main> element
|
// Writing the filters <section> element after the categories <section> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_filters,
|
this.element_filters,
|
||||||
this.element_categories.nextSibling,
|
this.element_categories.nextSibling
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
this.element_search instanceof HTMLElement
|
this.element_search instanceof HTMLElement
|
||||||
|
@ -496,7 +484,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the filters <section> element after the search <search> element in the <main> element
|
// Writing the filters <section> element after the search <search> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_filters,
|
this.element_filters,
|
||||||
this.element_search.nextSibling,
|
this.element_search.nextSibling
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
this.element_title instanceof HTMLElement
|
this.element_title instanceof HTMLElement
|
||||||
|
@ -506,7 +494,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the filters <section> element after the title <h2> element in the <main> element
|
// Writing the filters <section> element after the title <h2> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_filters,
|
this.element_filters,
|
||||||
this.element_title.nextSibling,
|
this.element_title.nextSibling
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Not initialized the title <h2> element in the <main> element
|
// Not initialized the title <h2> element in the <main> element
|
||||||
|
@ -520,7 +508,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the filters <section> before the first element in the <main> element
|
// Writing the filters <section> before the first element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_filters,
|
this.element_filters,
|
||||||
first,
|
first
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -529,9 +517,8 @@ import("/js/core.js").then(() =>
|
||||||
this.element_filters.outerHTML = json.filters;
|
this.element_filters.outerHTML = json.filters;
|
||||||
|
|
||||||
// Reinitializing the parameter with the filters <section> element
|
// Reinitializing the parameter with the filters <section> element
|
||||||
this.element_filters = document.getElementById(
|
this.element_filters =
|
||||||
"filters",
|
document.getElementById("filters");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -561,16 +548,14 @@ import("/js/core.js").then(() =>
|
||||||
this.element_sorting.outerHTML = json.sorting;
|
this.element_sorting.outerHTML = json.sorting;
|
||||||
|
|
||||||
// Reinitializing the parameter with the sorting <section> element
|
// Reinitializing the parameter with the sorting <section> element
|
||||||
this.element_sorting = document.getElementById(
|
this.element_sorting =
|
||||||
"sorting",
|
document.getElementById("sorting");
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Not found the sorting <section> element
|
// Not found the sorting <section> element
|
||||||
|
|
||||||
// Initialize the sorting <section> element
|
// Initialize the sorting <section> element
|
||||||
this.element_sorting = document.createElement(
|
this.element_sorting =
|
||||||
"section",
|
document.createElement("section");
|
||||||
);
|
|
||||||
|
|
||||||
if (core.main instanceof HTMLElement) {
|
if (core.main instanceof HTMLElement) {
|
||||||
// Found the <main> element
|
// Found the <main> element
|
||||||
|
@ -581,7 +566,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the sorting <section> element after the filters <section> element in the <main> element
|
// Writing the sorting <section> element after the filters <section> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_sorting,
|
this.element_sorting,
|
||||||
this.element_filters.nextSibling,
|
this.element_filters.nextSibling
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
this.element_categories instanceof HTMLElement
|
this.element_categories instanceof HTMLElement
|
||||||
|
@ -591,7 +576,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the sorting <section> element after the categories <section> element in the <main> element
|
// Writing the sorting <section> element after the categories <section> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_sorting,
|
this.element_sorting,
|
||||||
this.element_categories.nextSibling,
|
this.element_categories.nextSibling
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
this.element_search instanceof HTMLElement
|
this.element_search instanceof HTMLElement
|
||||||
|
@ -601,7 +586,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the sorting <section> element after the search <search> element in the <main> element
|
// Writing the sorting <section> element after the search <search> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_sorting,
|
this.element_sorting,
|
||||||
this.element_search.nextSibling,
|
this.element_search.nextSibling
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
this.element_title instanceof HTMLElement
|
this.element_title instanceof HTMLElement
|
||||||
|
@ -611,7 +596,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the sorting <section> element after the title <h2> element in the <main> element
|
// Writing the sorting <section> element after the title <h2> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_sorting,
|
this.element_sorting,
|
||||||
this.element_title.nextSibling,
|
this.element_title.nextSibling
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Not initialized the title <h2> element in the <main> element
|
// Not initialized the title <h2> element in the <main> element
|
||||||
|
@ -625,7 +610,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the sorting <section> before the first element in the <main> element
|
// Writing the sorting <section> before the first element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_sorting,
|
this.element_sorting,
|
||||||
first,
|
first
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -634,9 +619,8 @@ import("/js/core.js").then(() =>
|
||||||
this.element_sorting.outerHTML = json.sorting;
|
this.element_sorting.outerHTML = json.sorting;
|
||||||
|
|
||||||
// Reinitializing the parameter with the sorting <section> element
|
// Reinitializing the parameter with the sorting <section> element
|
||||||
this.element_sorting = document.getElementById(
|
this.element_sorting =
|
||||||
"sorting",
|
document.getElementById("sorting");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -666,16 +650,14 @@ import("/js/core.js").then(() =>
|
||||||
this.element_products.outerHTML = json.products;
|
this.element_products.outerHTML = json.products;
|
||||||
|
|
||||||
// Reinitializing the parameter with the products <section> element
|
// Reinitializing the parameter with the products <section> element
|
||||||
this.element_products = document.getElementById(
|
this.element_products =
|
||||||
"products",
|
document.getElementById("products");
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Not found the products <section> element element
|
// Not found the products <section> element element
|
||||||
|
|
||||||
// Initialize the products <section> element
|
// Initialize the products <section> element
|
||||||
this.element_products = document.createElement(
|
this.element_products =
|
||||||
"section",
|
document.createElement("section");
|
||||||
);
|
|
||||||
|
|
||||||
if (core.main instanceof HTMLElement) {
|
if (core.main instanceof HTMLElement) {
|
||||||
// Found the <main> element
|
// Found the <main> element
|
||||||
|
@ -686,7 +668,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the products <section> element after the sorting <section> element in the <main> element
|
// Writing the products <section> element after the sorting <section> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_products,
|
this.element_products,
|
||||||
this.element_sorting.nextSibling,
|
this.element_sorting.nextSibling
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
this.element_filters instanceof HTMLElement
|
this.element_filters instanceof HTMLElement
|
||||||
|
@ -696,7 +678,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the products <section> element after the filters <section> element in the <main> element
|
// Writing the products <section> element after the filters <section> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_products,
|
this.element_products,
|
||||||
this.element_filters.nextSibling,
|
this.element_filters.nextSibling
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
this.element_categories instanceof HTMLElement
|
this.element_categories instanceof HTMLElement
|
||||||
|
@ -706,7 +688,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the products <section> element after the categories <section> element in the <main> element
|
// Writing the products <section> element after the categories <section> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_products,
|
this.element_products,
|
||||||
this.element_categories.nextSibling,
|
this.element_categories.nextSibling
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
this.element_search instanceof HTMLElement
|
this.element_search instanceof HTMLElement
|
||||||
|
@ -716,7 +698,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the products <section> element after the search <search> element in the <main> element
|
// Writing the products <section> element after the search <search> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_products,
|
this.element_products,
|
||||||
this.element_search.nextSibling,
|
this.element_search.nextSibling
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
this.element_title instanceof HTMLElement
|
this.element_title instanceof HTMLElement
|
||||||
|
@ -726,7 +708,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the products <section> element after the title <h2> element in the <main> element
|
// Writing the products <section> element after the title <h2> element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_products,
|
this.element_products,
|
||||||
this.element_title.nextSibling,
|
this.element_title.nextSibling
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Not initialized the title <h2> element in the <main> element
|
// Not initialized the title <h2> element in the <main> element
|
||||||
|
@ -740,7 +722,7 @@ import("/js/core.js").then(() =>
|
||||||
// Writing the products <section> before the first element in the <main> element
|
// Writing the products <section> before the first element in the <main> element
|
||||||
core.main.insertBefore(
|
core.main.insertBefore(
|
||||||
this.element_products,
|
this.element_products,
|
||||||
first,
|
first
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -749,9 +731,8 @@ import("/js/core.js").then(() =>
|
||||||
this.element_products.outerHTML = json.products;
|
this.element_products.outerHTML = json.products;
|
||||||
|
|
||||||
// Reinitializing the parameter with the products <section> element
|
// Reinitializing the parameter with the products <section> element
|
||||||
this.element_products = document.getElementById(
|
this.element_products =
|
||||||
"products",
|
document.getElementById("products");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -780,8 +761,8 @@ import("/js/core.js").then(() =>
|
||||||
*/
|
*/
|
||||||
static product(button, force = false) {
|
static product(button, force = false) {
|
||||||
// Initializing identifier of the category
|
// Initializing identifier of the category
|
||||||
const identifier = button.parentElement.getAttribute(
|
const identifier = button.getAttribute(
|
||||||
"data-product-identifier",
|
"data-product-identifier"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Execute under damper
|
// Execute under damper
|
||||||
|
@ -804,7 +785,7 @@ import("/js/core.js").then(() =>
|
||||||
static product_damper = core.damper(
|
static product_damper = core.damper(
|
||||||
(...variables) => this.product_system(...variables),
|
(...variables) => this.product_system(...variables),
|
||||||
400,
|
400,
|
||||||
1,
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -821,17 +802,12 @@ import("/js/core.js").then(() =>
|
||||||
// Validated identifier
|
// Validated identifier
|
||||||
|
|
||||||
// Initialize the buffer of URN parameters @todo after opening window add to document.location.search
|
// Initialize the buffer of URN parameters @todo after opening window add to document.location.search
|
||||||
const parameters = new URLSearchParams(
|
const parameters = new URLSearchParams();
|
||||||
document.location.search,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Write parameter to the buffer of URN parameters
|
// Write parameter to the buffer of URN parameters
|
||||||
parameters.set("product", identifier);
|
parameters.set("product", identifier);
|
||||||
|
|
||||||
// Intializing URI of the request
|
return await core.request("?" + parameters).then((json) => {
|
||||||
const uri = "?" + parameters;
|
|
||||||
|
|
||||||
return await core.request(uri).then((json) => {
|
|
||||||
if (
|
if (
|
||||||
json.errors !== null &&
|
json.errors !== null &&
|
||||||
typeof json.errors === "object" &&
|
typeof json.errors === "object" &&
|
||||||
|
@ -854,9 +830,6 @@ import("/js/core.js").then(() =>
|
||||||
) {
|
) {
|
||||||
// Received data of the product
|
// Received data of the product
|
||||||
|
|
||||||
// Writing to the browser history
|
|
||||||
history.pushState({}, json.product.name, uri);
|
|
||||||
|
|
||||||
// Deinitializing of the old winow
|
// Deinitializing of the old winow
|
||||||
const old = document.getElementById("window");
|
const old = document.getElementById("window");
|
||||||
if (old instanceof HTMLElement) old.remove();
|
if (old instanceof HTMLElement) old.remove();
|
||||||
|
@ -901,9 +874,11 @@ import("/js/core.js").then(() =>
|
||||||
{
|
{
|
||||||
let x = event.pageX || event.touches[0].pageX;
|
let x = event.pageX || event.touches[0].pageX;
|
||||||
let y = event.pageY || event.touches[0].pageY;
|
let y = event.pageY || event.touches[0].pageY;
|
||||||
let _x = images_from.pageX ||
|
let _x =
|
||||||
|
images_from.pageX ||
|
||||||
images_from.touches[0].pageX;
|
images_from.touches[0].pageX;
|
||||||
let _y = images_from.pageY ||
|
let _y =
|
||||||
|
images_from.pageY ||
|
||||||
images_from.touches[0].pageY;
|
images_from.touches[0].pageY;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -935,10 +910,10 @@ import("/js/core.js").then(() =>
|
||||||
const _close = (event) => {
|
const _close = (event) => {
|
||||||
let x = event.pageX || event.touches[0].pageX;
|
let x = event.pageX || event.touches[0].pageX;
|
||||||
let y = event.pageY || event.touches[0].pageY;
|
let y = event.pageY || event.touches[0].pageY;
|
||||||
let _x = images_from.pageX ||
|
let _x =
|
||||||
images_from.touches[0].pageX;
|
images_from.pageX || images_from.touches[0].pageX;
|
||||||
let _y = images_from.pageY ||
|
let _y =
|
||||||
images_from.touches[0].pageY;
|
images_from.pageY || images_from.touches[0].pageY;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
event.type === "touchstart" ||
|
event.type === "touchstart" ||
|
||||||
|
@ -1044,7 +1019,6 @@ import("/js/core.js").then(() =>
|
||||||
const cost = document.createElement("p");
|
const cost = document.createElement("p");
|
||||||
cost.classList.add("cost");
|
cost.classList.add("cost");
|
||||||
cost.innerText = json.product.cost + "р";
|
cost.innerText = json.product.cost + "р";
|
||||||
console.log(json.product.cost);
|
|
||||||
|
|
||||||
h3.append(name);
|
h3.append(name);
|
||||||
exit.append(exit_icon);
|
exit.append(exit_icon);
|
||||||
|
@ -1063,19 +1037,21 @@ import("/js/core.js").then(() =>
|
||||||
document.body.append(wrap);
|
document.body.append(wrap);
|
||||||
|
|
||||||
// Reinitialize parameter
|
// Reinitialize parameter
|
||||||
core.window = document.getElementById("window");
|
core.window = document.getElementById('window');
|
||||||
|
|
||||||
let width = 0;
|
let width = 0;
|
||||||
let buffer;
|
let buffer;
|
||||||
[...images.children].forEach(
|
[...images.children].forEach(
|
||||||
(child) => (width += child.offsetWidth +
|
(child) =>
|
||||||
|
(width +=
|
||||||
|
child.offsetWidth +
|
||||||
(isNaN(
|
(isNaN(
|
||||||
buffer = parseFloat(
|
(buffer = parseFloat(
|
||||||
getComputedStyle(child).marginRight,
|
getComputedStyle(child).marginRight
|
||||||
),
|
))
|
||||||
)
|
)
|
||||||
? 0
|
? 0
|
||||||
: buffer)),
|
: buffer))
|
||||||
);
|
);
|
||||||
|
|
||||||
// блокировка закрытия карточки
|
// блокировка закрытия карточки
|
||||||
|
@ -1088,18 +1064,17 @@ import("/js/core.js").then(() =>
|
||||||
if (
|
if (
|
||||||
typeof event === "undefined" ||
|
typeof event === "undefined" ||
|
||||||
event.type !== "popstate"
|
event.type !== "popstate"
|
||||||
) {
|
)
|
||||||
history.back();
|
history.back();
|
||||||
}
|
|
||||||
|
|
||||||
wrap.remove();
|
wrap.remove();
|
||||||
images.removeEventListener(
|
images.removeEventListener(
|
||||||
"mousedown",
|
"mousedown",
|
||||||
_images_from,
|
_images_from
|
||||||
);
|
);
|
||||||
images.removeEventListener(
|
images.removeEventListener(
|
||||||
"touchstart",
|
"touchstart",
|
||||||
_images_from,
|
_images_from
|
||||||
);
|
);
|
||||||
wrap.removeEventListener("mousedown", _from);
|
wrap.removeEventListener("mousedown", _from);
|
||||||
wrap.removeEventListener("touchstart", _from);
|
wrap.removeEventListener("touchstart", _from);
|
||||||
|
@ -1135,7 +1110,7 @@ import("/js/core.js").then(() =>
|
||||||
|
|
||||||
images.hotline = new core.hotline(
|
images.hotline = new core.hotline(
|
||||||
json.product.identfier,
|
json.product.identfier,
|
||||||
images,
|
images
|
||||||
);
|
);
|
||||||
images.hotline.step = -0.3;
|
images.hotline.step = -0.3;
|
||||||
images.hotline.wheel = true;
|
images.hotline.wheel = true;
|
||||||
|
|
|
@ -28,8 +28,6 @@ import("/js/core.js").then(() => {
|
||||||
* @param {number} timeout Timer in milliseconds (ms)
|
* @param {number} timeout Timer in milliseconds (ms)
|
||||||
* @param {number} force Argument number storing the status of enforcement execution (see @example)
|
* @param {number} force Argument number storing the status of enforcement execution (see @example)
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
|
||||||
*
|
|
||||||
* @memberof core
|
* @memberof core
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
|
@ -39,13 +37,9 @@ import("/js/core.js").then(() => {
|
||||||
* b, // 1
|
* b, // 1
|
||||||
* c, // 2
|
* c, // 2
|
||||||
* force = false, // 3
|
* force = false, // 3
|
||||||
* d, // 4
|
* d // 4
|
||||||
* resolve,
|
|
||||||
* reject
|
|
||||||
* ) => {
|
* ) => {
|
||||||
* // Body of the function
|
* // Body of function
|
||||||
*
|
|
||||||
* resolve();
|
|
||||||
* },
|
* },
|
||||||
* 500,
|
* 500,
|
||||||
* 3, // 3 -> "force" argument
|
* 3, // 3 -> "force" argument
|
||||||
|
@ -57,39 +51,24 @@ import("/js/core.js").then(() => {
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
*/
|
*/
|
||||||
core.damper = (func, timeout = 300, force) => {
|
core.damper = (func, timeout = 300, force) => {
|
||||||
// Declaring of the timer for executing the function
|
// Initializing of the timer
|
||||||
let timer;
|
let timer;
|
||||||
|
|
||||||
return ((...args) => {
|
return (...args) => {
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// Deinitializing of the timer
|
// Deinitializing of the timer
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
|
|
||||||
if (typeof force === "number" && args[force]) {
|
if (typeof force === "number" && args[force]) {
|
||||||
// Requested execution with ignoring the timer
|
// Force execution (ignoring the timer)
|
||||||
|
|
||||||
// Deleting the force argument
|
|
||||||
if (typeof force === "number") delete args[force - 1];
|
|
||||||
|
|
||||||
// Writing promise handlers into the arguments variable
|
|
||||||
args.push(resolve, reject);
|
|
||||||
|
|
||||||
// Executing the function
|
|
||||||
func.apply(this, args);
|
func.apply(this, args);
|
||||||
} else {
|
} else {
|
||||||
// Normal execution
|
// Normal execution
|
||||||
|
|
||||||
// Deleting the force argument
|
// Execute the handled function (entry into recursion)
|
||||||
if (typeof force === "number") delete args[force - 1];
|
|
||||||
|
|
||||||
// Writing promise handlers into the arguments variable
|
|
||||||
args.push(resolve, reject);
|
|
||||||
|
|
||||||
// Resetting the timer and executing the function when the timer expires
|
|
||||||
timer = setTimeout(() => func.apply(this, args), timeout);
|
timer = setTimeout(() => func.apply(this, args), timeout);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
|
|
||||||
main>section:is(#summary, #products) {
|
|
||||||
width: var(--width);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--gap);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#summary>div {
|
|
||||||
padding-left: 1rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.4rem;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 1.375rem;
|
|
||||||
background-color: var(--tg-theme-secondary-bg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#summary>div>span:first-of-type {
|
|
||||||
/* margin-left: auto; */
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#summary>div>button#order {
|
|
||||||
/* margin-left: 0.3rem; */
|
|
||||||
margin-left: auto;
|
|
||||||
padding-left: 0.7rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 5rem;
|
|
||||||
max-height: 10rem;
|
|
||||||
display: flex;
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
overflow: hidden;
|
|
||||||
background-color: var(--tg-theme-secondary-bg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product[data-product-amount]:not([data-product-amount="0"]) * {
|
|
||||||
backdrop-filter: hue-rotate(calc(120deg + var(--hue-rotate-offset, 0deg)));
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product:is(:hover, :focus)>* {
|
|
||||||
transition: 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product:not(:is(:hover, :focus))>* {
|
|
||||||
transition: 0.2s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>a {
|
|
||||||
display: contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>a>img:first-of-type {
|
|
||||||
width: 5rem;
|
|
||||||
min-width: 5rem;
|
|
||||||
min-height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
image-rendering: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0.5rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.5rem;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div.head {
|
|
||||||
z-index: 50;
|
|
||||||
padding: 0 0.4rem;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div>button:first-of-type {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div>button {
|
|
||||||
padding: 0.4rem;
|
|
||||||
background: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div.head>button+button {
|
|
||||||
margin-left: 0.4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div.head>button>i.icon.trash {
|
|
||||||
color: var(--tg-theme-destructive-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div.body {
|
|
||||||
z-index: 30;
|
|
||||||
flex-grow: 1;
|
|
||||||
display: inline-flex;
|
|
||||||
flex-flow: row wrap;
|
|
||||||
align-items: start;
|
|
||||||
gap: 0.3rem;
|
|
||||||
font-size: 0.6rem;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div.body>span {
|
|
||||||
padding: 0.2rem 0.4rem;
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
color: var(--tg-theme-button-text-color);
|
|
||||||
background-color: var(--tg-theme-button-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div.footer {
|
|
||||||
z-index: 100;
|
|
||||||
padding: 0 0.4rem;
|
|
||||||
display: flex;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div.footer>span[data-product-parameter] {
|
|
||||||
font-size: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div.footer>span[data-product-parameter]+span[data-product-parameter="currency"] {
|
|
||||||
margin-left: 0.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
main>section#products>article.product>div>div.footer>input {
|
|
||||||
width: 2rem;
|
|
||||||
padding: 0 0.3rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
@charset "UTF-8";
|
@charset "UTF-8";
|
||||||
|
|
||||||
main>section#categories {
|
main>section:is(#products, #categories) {
|
||||||
width: var(--width);
|
width: var(--width);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
|
@ -119,7 +119,6 @@ main>section#products>div.column>article.product>a {
|
||||||
main>section#products>div.column>article.product>a>img:first-of-type {
|
main>section#products>div.column>article.product>a>img:first-of-type {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
image-rendering: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main>section#products>div.column>article.product>a>img:first-of-type+* {
|
main>section#products>div.column>article.product>a>img:first-of-type+* {
|
||||||
|
@ -156,12 +155,12 @@ main>section#products>div.column>article.product>div[data-product="buttons"]>but
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
main>section#products>div.column>article.product:is([data-product-amount="0"], [data-product-amount="1"])>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-parameter="amount"],
|
main>section#products>div.column>article.product:is([data-product-amount="0"], [data-product-amount="1"])>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-button-text="amount"],
|
||||||
main>section#products>div.column>article.product[data-product-amount="0"]>div[data-product="buttons"]>button:is([data-product-button="write"], [data-product-button="delete"]) {
|
main>section#products>div.column>article.product[data-product-amount="0"]>div[data-product="buttons"]>button:is([data-product-button="write"], [data-product-button="delete"]) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-parameter="amount"]:after {
|
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-button-text="amount"]:after {
|
||||||
content: '*';
|
content: '*';
|
||||||
margin: 0 0.2rem;
|
margin: 0 0.2rem;
|
||||||
}
|
}
|
||||||
|
@ -171,11 +170,11 @@ main>section#products>div.column>article.product[data-product-amount]:not([data-
|
||||||
}
|
}
|
||||||
|
|
||||||
@container product-buttons (max-width: 200px) {
|
@container product-buttons (max-width: 200px) {
|
||||||
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span:is([data-product-parameter="cost"], [data-product-parameter="currency"]) {
|
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span:is([data-product-button-text="cost"], [data-product-button-text="currency"]) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-parameter="amount"]:after {
|
main>section#products>div.column>article.product>div[data-product="buttons"]>button[data-product-button="toggle"]>span[data-product-button-text="amount"]:after {
|
||||||
content: unset;
|
content: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@charset "UTF-8";
|
@charset "UTF-8";
|
||||||
|
|
||||||
i.icon.arrow.circle {
|
i.icon.arrow.top.left {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -10,27 +10,28 @@ i.icon.arrow.circle {
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.icon.arrow.circle::after,
|
i.icon.arrow.top.left::after,
|
||||||
i.icon.arrow.circle::before {
|
i.icon.arrow.top.left::before {
|
||||||
content: "";
|
content: "";
|
||||||
display: block;
|
display: block;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.icon.arrow.top.left::after {
|
||||||
|
width: 10px;
|
||||||
|
height: 2px;
|
||||||
|
background: currentColor;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
bottom: 8px;
|
||||||
right: 4px;
|
right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.icon.arrow.circle::after {
|
i.icon.arrow.top.left::before {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
|
left: 4px;
|
||||||
|
top: 4px;
|
||||||
border-top: 2px solid;
|
border-top: 2px solid;
|
||||||
border-right: 2px solid;
|
border-left: 2px solid;
|
||||||
transform: rotate(45deg);
|
|
||||||
bottom: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.arrow.circle::before {
|
|
||||||
width: 10px;
|
|
||||||
height: 2px;
|
|
||||||
bottom: 8px;
|
|
||||||
background: currentColor;
|
|
||||||
}
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
|
|
||||||
i.icon.arrow:not(.circle, .square) {
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.arrow:not(.circle, .square)::after,
|
|
||||||
i.icon.arrow:not(.circle, .square)::before {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: absolute;
|
|
||||||
right: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.arrow:not(.circle, .square)::after {
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-top: 2px solid;
|
|
||||||
border-right: 2px solid;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
bottom: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.arrow:not(.circle, .square)::before {
|
|
||||||
width: 16px;
|
|
||||||
height: 2px;
|
|
||||||
bottom: 10px;
|
|
||||||
background: currentColor;
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
|
|
||||||
i.icon.corner {
|
|
||||||
position: relative;
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.corner::after,
|
|
||||||
i.icon.corner::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.corner.left::after,
|
|
||||||
i.icon.corner.left::before {
|
|
||||||
left: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.corner.right::after,
|
|
||||||
i.icon.corner.right::before {
|
|
||||||
right: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.corner::after {
|
|
||||||
bottom: 3px;
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.corner.left::after {
|
|
||||||
border-left: 2px solid;
|
|
||||||
border-bottom: 2px solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.corner.right::after {
|
|
||||||
border-top: 2px solid;
|
|
||||||
border-right: 2px solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.corner::before {
|
|
||||||
bottom: 6px;
|
|
||||||
width: 16px;
|
|
||||||
height: 12px;
|
|
||||||
border-bottom: 2px solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.corner.left::before {
|
|
||||||
border-bottom-right-radius: 4px;
|
|
||||||
border-right: 2px solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.corner.right::before {
|
|
||||||
border-bottom-left-radius: 4px;
|
|
||||||
border-left: 2px solid;
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
|
|
||||||
i.icon.list.add {
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
width: 12px;
|
|
||||||
height: 6px;
|
|
||||||
border-top: 0 solid transparent;
|
|
||||||
border-bottom: 2px solid transparent;
|
|
||||||
box-shadow:
|
|
||||||
inset 0 -2px 0,
|
|
||||||
-2px 4px 0 -2px,
|
|
||||||
0 -2px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.list.add.small {
|
|
||||||
width: 10px;
|
|
||||||
box-shadow:
|
|
||||||
inset 0 -2px 0,
|
|
||||||
-1px 3px 0 -1px,
|
|
||||||
0 -2px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.list.add::after,
|
|
||||||
i.icon.list.add::before {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: absolute;
|
|
||||||
width: 10px;
|
|
||||||
height: 2px;
|
|
||||||
background: currentColor;
|
|
||||||
top: 6px;
|
|
||||||
right: -8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.list.add.small::after,
|
|
||||||
i.icon.list.add.small::before {
|
|
||||||
width: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.list.add::before {
|
|
||||||
width: 2px;
|
|
||||||
height: 10px;
|
|
||||||
top: 2px;
|
|
||||||
right: -4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.list.add.small::before {
|
|
||||||
width: 2px;
|
|
||||||
height: 8px;
|
|
||||||
top: 3px;
|
|
||||||
right: -5px;
|
|
||||||
}
|
|
|
@ -10,6 +10,3 @@ i.icon.minus {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.icon.minus.small {
|
|
||||||
width: 10px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,18 +7,12 @@ i.icon.plus::after {
|
||||||
background: currentColor;
|
background: currentColor;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.icon.plus {
|
i.icon.plus {
|
||||||
margin-top: -2px;
|
margin-top: -2px;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.icon.plus.small {
|
|
||||||
width: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.plus::after {
|
i.icon.plus::after {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -28,8 +22,3 @@ i.icon.plus::after {
|
||||||
left: 7px;
|
left: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.icon.plus.small::after {
|
|
||||||
height: 10px;
|
|
||||||
top: -4px;
|
|
||||||
left: 4px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
|
|
||||||
i.icon.trash {
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
width: 10px;
|
|
||||||
height: 12px;
|
|
||||||
border: 2px solid transparent;
|
|
||||||
box-shadow:
|
|
||||||
0 0 0 2px,
|
|
||||||
inset -2px 0 0,
|
|
||||||
inset 2px 0 0;
|
|
||||||
border-bottom-left-radius: 1px;
|
|
||||||
border-bottom-right-radius: 1px;
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.trash.small {
|
|
||||||
height: 9px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.trash::after,
|
|
||||||
i.icon.trash::before {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.trash::after {
|
|
||||||
background: currentColor;
|
|
||||||
border-radius: 3px;
|
|
||||||
width: 16px;
|
|
||||||
height: 2px;
|
|
||||||
top: -4px;
|
|
||||||
left: -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.icon.trash::before {
|
|
||||||
width: 10px;
|
|
||||||
height: 4px;
|
|
||||||
border: 2px solid;
|
|
||||||
border-bottom: transparent;
|
|
||||||
border-top-left-radius: 2px;
|
|
||||||
border-top-right-radius: 2px;
|
|
||||||
top: -7px;
|
|
||||||
left: -2px;
|
|
||||||
}
|
|
|
@ -8,6 +8,8 @@
|
||||||
--socket-text: #b09999;
|
--socket-text: #b09999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
@ -86,8 +88,6 @@ main>search {
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {}
|
|
||||||
|
|
||||||
search:has(input:is(:focus, :active)) {
|
search:has(input:is(:focus, :active)) {
|
||||||
border-color: var(--tg-theme-accent-text-color);
|
border-color: var(--tg-theme-accent-text-color);
|
||||||
transition: unset;
|
transition: unset;
|
||||||
|
@ -129,8 +129,7 @@ search:has(input:disabled) {
|
||||||
backdrop-filter: contrast(0.5);
|
backdrop-filter: contrast(0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
button,
|
button, *[type="button"] {
|
||||||
*[type="button"] {
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,18 +166,7 @@ h2 {
|
||||||
margin: 1rem 0 0;
|
margin: 1rem 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
footer {}
|
||||||
background: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kabrio {
|
|
||||||
font-family: "Kabrio";
|
|
||||||
}
|
|
||||||
|
|
||||||
.cost.currency:after {
|
|
||||||
content: var(--currency);
|
|
||||||
margin-left: var(--currency-offset, 0.1rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
.unselectable {
|
.unselectable {
|
||||||
-webkit-touch-callout: none;
|
-webkit-touch-callout: none;
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
header>nav#menu {
|
header>nav#menu {
|
||||||
container-type: inline-size;
|
container-type: inline-size;
|
||||||
container-name: menu;
|
container-name: menu;
|
||||||
margin-bottom: 1rem;
|
|
||||||
width: var(--width);
|
width: var(--width);
|
||||||
min-height: 3rem;
|
min-height: 3rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -17,10 +16,8 @@ header>nav#menu>a[type="button"] {
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
padding: unset;
|
padding: unset;
|
||||||
border-radius: 1.375rem;
|
border-radius: 1.375rem;
|
||||||
/* color: var(--unsafe-color, var(--tg-theme-button-text-color));
|
color: var(--unsafe-color, var(--tg-theme-button-text-color));
|
||||||
background-color: var(--unsafe-background-color, var(--tg-theme-button-color)); */
|
background-color: var(--unsafe-background-color, var(--tg-theme-button-color));
|
||||||
color: var(--tg-theme-button-text-color);
|
|
||||||
background-color: var(--tg-theme-button-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
header>nav#menu>a[type=button]>:first-child {
|
header>nav#menu>a[type=button]>:first-child {
|
||||||
|
|
|
@ -89,7 +89,6 @@ section#window>div.card>div.images>img {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
image-rendering: auto;
|
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
transition: 0s;
|
transition: 0s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ final class templater extends controller implements ArrayAccess
|
||||||
if (!empty($account?->status())) $this->twig->addGlobal('account', $account);
|
if (!empty($account?->status())) $this->twig->addGlobal('account', $account);
|
||||||
$this->twig->addGlobal('language', $language = $account?->language ?? $session?->buffer['language'] ?? $settings?->language ?? language::en);
|
$this->twig->addGlobal('language', $language = $account?->language ?? $session?->buffer['language'] ?? $settings?->language ?? language::en);
|
||||||
$this->twig->addGlobal('currency', $currency = $account?->currency ?? $session?->buffer['currency'] ?? $settings?->currency ?? currency::usd);
|
$this->twig->addGlobal('currency', $currency = $account?->currency ?? $session?->buffer['currency'] ?? $settings?->currency ?? currency::usd);
|
||||||
$this->twig->addGlobal('cart', ['summary' => $cart->summary(currency: $currency), 'products' => $cart->products(language: $language, currency: $currency)]);
|
$this->twig->addGlobal('cart', $cart->all(language: $language, currency: $currency));
|
||||||
|
|
||||||
// Initialize function of dimensions formatting
|
// Initialize function of dimensions formatting
|
||||||
$this->twig->addFunction(
|
$this->twig->addFunction(
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
{% if ASDASDASDASDASDASDSD is not empty %}
|
|
||||||
<section id="" class="unselectable">
|
|
||||||
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
|
@ -1,48 +0,0 @@
|
||||||
{% macro card(product, amount) %}
|
|
||||||
<article id="{{ product._id }}" class="product unselectable" data-product-identifier="{{ product.identifier }}"
|
|
||||||
data-product-amount="{{ amount }}" {% if amount> 0 %} style="--hue-rotate-offset: {{ amount }}0deg;"{% endif %}>
|
|
||||||
<a data-product="cover" href="?product={{ product.identifier }}" onclick="return core.catalog.product(this);"
|
|
||||||
onkeydown="event.keyCode === 13 && core.catalog.product(this)" tabindex="10">
|
|
||||||
<img src="{{ product.images.0.storage }}" alt="{{ product.name }}" ondrugstart="return false;">
|
|
||||||
</a>
|
|
||||||
<div>
|
|
||||||
<div class="head" title="{{ product.name }}">
|
|
||||||
{{ product.name | length > 65 ? product.name | slice(0, 65) ~ '...' : product.name }}
|
|
||||||
<!-- <button data-product-button="list" onclick="core.cart.list(this, document.getElementById('{{ product._id }}'))" title="{{ language.name == 'ru' ? 'Добавить в список' : 'Add to a list' }}"><i class="icon small list add"></i></button> -->
|
|
||||||
<button data-product-button="toggle"
|
|
||||||
onclick="core.cart.toggle(this, document.getElementById('{{ product._id }}'), true)"
|
|
||||||
title="{{ language.name == 'ru' ? 'Удалить' : 'Delete' }}"><i class="icon small trash"></i></button>
|
|
||||||
</div>
|
|
||||||
<div class="body">
|
|
||||||
{% for characteristic in [product.brand, format_dimensions(product.dimensions.x,
|
|
||||||
product.dimensions.y, product.dimensions.z, ' '), product.weight ~ (language.name == 'ru' ? 'г' : 'g')] %}
|
|
||||||
{% if characteristic is not empty %}
|
|
||||||
<span>
|
|
||||||
{{ characteristic | length > 30 ? characteristic | slice(0, 30) ~ '...' : characteristic }}
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="footer">
|
|
||||||
<span class="cost currency" data-product-parameter="cost">{{ product.cost }}</span>
|
|
||||||
<button data-product-button="delete"
|
|
||||||
onclick="core.cart.delete(this, document.getElementById('{{ product._id }}'), 1)"
|
|
||||||
title="{{ language.name == 'ru' ? 'Уменьшить' : 'Decrease' }}"><i class="icon small minus"></i></button>
|
|
||||||
<input type="text" value="{{ amount ?? 1 }}" title="{{ language.name == 'ru' ? 'Количество' : 'Amount' }}"
|
|
||||||
data-product-parameter="amount"
|
|
||||||
onchange="core.cart.set(this, document.getElementById('{{ product._id }}'), +this.value)"
|
|
||||||
oninput="this.value = (this.value = +this.value.replaceAll(/[^\d]/g, '')) > 100 ? 100 : (this.value < 0 ? 0 : this.value)"></input>
|
|
||||||
<button data-product-button="write"
|
|
||||||
onclick="core.cart.write(this, document.getElementById('{{ product._id }}'), 1)"
|
|
||||||
title="{{ language.name == 'ru' ? 'Увеличить' : 'Increase' }}"><i class="icon small plus"></i></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
{% endmacro %}
|
|
||||||
{% if cart.products is not empty %}
|
|
||||||
<section id="products" class="unselectable">
|
|
||||||
{% for product in cart.products %}
|
|
||||||
{{ _self.card(product.document, product.amount) }}
|
|
||||||
{% endfor %}
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
|
@ -1,11 +0,0 @@
|
||||||
{% if cart.products is not empty %}
|
|
||||||
<section id="summary" class="unselectable">
|
|
||||||
<div>
|
|
||||||
<span id="amount">{{ cart.summary.amount ?? 0 }}</span>
|
|
||||||
<span>{{ language.name == "ru" ? "товаров на сумму" : "products worth" }}</span>
|
|
||||||
<span id="cost" class="cost currency">{{ cart.summary.cost ?? 0 }}</span>
|
|
||||||
<button id="order" onclick="core.cart.order(this)"
|
|
||||||
title="{{ language.name == 'ru' ? 'Оформить заказ' : 'Place an order' }}"><i class="icon arrow"></i></button>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
|
@ -1,24 +0,0 @@
|
||||||
{% extends "/themes/default/index.html" %}
|
|
||||||
|
|
||||||
{% block css %}
|
|
||||||
{{ parent() }}
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/cart.css" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/trash.css" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/list_add.css" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/shopping_cart.css" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/plus.css" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/minus.css" />
|
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/icons/arrow.css" />
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
<h2 class="unselectable">{{ h2 }}</h2>
|
|
||||||
{% include "/themes/default/cart/elements/summary.html" %}
|
|
||||||
{% include "/themes/default/cart/elements/products.html" %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
{{ parent() }}
|
|
||||||
<script src="/js/cart.js"></script>
|
|
||||||
<script src="/js/hotline.js"></script>
|
|
||||||
{% endblock %}
|
|
|
@ -3,7 +3,7 @@
|
||||||
product.dimensions.y, product.dimensions.z, ' ') ~ ' ' ~ product.weight ~ 'г' %}
|
product.dimensions.y, product.dimensions.z, ' ') ~ ' ' ~ product.weight ~ 'г' %}
|
||||||
{% set amount = cart[product.getId()].amount ?? 0 %}
|
{% set amount = cart[product.getId()].amount ?? 0 %}
|
||||||
<article id="{{ product.getId() }}" class="product unselectable" data-product-identifier="{{ product.identifier }}"
|
<article id="{{ product.getId() }}" class="product unselectable" data-product-identifier="{{ product.identifier }}"
|
||||||
data-product-amount="{{ amount }}"{% if amount > 0 %} style="--hue-rotate-offset: {{ amount }}0deg;"{% endif %}>
|
data-product-amount="{{ amount }}">
|
||||||
<a data-product="cover" href="?product={{ product.identifier }}" onclick="return core.catalog.product(this);"
|
<a data-product="cover" href="?product={{ product.identifier }}" onclick="return core.catalog.product(this);"
|
||||||
onkeydown="event.keyCode === 13 && core.catalog.product(this)" tabindex="10">
|
onkeydown="event.keyCode === 13 && core.catalog.product(this)" tabindex="10">
|
||||||
<img src="{{ product.images.0.storage }}" alt="{{ product.name }}" ondrugstart="return false;">
|
<img src="{{ product.images.0.storage }}" alt="{{ product.name }}" ondrugstart="return false;">
|
||||||
|
@ -11,14 +11,14 @@ product.dimensions.y, product.dimensions.z, ' ') ~ ' ' ~ product.weight ~ 'г' %
|
||||||
{{ title | length > 45 ? title | slice(0, 45) ~ '...' : title }}
|
{{ title | length > 45 ? title | slice(0, 45) ~ '...' : title }}
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
<div data-product="buttons">
|
<div data-product="buttons"{% if amount > 0 %} style="--hue-rotate-offset: {{ amount }}0deg;"{% endif %}>
|
||||||
<button data-product-button="delete" onclick="core.cart.delete(this, document.getElementById('{{ product.getId() }}'), 1)" title="{{ language.name == 'ru' ? 'Уменьшить' : 'Decrease' }}"><i class="icon small minus"></i></button>
|
<button data-product-button="delete" onclick="core.cart.delete(this, 1)"><i class="icon minus"></i></button>
|
||||||
<button data-product-button="toggle" onclick="core.cart.toggle(this, document.getElementById('{{ product.getId() }}'))" tabindex="15">
|
<button data-product-button="toggle" onclick="core.cart.toggle(this)" tabindex="15">
|
||||||
<span data-product-parameter="amount">{{ amount }}</span>
|
<span data-product-button-text="amount">{{ amount }}</span>
|
||||||
<span class="cost currency" data-product-parameter="cost">{{ product.cost }}</span>
|
<span data-product-button-text="cost">{{ product.cost }}</span>
|
||||||
<span data-product-parameter="currency">{{ currency.symbol }}</span>
|
<span data-product-button-text="currency">{{ currency.symbol }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button data-product-button="write" onclick="core.cart.write(this, document.getElementById('{{ product.getId() }}'), 1)" title="{{ language.name == 'ru' ? 'Увеличить' : 'Increase' }}"><i class="icon small plus"></i></button>
|
<button data-product-button="write" onclick="core.cart.write(this, 1)"><i class="icon plus"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
|
@ -16,10 +16,4 @@
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/loading.css" />
|
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/loading.css" />
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/window.css" />
|
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/window.css" />
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/fonts/dejavu.css" />
|
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/fonts/dejavu.css" />
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/{{ theme }}/css/fonts/kabrio.css" />
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--currency: "{{ currency.symbol ?? '$' }}";
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<!-- {{ block('connection_body') }} -->
|
{{ block('connection_body') }}
|
||||||
<!-- {{ block('account_body') }} -->
|
{{ block('account_body') }}
|
||||||
{{ block('header') }}
|
{{ block('header') }}
|
||||||
<main>
|
<main>
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/default/css/menu.css">
|
<link type="text/css" rel="stylesheet" href="/themes/default/css/menu.css">
|
||||||
{% for button in menu %}
|
{% for button in menu %}
|
||||||
{% if button.icon %}
|
{% if button.icon %}
|
||||||
<link type="text/css" rel="stylesheet" href="/themes/default/css/icons/{{ button.icon.class|replace({' ': '_'}) }}.css">
|
<link type="text/css" rel="stylesheet" href="/themes/default/css/icons/{{ button.icon|replace({' ': '-'}) }}.css">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -11,12 +11,10 @@
|
||||||
<nav id="menu">
|
<nav id="menu">
|
||||||
{% for button in menu %}
|
{% for button in menu %}
|
||||||
<a href='{{ button.urn }}' onclick="return core.loader.load('{{ button.urn }}');" type="button" class="unselectable"
|
<a href='{{ button.urn }}' onclick="return core.loader.load('{{ button.urn }}');" type="button" class="unselectable"
|
||||||
title="{{ button.name }}" {% if button.style %}
|
title="{{ button.name }}"
|
||||||
style="{% for parameter, value in button.style %}{{ parameter ~ ': ' ~ value ~ '; ' }}{% endfor %}" {% endif %}">
|
style="order: {{ button.position }};{% for target, color in button.color %} --unsafe-{{ target }}: {{ color|e }};{% endfor %}">
|
||||||
{% if button.icon %}
|
{% if button.icon %}
|
||||||
<i class="icon {{ button.icon.class }}" {% if button.icon.style %}
|
<i class="icon {{ button.icon }}"></i>
|
||||||
style="{% for parameter, value in button.icon.style %}{{ parameter ~ ': ' ~ value ~ '; ' }}{% endfor %}" {% endif
|
|
||||||
%}></i>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span>{{ button.name }}</span>
|
<span>{{ button.name }}</span>
|
||||||
{% if button.image.storage %}
|
{% if button.image.storage %}
|
||||||
|
|
Loading…
Reference in New Issue