fixed many problems + resolved #21

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2024-12-11 19:16:05 +03:00
parent 557eebc91f
commit ae866d8ddb
22 changed files with 2960 additions and 946 deletions

View File

@ -85,6 +85,31 @@ final class cart extends core
'products' => $this->cart?->products(language: $this->language, currency: $this->currency)
];
if (!empty($this->view->cart['products'])) {
// Initialized products
// Declaring buffer of formatted products
$formatted = [];
foreach ($this->view->cart['products'] as $product) {
// Iterating over products
// Formatting products
for ($i = 0; $i < $product['amount']; ++$i) {
$formatted[] = [
'weight' => $product['document']['weight'] ?? 0,
...$product['document']['dimensions']
];
}
}
// Deinitializing unnecessary variables
unset($product);
// Initializing formatted products
$this->view->formatted = $formatted;
}
// Initializing types of avaiabld deliveries
$this->view->deliveries = [
'cdek' => [
@ -319,8 +344,33 @@ final class cart extends core
if ($this->cart instanceof model) {
// Initialized the cart
// Initializing summary data of the cart
$summary = $this->cart?->summary(currency: $this->currency, errors: $this->errors['cart']);
// Initializing products in the cart
$products = $this->cart->products(language: $this->language, currency: $this->currency);
if (!empty($products)) {
// Initialized products
// Initializing summary data of the cart
$summary = $this->cart?->summary(currency: $this->currency, errors: $this->errors['cart']);
// Declaring buffer of formatted products
$formatted = [];
foreach ($products as $product) {
// Iterating over products
// Formatting products
for ($i = 0; $i < $product['amount']; ++$i) {
$formatted[] = [
'weight' => $product['document']['weight'] ?? 0,
...$product['document']['dimensions']
];
}
}
}
// Deinitializing unnecessary variables
unset($product);
// Sending response
$this->response
@ -330,6 +380,7 @@ final class cart extends core
->json([
'cost' => $summary['cost'] ?? 0,
'amount' => $summary['amount'] ?? 0,
'products' => $formatted ?? [],
'errors' => $this->errors
])
->validate($this->request)

View File

@ -148,7 +148,7 @@ final class catalog extends core
$this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: ['catalog_filters_brand' => $brand ?? null]));
// Writing to the current implementator of the buffer
$this->session->buffer = ['catalog' => ['filters' => ['brand' => $brand ?? null]]] + $this->session->buffer ?? [];
$this->session->buffer = ['catalog' => ['filters' => ['brand' => $brand ?? null]]] + ($this->session->buffer ?? []);
// Initialize buffer of filters query (AQL)
$_sort = 'd.position ASC, d.name ASC, d.created DESC';

View File

@ -58,8 +58,9 @@ final class delivery extends core
* Validate and write delivery data to account and session buffers
*
* @param string|null $company Name of delivery company
* @param ?string $location location
* @param ?string $street Address with street and house
* @param string|null $location Location (city)
* @param string|null $street Address (street with house)
* @param string|int|null $type Type or taruff
*
* @return null
*/
@ -68,7 +69,8 @@ final class delivery extends core
string|null $company = null,
/* string|location|null $location = null, */
?string $location = null,
?string $street = null
?string $street = null,
string|int|null $type = null
): null {
if (str_contains($this->request->headers['accept'], content::json->value)) {
// Request for JSON response
@ -102,6 +104,53 @@ final class delivery extends core
// Writing to the buffer of the response
/* $response['company'] = $normalized; */
// Initializing the cart
$this->cart ??= $this->account?->cart() ?? $this->session?->cart();
if ($this->cart instanceof cart) {
// Initialized the cart
// Initializing products in the cart
$products = $this->cart->products(language: $this->language, currency: $this->currency);
// Declaring buffer of formatted products
$formatted = [];
if (!empty($products)) {
// Initialized products
foreach ($products as $product) {
// Iterating over products
// Formatting products
for ($i = 0; $i < $product['amount']; ++$i) {
$formatted[] = [
'weight' => $product['document']['weight'] ?? 0,
...$product['document']['dimensions']
];
}
}
}
// Deinitializing unnecessary variables
unset($product);
// Writing delivery section to the buffer of the response (@todo add check for exists)
$response['delivery'] = [
'html' => $this->view->render('cart/elements/deliveries/' . $normalized . '/section.html'),
'javascript' => match ($normalized) {
'cdek' => [
[
'code' => $this->view->render('cart/elements/deliveries/' . $normalized . '/javascript.html', [
'formatted' => $formatted
])
]
],
default => null
}
];
}
// Initialization buffer of delivery parameters
$delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? [];
@ -174,7 +223,6 @@ final class delivery extends core
$locations = null;
if ($delivery['company'] === 'cdek') {
// Delivery by CDEK
// Searching for locations by name (first part with spaces before first comma or any non word symbol)
$cdek = cdek::location($normalized[0], $this->errors['delivery'])?->items;
@ -250,42 +298,45 @@ final class delivery extends core
// Reinitializating locations from buffer of validated locations by input values
$locations = $buffer;
if (count($locations) === 1) {
// Identificated location
/* if (count($locations) === 1) { */
// Identificated location
// Writing to the session buffer
$this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_location' => $locations[0]]));
// Writing to the session buffer
$this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_location' => $locations[0]]));
// Writing to the account buffer
$this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $locations[0]]));
// Writing to the account buffer
$this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $locations[0]]));
// Deinitializing unnecessary variables
unset($name);
// Deinitializing unnecessary variables
unset($name);
// Writing result value of location name
$result = $locations[0]['name'] . ', ' . implode(', ', array_reverse($locations[0]['structure']));
// Writing result value of location name
$result = $locations[0]['name'] . ', ' . implode(', ', array_reverse($locations[0]['structure']));
// Writing location data to the buffer of the response
/* $response['location'] = [
// Writing location data to the buffer of the response
/* $response['location'] = [
'identifier' => $locations[0]['identifier'],
'input' => $result
]; */
if (!empty($delivery[$delivery['company']]['street'])) {
// Required parameters initialized: company, location, street
// Writing status of execution to the buffer of the response
$response['status'] = 'success';
// Writing readiness status to the buffer of the response
$response['ready'] = true;
if (!empty($delivery[$delivery['company']]['street'])) {
// Required parameters initialized: company, location, street
// Writing to the session buffer
$this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true]));
// Writing readiness status to the buffer of the response
$response['ready'] = true;
// Writing to the account buffer
$this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true]));
// Writing to the session buffer
$this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_ready' => true]));
// Deinitializing unnecessary variables
unset($name);
} else {
// Writing to the account buffer
$this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => true]));
// Deinitializing unnecessary variables
unset($name);
/* } else {
// Not initialized required parameters
// Writing to the session buffer
@ -304,10 +355,7 @@ final class delivery extends core
// Deinitializing unnecessary variables
unset($name_ready, $name_cost, $name_days);
}
// Writing status of execution to the buffer of the response
$response['status'] = 'success';
} */
// Writing locations into response buffer
$response['locations'] = [];
@ -428,7 +476,7 @@ final class delivery extends core
$normalized = '';
// Normalizing street
if (preg_match('/[\w\d\s]+/u', urldecode($street), $matches)) $normalized = mb_ucfirst($matches[0] ?? '');
if (preg_match('/[\w\d\s\.\,]+/u', urldecode($street), $matches)) $normalized = mb_ucfirst($matches[0] ?? '');
// Deinitializing unnecessary variables
unset($matches);
@ -502,6 +550,79 @@ final class delivery extends core
// Deinitializing unnecessary variables
unset($normalized);
}
} else if (isset($type)) {
// Received delivery type
if ((is_string($type) && mb_strlen($type) < 30) || (is_int($type && $type < 10000))) {
// Validated delivery type
// Declating variable for result value of delivery type
$result = '';
// Declating variable for normalized value of delivery type
$normalized = '';
// Normalizing location name
if (preg_match('/[\w\d]+/', trim(urldecode($type)), $matches)) $normalized = $matches[0];
// Deinitializing unnecessary variables
unset($matches);
// Initialization buffer of delivery parameters
$delivery = $this->account?->buffer['delivery'] ?? $this->session?->buffer['delivery'] ?? [];
if (isset($delivery['company'])) {
// Initialized delivery company
if (!empty($normalized)) {
// Normalized delivery type
// Writing to the session buffer
$this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [$name = 'delivery_' . $delivery['company'] . '_type' => $normalized]));
// Writing to the account buffer
$this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [$name => $normalized]));
// Deinitializing unnecessary variables
unset($name);
// Writing result value of delivery type
$result = $normalized;
// Writing status of execution to the buffer of the response
$response['status'] = 'success';
// Deinitializing unnecessary variables
unset($normalized);
} else {
// Value is empty after separating
// Not initialized required parameters
// Writing to the session buffer
$this->core->request(new request('PATCH', '/session/write', protocol::http_3, parameters: [
$name_type = 'delivery_' . $delivery['company'] . '_type' => null,
$name_ready = 'delivery_' . $delivery['company'] . '_ready' => false,
$name_cost = 'delivery_' . $delivery['company'] . '_cost' => null,
$name_days = 'delivery_' . $delivery['company'] . '_days' => null
]));
// Writing to the account buffer
$this->core->request(new request('PATCH', '/account/write', protocol::http_3, parameters: [
$name_type => null,
$name_ready => false,
$name_cost => null,
$name_days => null
]));
// Deinitializing unnecessary variables
unset($name_type, $name_ready, $name_cost, $name_days);
}
}
// Deinitializing unnecessary variables
unset($delivery, $location, $result, $normalized);
}
}
// Sending response
@ -588,8 +709,7 @@ final class delivery extends core
from_street: 'Екатерининская 116', // @todo issues #13
to_location: $delivery[$delivery['company']]['location']['identifier'],
to_street: $delivery[$delivery['company']]['street'],
tariff: 368, // ИМ : warehouse-terminal (склад-постамат)
// tariff: 486, // Обычная доставка : warehouse-terminal (склад-постамат)
tariff: $delivery[$delivery['company']]['type'] ?? 368,
products: $formatted,
date: new datetime(), // @todo weekdays only? + timezones
errors: $this->errors['delivery']
@ -636,12 +756,15 @@ final class delivery extends core
],
'street' => $delivery[$delivery['company']]['street'],
'cost' => $cdek->total_sum,
'days' => $cdek->calendar_max
'days' => $cdek->calendar_max,
'type' => $delivery[$delivery['company']]['type'] ?? 368,
]], $this->errors['buffer']);
// Writing to response buffer
$response['cost'] = $cdek->total_sum;
$response['days'] = $cdek->calendar_max;
$response['longitude'] = $delivery[$delivery['company']]['location']['data']['longitude'];
$response['latitude'] = $delivery[$delivery['company']]['location']['data']['latitude'];
}
}

View File

@ -268,10 +268,12 @@ final class session extends core implements document_interface, collection_inter
<<<'AQL'
FOR d IN @@collection
FILTER d.address == @address && d.expires > @time && d.active == true
SORT d.updated DESC
LIMIT 1
RETURN d
AQL,
[
'@collection' => static::COLLECTION,
'@collection' => static::COLLECTION,
'address' => $address,
'time' => time()
],

View File

@ -0,0 +1,348 @@
<?php
define('SETTINGS', realpath('..' . DIRECTORY_SEPARATOR . 'settings'));
define('CDEK', require(SETTINGS . DIRECTORY_SEPARATOR . 'deliveries' . DIRECTORY_SEPARATOR . 'cdek.php'));
$service = new service(
/**
* Вставьте свой аккаунт\идентификатор для интеграции
* Put your account for integration here
*/
CDEK['account'],
/**
* Вставьте свой пароль для интеграции
* Put your password for integration here
*/
CDEK['secret']
);
$service->process($_GET, file_get_contents('php://input'));
class service
{
/**
* @var string Auth login
*/
private $login;
/**
* @var string Auth pwd
*/
private $secret;
/**
* @var string Base Url for API 2.0 Production
*/
private $baseUrl;
/**
* @var string Auth Token
*/
private $authToken;
/**
* @var array Data From Request
*/
private $requestData;
/** @var array Request metrics */
private $metrics;
public function __construct($login, $secret, $baseUrl = 'https://api.cdek.ru/v2')
{
$this->login = $login;
$this->secret = $secret;
$this->baseUrl = $baseUrl;
$this->metrics = array();
}
public function process($requestData, $body)
{
$time = $this->startMetrics();
$this->requestData = array_merge($requestData, json_decode($body, true) ?: array());
if (!isset($this->requestData['action'])) {
$this->sendValidationError('Action is required');
}
$this->getAuthToken();
switch ($this->requestData['action']) {
case 'offices':
$this->sendResponse($this->getOffices(), $time);
break;
case 'calculate':
$this->sendResponse($this->calculate(), $time);
break;
default:
$this->sendValidationError('Unknown action');
}
}
private function sendValidationError($message)
{
$this->http_response_code(400);
header('Content-Type: application/json');
header('X-Service-Version: 3.11.1');
echo json_encode(array('message' => $message));
exit();
}
private function http_response_code($code)
{
switch ($code) {
case 100:
$text = 'Continue';
break;
case 101:
$text = 'Switching Protocols';
break;
case 200:
$text = 'OK';
break;
case 201:
$text = 'Created';
break;
case 202:
$text = 'Accepted';
break;
case 203:
$text = 'Non-Authoritative Information';
break;
case 204:
$text = 'No Content';
break;
case 205:
$text = 'Reset Content';
break;
case 206:
$text = 'Partial Content';
break;
case 300:
$text = 'Multiple Choices';
break;
case 301:
$text = 'Moved Permanently';
break;
case 302:
$text = 'Moved Temporarily';
break;
case 303:
$text = 'See Other';
break;
case 304:
$text = 'Not Modified';
break;
case 305:
$text = 'Use Proxy';
break;
case 400:
$text = 'Bad Request';
break;
case 401:
$text = 'Unauthorized';
break;
case 402:
$text = 'Payment Required';
break;
case 403:
$text = 'Forbidden';
break;
case 404:
$text = 'Not Found';
break;
case 405:
$text = 'Method Not Allowed';
break;
case 406:
$text = 'Not Acceptable';
break;
case 407:
$text = 'Proxy Authentication Required';
break;
case 408:
$text = 'Request Time-out';
break;
case 409:
$text = 'Conflict';
break;
case 410:
$text = 'Gone';
break;
case 411:
$text = 'Length Required';
break;
case 412:
$text = 'Precondition Failed';
break;
case 413:
$text = 'Request Entity Too Large';
break;
case 414:
$text = 'Request-URI Too Large';
break;
case 415:
$text = 'Unsupported Media Type';
break;
case 500:
$text = 'Internal Server Error';
break;
case 501:
$text = 'Not Implemented';
break;
case 502:
$text = 'Bad Gateway';
break;
case 503:
$text = 'Service Unavailable';
break;
case 504:
$text = 'Gateway Time-out';
break;
case 505:
$text = 'HTTP Version not supported';
break;
default:
exit('Unknown http status code "' . htmlentities($code) . '"');
}
$protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
header($protocol . ' ' . $code . ' ' . $text);
$GLOBALS['http_response_code'] = $code;
}
private function getAuthToken()
{
$time = $this->startMetrics();
$token = $this->httpRequest('oauth/token', array(
'grant_type' => 'client_credentials',
'client_id' => $this->login,
'client_secret' => $this->secret,
), true);
$this->endMetrics('auth', 'Server Auth Time', $time);
$result = json_decode($token['result'], true);
if (!isset($result['access_token'])) {
throw new RuntimeException('Server not authorized to CDEK API');
}
$this->authToken = $result['access_token'];
}
private function startMetrics()
{
return function_exists('hrtime') ? hrtime(true) : microtime(true);
}
private function httpRequest($method, $data, $useFormData = false, $useJson = false)
{
$ch = curl_init("$this->baseUrl/$method");
$headers = array(
'Accept: application/json',
'X-App-Name: widget_pvz',
'X-App-Version: 3.11.1'
);
if ($this->authToken) {
$headers[] = "Authorization: Bearer $this->authToken";
}
if ($useFormData) {
curl_setopt_array($ch, array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $data,
));
} elseif ($useJson) {
$headers[] = 'Content-Type: application/json';
curl_setopt_array($ch, array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
));
} else {
curl_setopt($ch, CURLOPT_URL, "$this->baseUrl/$method?" . http_build_query($data));
}
curl_setopt_array($ch, array(
CURLOPT_USERAGENT => 'widget/3.11.1',
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
));
$response = curl_exec($ch);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $headerSize);
$result = substr($response, $headerSize);
$addedHeaders = $this->getHeaderValue($headers);
if ($result === false) {
throw new RuntimeException(curl_error($ch), curl_errno($ch));
}
return array('result' => $result, 'addedHeaders' => $addedHeaders);
}
private function getHeaderValue($headers)
{
$headerLines = explode("\r\n", $headers);
return array_filter($headerLines, static function ($line) {
return !empty($line) && stripos($line, 'X-') !== false;
});
}
private function endMetrics($metricName, $metricDescription, $start)
{
$this->metrics[] = array(
'name' => $metricName,
'description' => $metricDescription,
'time' => round(
function_exists('hrtime') ? (hrtime(true) - $start) / 1e+6 : (microtime(true) - $start) * 1000,
2
),
);
}
private function sendResponse($data, $start)
{
$this->http_response_code(200);
header('Content-Type: application/json');
header('X-Service-Version: 3.11.1');
if (!empty($data['addedHeaders'])) {
foreach ($data['addedHeaders'] as $header) {
header($header);
}
}
$this->endMetrics('total', 'Total Time', $start);
if (!empty($this->metrics)) {
header('Server-Timing: ' . array_reduce($this->metrics, function ($c, $i) {
return $c . $i['name'] . ';desc="' . $i['description'] . '";dur=' . $i['time'] . ',';
}, ''));
}
echo $data['result'];
exit();
}
protected function getOffices()
{
$time = $this->startMetrics();
$result = $this->httpRequest('deliverypoints', $this->requestData);
$this->endMetrics('office', 'Offices Request', $time);
return $result;
}
protected function calculate()
{
$time = $this->startMetrics();
$result = $this->httpRequest('calculator/tarifflist', $this->requestData, false, true);
$this->endMetrics('calc', 'Calculate Request', $time);
return $result;
}
}

View File

@ -799,6 +799,15 @@ Object.assign(
cost.innerText = json.cost;
}
// Dispatching event
document.dispatchEvent(
new CustomEvent("core.cart.summary.received", {
detail: {
json,
},
}),
);
// Exit (success)
resolve(json);
}

View File

@ -329,6 +329,7 @@ Object.assign(
exit_icon.classList.add("icon", "close");
const images = document.createElement("div");
images.setAttribute("id", "images");
images.classList.add("images", "unselectable");
for (
@ -350,7 +351,8 @@ Object.assign(
let width = 0;
let buffer;
[...images.children].forEach(
(child) => (width += child.offsetWidth +
// 150px instead of child.offsetWidth by min-width in window.css
(child) => (width += 150 +
(isNaN(
buffer = parseFloat(
getComputedStyle(child).marginRight,
@ -368,66 +370,84 @@ Object.assign(
images.addEventListener("mousedown", _images_from);
images.addEventListener("touchstart", _images_from);
let touches;
images.addEventListener('touchmove', (move) => {
touches = move.touches;
});
const _open = (event) => {
if (
event.type === "touchstart" ||
event.button === 0
) {
{
const x = event.pageX || event.touches[0].pageX;
const y = event.pageY || event.touches[0].pageY;
const _x = images_from.pageX ||
images_from.touches[0].pageX;
const _y = images_from.pageY ||
images_from.touches[0].pageY;
const x = event.pageX ||
(event.touches && event.touches[0]?.pageX) || 0;
const y = event.pageY ||
(event.touches && event.touches[0]?.pageY) || 0;
const _x = images_from.pageX ||
(images_from.touches &&
images_from.touches[0]?.pageX) ||
0;
const _y = images_from.pageY ||
(images_from.touches &&
images_from.touches[0]?.pageY) ||
0;
if (
_x - x < 10 &&
_x - x > -10 &&
_y - y < 10 &&
_y - y > -10
) {
// Replacing small images with big images
Array.from(images.children).forEach((image) =>
image.setAttribute(
"src",
image.getAttribute("data-image-big"),
)
);
if (
_x - x < 10 &&
_x - x > -10 &&
_y - y < 10 &&
_y - y > -10
) {
// Replacing small images with big images
Array.from(images.children).forEach((image) =>
image.setAttribute(
"src",
image.getAttribute("data-image-big"),
)
);
// Expanding the "Web App" window
core.telegram.api.expand();
// Expanding the "Web App" window
core.telegram.api.expand();
core.telegram.api.disableVerticalSwipes();
images.classList.add("extend");
images.classList.add("extend");
if (button) {
core.telegram.api.MainButton.hide();
}
setTimeout(() => {
images.hotline.step = 0;
images.hotline.wheel = false;
images.hotline.start();
images.addEventListener("mouseup", _close);
images.addEventListener("touchend", _close);
}, 300);
images.removeEventListener("mouseup", _open);
images.removeEventListener("touchend", _open);
if (button) {
core.telegram.api.MainButton.hide();
}
setTimeout(() => {
images.hotline.alive = false;
images.hotline.movable = false;
images.hotline.restart();
images.addEventListener("mouseup", _close);
images.addEventListener("touchend", _close);
}, 300);
images.removeEventListener("mouseup", _open);
images.removeEventListener("touchend", _open);
}
}
};
const _close = (event) => {
const x = event.pageX || event.touches[0].pageX;
const y = event.pageY || event.touches[0].pageY;
console.log(event)
const x = event.pageX ||
(touches && touches[0]?.pageX) || 0;
const y = event.pageY ||
(touches && touches[0]?.pageY) || 0;
const _x = images_from.pageX ||
images_from.touches[0].pageX;
(images_from.touches &&
images_from.touches[0]?.pageX) ||
0;
const _y = images_from.pageY ||
images_from.touches[0].pageY;
(images_from.touches &&
images_from.touches[0]?.pageY) ||
0;
if (
event.type === "touchstart" ||
event.type === "touchend" ||
event.button === 0
) {
if (
@ -440,8 +460,11 @@ Object.assign(
// (в идеале надо переделать на таймер 2 секунды есди зажата кнопка то ничего не делать а просто двигать)
// пох абсолютно сейчас заказчик слишком охуевший для этого
images.hotline.step = -0.3;
images.hotline.movable = true;
images.hotline.alive = true;
images.hotline.step = -1;
images.hotline.wheel = true;
images.hotline.restart();
if (width < card.offsetWidth) {
images.hotline.stop();
@ -457,6 +480,9 @@ Object.assign(
images.classList.remove("extend");
core.telegram.api.enableVerticalSwipes();
if (button) {
core.telegram.api.MainButton.show();
}
@ -465,10 +491,30 @@ Object.assign(
images.removeEventListener("touchend", _close);
images.addEventListener("mousedown", _start);
images.addEventListener("touchstart", _start);
} else {
// Курсор был сдвинут более чем на 10 пикселей
if (x > _x) images.hotline.forward();
else images.hotline.backward();
}
}
};
const _start = (event) => {
if (
event.type === "touchstart" ||
event.button === 0
) {
images.removeEventListener("mousedown", _start);
images.removeEventListener("touchstart", _start);
images.addEventListener("mouseup", _open);
images.addEventListener("touchend", _open);
}
};
images.addEventListener("mousedown", _start);
images.addEventListener("touchstart", _start);
const header = document.createElement("p");
header.classList.add("header");
@ -610,7 +656,6 @@ Object.assign(
wrap.addEventListener("touchstart", _from);
const remove = (event) => {
console.log("BABLO: " + typeof event);
if (
typeof event === "undefined" ||
event.type !== "popstate"
@ -625,8 +670,6 @@ Object.assign(
if (parameters.get("product") === identifier) {
// The previous window with the product card was exactly the same
console.log("aboba");
// Deleting product card
parameters.delete("product");
@ -698,38 +741,26 @@ Object.assign(
core.telegram.api.BackButton.show();
core.telegram.api.BackButton.onClick(remove);
setTimeout(() => {
import("./hotline.js").then((hotline) => {
// Imported the hotline module
// setTimeout(() => {
import("./hotline.mjs").then((hotline) => {
// Imported the hotline module
images.hotline = new hotline.default(
images,
);
images.hotline.step = -1;
images.hotline.interval = 20;
images.hotline.wheel = true;
images.hotline.touch = true;
images.hotline.events.set("transfer.beginning", true);
images.hotline.events.set("transfer.end", true);
images.hotline.events.set("moved.forward", true);
images.hotline.events.set("moved.backward", true);
const _start = (event) => {
if (
event.type === "touchstart" ||
event.button === 0
) {
images.removeEventListener("mousedown", _start);
images.removeEventListener("touchstart", _start);
images.addEventListener("mouseup", _open);
images.addEventListener("touchend", _open);
}
};
images.addEventListener("mousedown", _start);
images.addEventListener("touchstart", _start);
images.hotline = new hotline.default(
json.product.identfier,
images,
);
images.hotline.step = -0.3;
images.hotline.wheel = true;
images.hotline.touch = true;
if (width > card.offsetWidth) {
images.hotline.start();
}
});
}, 300);
if (width > card.offsetWidth) {
images.hotline.start();
}
});
// }, 300);
}
});

View File

@ -49,7 +49,7 @@ export default function damper(func, timeout = 300, force) {
// Requested execution with ignoring the timer
// Deleting the force argument
if (typeof force === "number") delete args[force - 1];
if (typeof force === "number") args.splice(force - 1, force);
// Writing promise handlers into the arguments variable
args.push(resolve, reject);

View File

@ -93,7 +93,7 @@ export default class delivery {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.add("deleted");
request.classList.add("hidden");
}
} else {
// Not received readiness status or readiness status is false
@ -102,7 +102,7 @@ export default class delivery {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.remove("deleted");
request.classList.remove("hidden");
}
}
@ -122,6 +122,100 @@ export default class delivery {
button.checked = true;
}
}
if (json.delivery) {
// Received delivery HTML-code
core.modules.connect(["telegram"])
.then(() => {
//
core.telegram.api.LocationManager.init(() => {
//if (core.telegram.api.LocationManager.isAccessRequested && !core.telegram.api.LocationManager.isAccessGranted) {
// alert('Предоставьте разрешение на доступ к геопозиции');
// core.telegram.api.LocationManager.openSettings();
//}
if (!core.telegram.api.LocationManager.isLocationAvailable) {
// Dispatching event
document.dispatchEvent(
new CustomEvent("core.telegram.api.location.rejected"),
);
} else {
core.telegram.api.LocationManager.getLocation(
(location) => {
// Dispatching event
document.dispatchEvent(
new CustomEvent(
"core.telegram.api.location.received",
{
detail: {
location,
},
},
),
);
},
);
}
});
});
// Initializing the deliveries <div> element
const deliveries = document.getElementById("deliveries");
if (deliveries instanceof HTMLElement) {
// Initialized the deliveries <div> element
// Initializing the deliveries <section> element
let section = deliveries.nextElementSibling;
if (section instanceof HTMLElement) {
// Initialized the deliveries <section> element
// Deinitializing the delivery <section> element
section.remove();
}
// Creating the delivery <section> element
section = document.createElement("section");
// Writing the delivery <section> element after the delivery <div> element
deliveries.parentElement.insertBefore(
section,
deliveries.nextElementSibling,
);
// Reinitializing the delivery <section> element
section.outerHTML = json.delivery.html;
// Reinitializing the deliveries <section> element
section = deliveries.nextElementSibling;
for (const javascript of json.delivery.javascript) {
// Received delivery JavaScript-code and delivery JavaScript-links
// Initializing the delivery JavaScript-code <script> element
const script = document.createElement("script");
script.setAttribute("defer", "true");
if (javascript.link) {
// Initializing the delivery JavaScript-link <script> element attributes
script.setAttribute("type", "text/javascript");
script.setAttribute("src", javascript.link);
script.setAttribute("charset", 'charset="utf-8');
} else if (javascript.code) {
// Delivery JavaScript-code
// Initializing the delivery JavaScript-code <script> element value
script.innerHTML = javascript.code;
}
// Writing the delivery JavaScript-code <script> element and executing the delivery JavaScript-code
section.appendChild(script);
}
}
}
}
};
@ -241,7 +335,7 @@ export default class delivery {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.add("deleted");
request.classList.add("hidden");
}
} else {
// Not received readiness status or readiness status is false
@ -250,7 +344,7 @@ export default class delivery {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.remove("deleted");
request.classList.remove("hidden");
}
}
@ -468,7 +562,7 @@ export default class delivery {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.add("deleted");
request.classList.add("hidden");
}
core.modules.connect("telegram").then(() => {
@ -483,7 +577,7 @@ export default class delivery {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.remove("deleted");
request.classList.remove("hidden");
}
}
@ -937,6 +1031,15 @@ Object.assign(
document.getElementById("shipping")?.remove();
}
// Dispatching event
document.dispatchEvent(
new CustomEvent("core.delivery.calculated", {
detail: {
json,
},
}),
);
// Exit (success)
resolve(json);
}

View File

@ -1,750 +0,0 @@
"use strict";
/**
* @name Бегущая строка
*
* @description
* Простой, но мощный класс для создания бегущих строк. Поддерживает
* перемещение мышью и прокрутку колесом, полностью настраивается очень гибок
* для настроек в CSS и подразумевается, что отлично индексируется поисковыми роботами.
* Имеет свой препроцессор, благодаря которому можно создавать бегущие строки
* без программирования - с помощью HTML-аттрибутов, а так же возможность
* изменять параметры (data-hotline-* аттрибуты) на лету. Есть возможность вызывать
* события при выбранных действиях для того, чтобы пользователь имел возможность
* дорабатывать функционал без изучения и изменения моего кода
*
* @example
* сonst hotline = new hotline();
* hotline.step = '-5';
* hotline.start();
*
* @todo
* 1. Бесконечный режим - элементы не удаляются если видны на экране (будут дубликаты).
* Сейчас при БЫСТРОМ прокручивании можно заметит как элементы "появляются" в начале и конце строки.
* 2. "gap" and "padding" in wrap should be removed! or added here to the calculations
*
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
export default class hotline {
// Идентификатор
#id = 0;
// Оболочка (instanceof HTMLElement)
#shell = document.getElementById("hotline");
// Инстанция горячей строки
#instance = null;
// Перемещение
#transfer = true;
// Движение
#move = true;
// Наблюдатель
#observer = null;
// Реестр запрещённых к изменению параметров
#block = new Set(["events"]);
// Status (null, active, inactive)
#status = null;
// Настраиваемые параметры
transfer = null;
move = null;
delay = 10;
step = 1;
hover = true;
movable = true;
sticky = false;
wheel = false;
delta = null;
vertical = false;
button = 0; // button for grabbing. 0 is main mouse button (left)
observe = false;
events = new Map([
["start", false],
["stop", false],
["move", false],
["move.block", false],
["move.unblock", false],
["offset", false],
["transfer.start", true],
["transfer.end", true],
["mousemove", false],
["touchmove", false],
]);
// Is hotline currently moving due to "onmousemove" or "ontouchmove"?
moving = false;
constructor(id, shell) {
// Запись идентификатора
if (typeof id === "string" || typeof id === "number") this.#id = id;
// Запись оболочки
if (shell instanceof HTMLElement) this.#shell = shell;
}
start() {
if (this.#instance === null) {
// Нет запущенной инстанции бегущей строки
// Инициализация ссылки на ядро
const _this = this;
// Запуск движения
this.#instance = setInterval(function () {
if (_this.#shell.childElementCount > 1) {
// Найдено содержимое бегущей строки (2 и более)
// Инициализация буфера для временных данных
let buffer;
// Инициализация данных первого элемента в строке
const first = {
element: (buffer = _this.#shell.firstElementChild),
coords: buffer.getBoundingClientRect(),
};
if (_this.vertical) {
// Вертикальная бегущая строка
// Инициализация сдвига у первого элемента (движение)
first.offset = isNaN(
buffer = parseFloat(first.element.style.marginTop),
)
? 0
: buffer;
// Инициализация отступа до второго элемента у первого элемента (разделение)
first.separator = isNaN(
buffer = parseFloat(
getComputedStyle(first.element).marginBottom,
),
)
? 0
: buffer;
// Инициализация крайнего с конца ребра первого элемента в строке
first.end = first.coords.y + first.coords.height +
first.separator;
} else {
// Горизонтальная бегущая строка
// Инициализация отступа у первого элемента (движение)
first.offset = isNaN(
buffer = parseFloat(first.element.style.marginLeft),
)
? 0
: buffer;
// Инициализация отступа до второго элемента у первого элемента (разделение)
first.separator = isNaN(
buffer = parseFloat(
getComputedStyle(first.element).marginRight,
),
)
? 0
: buffer;
// Инициализация крайнего с конца ребра первого элемента в строке
first.end = first.coords.x + first.coords.width +
first.separator;
}
if (
(_this.vertical &&
Math.round(first.end) < _this.#shell.offsetTop) ||
(!_this.vertical &&
Math.round(first.end) < _this.#shell.offsetLeft)
) {
// Элемент (вместе с отступом до второго элемента) вышел из области видимости (строки)
if (
(_this.transfer === null && _this.#transfer) ||
_this.transfer === true
) {
// Перенос разрешен
if (_this.vertical) {
// Вертикальная бегущая строка
// Удаление отступов (движения)
first.element.style.marginTop = null;
} else {
// Горизонтальная бегущая строка
// Удаление отступов (движения)
first.element.style.marginLeft = null;
}
// Копирование первого элемента в конец строки
_this.#shell.appendChild(first.element);
if (_this.events.get("transfer.end")) {
// Запрошен вызов события: "перемещение в конец"
// Вызов события: "перемещение в конец"
document.dispatchEvent(
new CustomEvent(`hotline.${_this.#id}.transfer.end`, {
detail: {
element: first.element,
offset: -(
(_this.vertical
? first.coords.height
: first.coords.width) + first.separator
),
},
}),
);
}
}
} else if (
(_this.vertical &&
Math.round(first.coords.y) > _this.#shell.offsetTop) ||
(!_this.vertical &&
Math.round(first.coords.x) > _this.#shell.offsetLeft)
) {
// Передняя (движущая) граница первого элемента вышла из области видимости
if (
(_this.transfer === null && _this.#transfer) ||
_this.transfer === true
) {
// Перенос разрешен
// Инициализация отступа у последнего элемента (разделение)
const separator = (buffer = isNaN(
buffer = parseFloat(
getComputedStyle(_this.#shell.lastElementChild)[
_this.vertical ? "marginBottom" : "marginRight"
],
),
)
? 0
: buffer) === 0
? first.separator
: buffer;
// Инициализация координат первого элемента в строке
const coords = _this.#shell.lastElementChild
.getBoundingClientRect();
if (_this.vertical) {
// Вертикальная бегущая строка
// Удаление отступов (движения)
_this.#shell.lastElementChild.style.marginTop = -coords.height -
separator + "px";
} else {
// Горизонтальная бегущая строка
// Удаление отступов (движения)
_this.#shell.lastElementChild.style.marginLeft = -coords.width -
separator + "px";
}
// Копирование последнего элемента в начало строки
_this.#shell.insertBefore(
_this.#shell.lastElementChild,
first.element,
);
// Удаление отступов у второго элемента в строке (движения)
_this.#shell.children[1].style[
_this.vertical ? "marginTop" : "marginLeft"
] = null;
if (_this.events.get("transfer.start")) {
// Запрошен вызов события: "перемещение в начало"
// Вызов события: "перемещение в начало"
document.dispatchEvent(
new CustomEvent(`hotline.${_this.#id}.transfer.start`, {
detail: {
element: _this.#shell.lastElementChild,
offset: (_this.vertical ? coords.height : coords.width) +
separator,
},
}),
);
}
}
} else {
// Элемент в области видимости
if (
(_this.move === null && _this.#move) || _this.move === true
) {
// Движение разрешено
// Запись новых координат сдвига
const offset = first.offset + _this.step;
// Запись сдвига (движение)
_this.offset(offset);
if (_this.events.get("move")) {
// Запрошен вызов события: "движение"
// Вызов события: "движение"
document.dispatchEvent(
new CustomEvent(`hotline.${_this.#id}.move`, {
detail: {
from: first.offset,
to: offset,
},
}),
);
}
}
}
}
}, _this.delay);
if (this.hover) {
// Запрошена возможность останавливать бегущую строку
// Инициализация сдвига
let offset = 0;
// Инициализация слушателя события при перемещении элемента в бегущей строке
const listener = function (e) {
// Увеличение сдвига
offset += e.detail.offset ?? 0;
};
// Объявление переменной в области видимости обработки остановки бегущей строки
let move;
// Инициализация обработчика наведения курсора (остановка движения)
this.#shell.onmouseover = function (e) {
// Курсор наведён на бегущую строку
// Блокировка движения
_this.#move = false;
if (_this.events.get("move.block")) {
// Запрошен вызов события: "блокировка движения"
// Вызов события: "блокировка движения"
document.dispatchEvent(
new CustomEvent(`hotline.${_this.#id}.move.block`),
);
}
};
if (this.movable) {
// Запрошена возможность двигать бегущую строку
_this.#shell.onmousedown =
_this.#shell.ontouchstart =
function (
start,
) {
// Handling a "mousedown" and a "touchstart" on hotline
if (
start.type === "touchstart" ||
start.button === _this.button
) {
const x = start.pageX || start.touches[0].pageX;
const y = start.pageY || start.touches[0].pageY;
// Блокировка движения
_this.#move = false;
if (_this.events.get("move.block")) {
// Запрошен вызов события: "блокировка движения"
// Вызов события: "блокировка движения"
document.dispatchEvent(
new CustomEvent(`hotline.${_this.#id}.move.block`),
);
}
// Инициализация слушателей события перемещения элемента в бегущей строке
document.addEventListener(
`hotline.${_this.#id}.transfer.start`,
listener,
);
document.addEventListener(
`hotline.${_this.#id}.transfer.end`,
listener,
);
// Инициализация буфера для временных данных
let buffer;
// Инициализация данных первого элемента в строке
const first = {
offset: isNaN(
buffer = parseFloat(
_this.vertical
? _this.#shell.firstElementChild.style
.marginTop
: _this.#shell.firstElementChild.style
.marginLeft,
),
)
? 0
: buffer,
};
move = (move) => {
// Обработка движения курсора
if (_this.#status === "active") {
// Запись статуса ручного перемещения
_this.moving = true;
const _x = move.pageX || move.touches[0].pageX;
const _y = move.pageY || move.touches[0].pageY;
if (_this.vertical) {
// Вертикальная бегущая строка
// Инициализация буфера местоположения
const from =
_this.#shell.firstElementChild.style.marginTop;
const to = _y - (y + offset - first.offset);
// Движение
_this.#shell.firstElementChild.style.marginTop = to +
"px";
} else {
// Горизонтальная бегущая строка
// Инициализация буфера местоположения
const from =
_this.#shell.firstElementChild.style.marginLeft;
const to = _x - (x + offset - first.offset);
// Движение
_this.#shell.firstElementChild.style.marginLeft = to +
"px";
}
if (_this.events.get(move.type)) {
// Запрошен вызов события: "перемещение" (мышью или касанием)
// Вызов события: "перемещение" (мышью или касанием)
document.dispatchEvent(
new CustomEvent(
`hotline.${_this.#id}.${move.type}`,
{
detail: { from, to },
},
),
);
}
// Запись курсора
_this.#shell.style.cursor = "grabbing";
}
};
// Запуск обработки движения
document.addEventListener("mousemove", move);
document.addEventListener("touchmove", move);
}
};
// Перещапись событий браузера (чтобы не дёргалось)
_this.#shell.ondragstart = null;
_this.#shell.onmouseup = _this.#shell.ontouchend = function () {
// Курсор деактивирован
// Запись статуса ручного перемещения
_this.moving = false;
// Остановка обработки движения
document.removeEventListener("mousemove", move);
document.removeEventListener("touchmove", move);
// Сброс сдвига
offset = 0;
document.removeEventListener(
`hotline.${_this.#id}.transfer.start`,
listener,
);
document.removeEventListener(
`hotline.${_this.#id}.transfer.end`,
listener,
);
// Разблокировка движения
_this.#move = true;
if (_this.events.get("move.unblock")) {
// Запрошен вызов события: "разблокировка движения"
// Вызов события: "разблокировка движения"
document.dispatchEvent(
new CustomEvent(`hotline.${_this.#id}.move.unblock`),
);
}
// Восстановление курсора
_this.#shell.style.cursor = null;
};
}
// Инициализация обработчика отведения курсора (остановка движения)
this.#shell.onmouseleave = function (onmouseleave) {
// Курсор отведён от бегущей строки
if (!_this.sticky) {
// Отключено прилипание
// Запись статуса ручного перемещения
_this.moving = false;
// Остановка обработки движения
document.removeEventListener("mousemove", move);
document.removeEventListener("touchmove", move);
document.removeEventListener(
`hotline.${_this.#id}.transfer.start`,
listener,
);
document.removeEventListener(
`hotline.${_this.#id}.transfer.end`,
listener,
);
// Восстановление курсора
_this.#shell.style.cursor = null;
}
// Сброс сдвига
offset = 0;
// Разблокировка движения
_this.#move = true;
if (_this.events.get("move.unblock")) {
// Запрошен вызов события: "разблокировка движения"
// Вызов события: "разблокировка движения"
document.dispatchEvent(
new CustomEvent(`hotline.${_this.#id}.move.unblock`),
);
}
};
}
if (this.wheel) {
// Запрошена возможность прокручивать колесом мыши
// Инициализация обработчика наведения курсора (остановка движения)
this.#shell.onwheel = function (e) {
// Курсор наведён на бегущую
// Инициализация буфера для временных данных
let buffer;
// Перемещение
_this.offset(
(isNaN(
buffer = parseFloat(
_this.#shell.firstElementChild.style[
_this.vertical ? "marginTop" : "marginLeft"
],
),
)
? 0
: buffer) +
(_this.delta === null
? e.wheelDelta
: e.wheelDelta > 0
? _this.delta
: -_this.delta),
);
};
}
this.#status = "active";
}
if (this.observe) {
// Запрошено наблюдение за изменениями аттрибутов элемента бегущей строки
if (this.#observer === null) {
// Отсутствует наблюдатель
// Инициализация ссылки на ядро
const _this = this;
// Инициализация наблюдателя
this.#observer = new MutationObserver(function (mutations) {
for (const mutation of mutations) {
if (mutation.type === "attributes") {
// Запись параметра в инстанцию бегущей строки
_this.configure(mutation.attributeName);
}
}
// Перезапуск бегущей строки
_this.restart();
});
// Активация наблюдения
this.#observer.observe(this.#shell, {
attributes: true,
});
}
} else if (this.#observer instanceof MutationObserver) {
// Запрошено отключение наблюдения
// Деактивация наблюдения
this.#observer.disconnect();
// Удаление наблюдателя
this.#observer = null;
}
if (this.events.get("start")) {
// Запрошен вызов события: "запуск"
// Вызов события: "запуск"
document.dispatchEvent(
new CustomEvent(`hotline.${this.#id}.start`),
);
}
return this;
}
stop() {
this.#status = "inactive";
// Остановка бегущей строки
clearInterval(this.#instance);
// Удаление инстанции интервала
this.#instance = null;
if (this.events.get("stop")) {
// Запрошен вызов события: "остановка"
// Вызов события: "остановка"
document.dispatchEvent(new CustomEvent(`hotline.${this.#id}.stop`));
}
return this;
}
restart() {
// Остановка бегущей строки
this.stop();
// Запуск бегущей строки
this.start();
}
configure(attribute) {
// Инициализация названия параметра
const parameter = (/^data-hotline-(\w+)$/.exec(attribute) ?? [, null])[1];
if (typeof parameter === "string") {
// Параметр найден
// Проверка на разрешение изменения
if (this.#block.has(parameter)) return;
// Инициализация значения параметра
const value = this.#shell.getAttribute(attribute);
if (typeof value !== undefined || typeof value !== null) {
// Найдено значение
// Инициализация буфера для временных данных
let buffer;
// Запись параметра
this[parameter] = isNaN(buffer = parseFloat(value))
? value === "true" ? true : value === "false" ? false : value
: buffer;
}
}
return this;
}
offset(value) {
// Запись отступа
this.#shell.firstElementChild.style[
this.vertical ? "marginTop" : "marginLeft"
] = value + "px";
if (this.events.get("offset")) {
// Запрошен вызов события: "сдвиг"
// Вызов события: "сдвиг"
document.dispatchEvent(
new CustomEvent(`hotline.${this.#id}.offset`, {
detail: {
to: value,
},
}),
);
}
return this;
}
static preprocessing(event = false) {
// Инициализация счётчиков инстанций горячей строки
const success = new Set();
let error = 0;
for (
const element of document.querySelectorAll('*[data-hotline="true"]')
) {
// Перебор элементов для инициализации бегущих строк
if (typeof element.id === "string") {
// Найден идентификатор
// Инициализация инстанции бегущей строки
const hotline = new this(element.id, element);
for (const attribute of element.getAttributeNames()) {
// Перебор аттрибутов
// Запись параметра в инстанцию бегущей строки
hotline.configure(attribute);
}
// Запуск бегущей строки
hotline.start();
// Запись инстанции бегущей строки в элемент
element.hotline = hotline;
// Запись в счётчик успешных инициализаций
success.add(hotline);
} else ++error;
}
if (event) {
// Запрошен вызов события: "предварительная подготовка"
// Вызов события: "предварительная подготовка"
document.dispatchEvent(
new CustomEvent(`hotline.preprocessed`, {
detail: {
success,
error,
},
}),
);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -146,4 +146,4 @@ Object.assign(
);
// Connecting to the core
if (!core.session) core.session = session;
// if (!core.session) core.session = session;

View File

@ -1,5 +1,6 @@
@charset "UTF-8";
main>button#order,
main>section:is(#summary, #products, #delivery, #delivery_request) {
width: var(--width);
gap: var(--gap);
@ -48,33 +49,108 @@ main>section#delivery>div.column>div#deliveries>input:checked+label:active {
filter: brightness(0.8);
}
main>section#delivery>div.column>div#address {
main>section#delivery>div.column>section {
gap: 0.7rem;
}
main>section#delivery>div.column>section.cdek>div#address {
flex-flow: row wrap;
gap: 0.7rem;
}
main>section#delivery>div.column>div#address>input#location {
main>section#delivery>div.column>section.cdek>div#address>input#location {
min-width: max(6rem, 20%);
width: min(6rem, 100%);
flex-grow: 1;
}
main>section#delivery>div.column>div#address>input#street {
main>section#delivery>div.column>section.cdek>div#address>input#street {
min-width: max(10rem, 30%);
width: min(10rem, 100%);
flex-grow: 10;
}
main>section#delivery>div.column:not(:has(div#deliveries>input:checked))>div#address {
display: none;
main>section#delivery>div.column>section.cdek>div#map {
height: 203px;
overflow: hidden;
}
main>section#delivery>div.column>section.cdek>div#map * {
color: black !important;
}
main>section#delivery>div.column>section.cdek>div#map:not(.office, .door)>div>div:first-child,
main>section#delivery>div.column>section.cdek>div#map>div>div:last-child a[href="https://cdek.ru"],
main>section#delivery>div.column>section.cdek>div#map>div>div:last-child>div:first-child>div>ymaps>ymaps:last-of-type {
display: none !important;
}
main>section#delivery>div.column>section.cdek>div#map:not(.office, .door)>div>div:last-child>div:first-child>div>ymaps>ymaps:is(:nth-of-type(2), :nth-of-type(4)),
main>section#delivery>div.column>section.cdek>div#map:is(.office, .door)>div>div:last-child>div:first-child>div>ymaps>ymaps:is(:nth-of-type(1), :nth-of-type(3)) {
margin-bottom: unset !important;
}
main>section#delivery>div.column>section.cdek>div#map.office.door>div {
display: flex;
flex-direction: column;
gap: 1rem;
}
main>section#delivery>div.column>section.cdek>div#map.office.door>div>div:first-child {
order: 2;
margin-bottom: unset !important;
display: flex !important;
padding: unset !important;
flex-flow: row wrap;
gap: 0.7rem !important;
}
main>section#delivery>div.column>section.cdek>div#map.office.door>div>div:first-child> :is(div, div:is(:hover, :focus, :active)) {
margin: unset !important;
min-width: calc(50% - 0.7rem);
padding: 0.2rem 1rem;
flex-grow: 1;
border-radius: 0.75rem !important;
background-color: var(--tg-theme-button-color) !important;
filter: unset;
}
main>section#delivery>div.column>section.cdek>div#map.office.door>div>div:first-child>div:is(:hover, :focus) {
filter: brightness(1.5);
}
main>section#delivery>div.column>section.cdek>div#map.office.door>div>div:first-child>div:active {
filter: brightness(0.8);
}
main>section#delivery>div.column>section.cdek>div#map.office.door>div>div:first-child label {
color: var(--tg-theme-text-color);
}
main>section#delivery>div.column>section.cdek>div#map>div>div:last-child {
border: unset !important;
}
main>section#delivery>div.column>section.cdek>div#map:not(.office, .door)>div>div:last-child {
height: 100% !important
}
main>section#delivery>div.column>section.cdek>div#map.office.door>div>div:last-child {
order: 1;
height: calc(100% - 3.375rem - 0.5rem) !important;
border-radius: 0.75rem !important;
}
/* main>section#delivery>div.column:not(:has(div#deliveries>input:checked))>div#address {
display: none;
} */
main:has(section#summary.disabled:hover)>section#delivery>div {
filter: brightness(1.2);
}
section#delivery>div.column>div#deliveries>input:not(:checked)+section#delivery_request {
display: inline-flex;
section#delivery.hidden+#delivery_request {
display: none;
}
main>section#delivery_request>p:only-of-type {
@ -98,11 +174,17 @@ main>section#delivery_request>p:only-of-type>span:only-of-type {
color: var(--tg-theme-hint-color);
}
main>section#summary {
margin-top: -0.8rem;
margin-bottom: -0.5rem;
background-color: unset;
}
main>section#summary>div {
container-type: inline-size;
container-name: summary;
height: 2rem;
padding-left: 1rem;
padding: 0 1rem;
align-items: center;
gap: 0.4rem;
overflow: hidden;
@ -118,29 +200,8 @@ 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;
background: unset;
}
main>section#summary>div>button#order * {
color: var(--tg-theme-button-color);
}
main>section#summary.disabled,
main>section#summary>div:has(button#order:disabled),
main:not(:has(section#delivery>div.column>div#deliveries>input:checked))>section#summary>div:has(button#order:enabled) {
/* cursor: not-allowed; */
}
main>section#summary.disabled,
main>section#summary>div>button#order:disabled,
main:not(:has(section#delivery>div.column>div#deliveries>input:checked))>section#summary>div>button#order:enabled {
/* pointer-events: none;
filter: grayscale(1); */
display: none;
main>button#order {
/* margin-left: auto; */
}
main>section#products>article.product {
@ -256,6 +317,7 @@ main>section#products>article.product>div>div.footer>input {
width: 2rem;
padding: 0 0.3rem;
text-align: center;
color: var(--tg-theme-text-color);
}
@container summary (max-width: 450px) {
@ -263,7 +325,7 @@ main>section#products>article.product>div>div.footer>input {
--days: var(--days-short);
}
main>section#summary>div>span:not(#cost, #cost_delivery, #shipping) {
/* main>section#summary>div>span:not(#cost, #cost_delivery, #shipping) {
display: none;
}
} */
}

View File

@ -9,15 +9,16 @@
outline: none;
-webkit-tap-highlight-color: transparent;
font-family: "DejaVu";
color: var(--tg-theme-text-color);
transition: 0.1s ease-out;
}
* {
text-decoration: none;
outline: none;
border: none;
font-family: "DejaVu";
color: var(--tg-theme-text-color);
transition: 0.1s ease-out;
}
a {
@ -70,7 +71,7 @@ main {
transition: 0s;
}
main > *.merged {
main>*.merged {
margin-top: -14px;
}
@ -220,15 +221,20 @@ button {
background-color: var(--tg-theme-button-color);
}
:is(a[type="button"], button):disabled {
filter: contrast(0.7) brightness(0.7);
cursor: not-allowed;
}
a[type="button"] {
height: 23px;
}
:is(button, :is(a, label)[type="button"]):is(:hover, :focus) {
:is(button, :is(a, label)[type="button"]):not(:disabled):is(:hover, :focus) {
filter: brightness(120%);
}
:is(button, :is(a, label)[type="button"]):active {
:is(button, :is(a, label)[type="button"]):not(:disabled):active {
filter: brightness(80%);
transition: 0s;
}
@ -239,6 +245,7 @@ h2 {
}
input {
color: var(--tg-theme-text-color);
background: unset;
}
@ -292,8 +299,8 @@ input {
color: var(--tg-theme-hint-color);
}
.deleted {
display: none;
.hidden {
display: none !important;
}
.unselectable {

View File

@ -69,7 +69,6 @@ section#window>div.card>h3>a.exit[type="button"] {
}
section#window>div.card>div.images {
--image-width: 10rem;
height: 10rem;
min-height: 10rem;
max-height: 10rem;
@ -79,10 +78,13 @@ section#window>div.card>div.images {
transition: 0s;
}
section#window>div.card>div.images:has(> img:last-child:nth-child(2)) {
padding: 0rem 1rem;
}
section#window>div.card>div.images.extend {
--image-width: max(30rem, 40vw);
z-index: 9999999;
left: 0;
left: 10vw;
top: 10vh;
margin: unset !important;
position: absolute;
@ -93,6 +95,7 @@ section#window>div.card>div.images.extend {
max-height: 80vh;
align-items: center;
cursor: default;
overflow: unset;
transition: 0s;
}
@ -102,13 +105,12 @@ section#window>div.card:has(>div.images.extend)>:not(div.images.extend) {
section#window>div.card>div.images>img {
margin-right: 0.5rem;
width: var(--image-width);
max-width: var(--image-width);
min-width: 150px;
width: auto;
height: 10rem;
flex-shrink: 0;
flex-grow: 0;
object-fit: contain;
object-fit: cover;
image-rendering: auto;
border-radius: 0.5rem;
transition: 0s;
@ -116,8 +118,9 @@ section#window>div.card>div.images>img {
section#window>div.card>div.images.extend>img {
margin-right: 3vw;
width: auto;
height: 100%;
width: 80vw;
height: auto;
max-height: 100%;
object-fit: contain;
border-radius: 0.75rem;
}
@ -183,7 +186,6 @@ section#window>div.card>div.footer>button.buy {
}
@container window-footer (max-width: 350px) {
section#window>div.card>div.footer>small:first-of-type {
margin-left: auto;
}

View File

@ -0,0 +1,189 @@
var cdek;
var ready = false;
var moving = true;
function init(location) {
import('https://cdn.jsdelivr.net/npm/@cdek-it/widget@3')
.then(module => {
cdek = new window.CDEKWidget({
from: {
code: 248,
address: 'Екатерининская 116'
},
root: 'map',
apiKey: 'a222c5fe-fee7-420a-b979-aec0473a0400',
servicePath: 'https://arming.dev.mirzaev.sexy/api/cdek',
hideFilters: {
have_cashless: true,
have_cash: true,
is_dressing_room: true,
type: false,
},
hideDeliveryOptions: {
office: false,
door: false,
},
lang: '{{ language.name == "ru" ? "rus" : "eng" }}',
currency: '{{ currency.name|upper }}',
tariffs: {
office: [234, 136, 185, 368, 378, 498, 2323, 2360, 510, 291],
door: [233, 137, 186, 2322, 294],
},
defaultLocation: [location?.longitude || {{ session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].location.data.longitude ?? 37.622513 }}, location?.latitude || {{ session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].location.data.latitude ?? 55.75322 }}],
onReady() {
// const map = document.getElementById('map');
// map?.style.setProperty('--animation-end-height', '240px');
// map?.classList.add('animated', 'slide-down');
},
onCalculate(tariffs, address) {
// Deleting the delivery cost <span> element
document.getElementById("cost_delivery")?.remove();
// Deleting the delivery days <span> element
document.getElementById("shipping")?.remove();
// Disablind the order button
document.getElementById("order")?.setAttribute('disabled', true);
},
onChoose(type, tariff, address) {
moving = false;
// Deleting the delivery cost <span> element
document.getElementById("cost_delivery")?.remove();
// Deleting the delivery days <span> element
document.getElementById("shipping")?.remove();
// Disablind the order button
document.getElementById("order")?.setAttribute('disabled', true);
core.modules.connect("damper").then(
() => {
// Imported the damper module
// Execute under damper
if (tariff)
core.delivery.write.damper("type", tariff.tariff_code, true);
},
() => {
// Not imported the damper module
// Execute
if (tariff)
core.delivery.write.system("type", tariff.tariff_code, true);
},
);
setTimeout(() => {
//
const location = document.getElementById('location');
if (location instanceof HTMLInputElement) {
//
//
location.value = address.city;
//
core.delivery.location(location, false, true);
}
setTimeout(() => {
//
const street = document.getElementById('street');
if (type === 'office') {
//
if (street instanceof HTMLInputElement) {
//
//
street.value = address.address;
//
core.delivery.street(street, true);
}
} else {
//
if (street instanceof HTMLInputElement) {
//
//
street.value = address.name;
//
core.delivery.street(street, true);
}
}
setTimeout(() => {
map = true;
// Initializing the delivery data request <section> element
const request = document.getElementById("delivery_request");
if (request instanceof HTMLElement) {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.add("hidden");
}}, 1000);
}, 500);
}, 500);
},
});
{% for product in formatted %}
cdek?.addParcel({
weight: Math.ceil({{ product.weight is empty ? 0 : product.weight }}),
width: Math.ceil({{ product.x is empty ? 0 : product.x }}),
height: Math.ceil({{ product.y is empty ? 0 : product.y }}),
length: Math.ceil({{ product.z is empty ? 0 : product.z }})
});
{% endfor %}
});
}
document.addEventListener('core.telegram.api.location.received', (event) => {
if (!ready) {
ready = true;
init(event.detail.location);
}
});
document.addEventListener('core.telegram.api.location.rejected', (event) => {
if (!ready) {
ready = true;
init();
}
});
document.addEventListener('core.delivery.calculated', (event) => {
if (map && event.detail.json.longitude && event.detail.json.latitude)
cdek?.updateLocation([event.detail.json.longitude, event.detail.json.latitude]);
});
document.addEventListener('core.cart.summary.received', (event) => {
cdek?.resetParcels();
for (const product of event.detail.json?.products) {
cdek?.addParcel({
weight: Math.ceil(product.weight || 0),
width: Math.ceil(product.x || 0),
height: Math.ceil(product.y || 0),
length: Math.ceil(product.z || 0)
});
}
});
setTimeout(() =>
{
if (!ready) {
ready = true;
init();
}
}, 5000);

View File

@ -0,0 +1,21 @@
<section class="cdek column">
<div id="address" class="row">
<input id="location"
class="identifier{% if session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].location.identifier ?? session.buffer.delivery.location %} success{% endif %}"
placeholder="{{ language.name == 'ru' ? 'Город' : 'location' }}" value="{{
session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].location.name
? session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].location.name
~ ', '
~ session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].location.structure|reverse|join(', ')
: session.buffer.delivery.location }}"
onkeyup="core.delivery.location(this)" oninput="core.delivery.location(this)" tabindex="6" />
<input id="street" {% if session.buffer.delivery[account.buffer.delivery.company ??
session.buffer.delivery.company].street %} class="success" {% endif %}
placeholder="{{ language.name == 'ru' ? 'Улица' : 'Street' }}"
value="{{ session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].street ?? session.buffer.delivery.street }}"
onkeyup="core.delivery.street(this)" oninput="core.delivery.street(this)" tabindex="6" />
</div>
<div id="map" class="rounded">
</div>
</section>

View File

@ -3,8 +3,7 @@
<div class="column">
<div id="deliveries" class="row">
{% for identifier, delivery in deliveries %}
<input id="{{ identifier }}" name="delivery" type="radio" {% if identifier == (account.buffer.delivery.company ?? session.buffer.delivery.company) %}
checked{% endif %}>
<input id="{{ identifier }}" name="delivery" type="radio">
<label class="rounded" for="{{ identifier }}" type="button"
title="{{ (language.name == 'ru' ? 'Выбрать ' : 'Choose ') ~ delivery.label }}"
onclick="core.delivery.company(this.previousElementSibling)" tabindex="5">
@ -12,23 +11,21 @@
</label>
{% endfor %}
</div>
<div id="address" class="row">
<input id="location" class="identifier{% if session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].location.identifier %} success{% endif %}" placeholder="{{ language.name == 'ru' ? 'Город' : 'location' }}"
value="{{
session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].location.name
? session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].location.name
~ ', '
~ session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].location.structure|reverse|join(', ')
: (session.buffer.delivery.location ?? account.buffer.delivery.location) }}"
onkeyup="core.delivery.location(this)" oninput="core.delivery.location(this)" tabindex="6" />
<input id="street"{% if session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].street %} class="success"{% endif %} placeholder="{{ language.name == 'ru' ? 'Улица' : 'Street' }}"
value="{{ session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company] ? session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].street : (session.buffer.delivery.street ?? session.buffer.delivery.street) }}"
onkeyup="core.delivery.street(this)" oninput="core.delivery.location(this)" tabindex="6" />
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// The document loaded
setTimeout(() => {
// Selecting active delivery company <input> element in the delivery list <div> element
document.getElementById('deliveries')?.querySelector('label[for="{{ account.buffer.delivery.company ?? session.buffer.delivery.company }}"]')?.click()
}, 300);
});
</script>
</div>
</section>
<section id="delivery_request" class="rounded row unselectable merged {% if session.buffer.delivery[account.buffer.delivery.company ??
session.buffer.delivery.company].ready %}deleted{% endif %}">
<section id="delivery_request" class="rounded row unselectable merged{% if
session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].ready!=false %}
hidden{% endif %}">
<p>
<!-- <i class="icon pin small"></i> -->
<span>{{ language.name == 'ru' ? 'Укажите данные для доставки' : 'Enter delivery information' }}</span>

View File

@ -0,0 +1,5 @@
{% if cart.products is not empty %}
<button id="order" class="rounded merged column unselectable" onclick="core.cart.share(this)" {% if
session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].ready==false %}
disabled="true" {% endif %}>Оформить заказ</button>
{% endif %}

View File

@ -3,7 +3,7 @@
class="rounded column unselectable">
<div class="row">
<span id="amount">{{ cart.summary.amount ?? 0 }}</span>
<span>{{ language.name == "ru" ? "товаров на сумму" : "products worth" }}</span>
<span>{{ language.name == "ru" ? "товаров за " : "products worth" }}</span>
<span id="cost" class="cost currency">{{ cart.summary.cost ?? 0 }}</span>
{% if session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].cost %}
<span id="cost_delivery" class="cost delivery currency plus hint">{{ session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].cost }}</span>
@ -11,9 +11,6 @@
{% if session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].days %}
<span id="shipping" class="delivery days hint">{{ session.buffer.delivery[account.buffer.delivery.company ?? session.buffer.delivery.company].days }}</span>
{% endif %}
<button id="order" onclick="core.cart.share(this)" {% if session.buffer.delivery[account.buffer.delivery.company ??
session.buffer.delivery.company].ready == false %} disabled="true" {% endif %}
title="{{ language.name == 'ru' ? 'Оформить заказ' : 'Place an order' }}"><i class="icon arrow"></i></button>
</div>
</section>
{% endif %}

View File

@ -16,6 +16,7 @@
<h2 id="title" class="unselectable">{{ h2 }}</h2>
{% include "/themes/default/cart/elements/delivery.html" %}
{% include "/themes/default/cart/elements/summary.html" %}
{% include "/themes/default/cart/elements/order.html" %}
{% include "/themes/default/cart/elements/products.html" %}
{% endblock %}

View File

@ -23,5 +23,5 @@
{{ parent() }}
<script src="/js/modules/catalog.mjs" type="module"></script>
<script src="/js/modules/cart.mjs" type="module"></script>
<script src="/js/modules/hotline.js" type="module"></script>
<script src="/js/modules/hotline.mjs" type="module"></script>
{% endblock %}