2declare(strict_types=1);
4namespace Bitrix\Landing\Copilot\Data\Block;
6use Bitrix\Landing\Block;
7use Bitrix\Landing\Copilot\Data;
17 private const ZONES_WHERE_NEED_CHECK_RESPONSE = [
'ru'];
18 private const DEFAULT_ASPECT_RATIO =
'3by2';
19 private const DEFAULT_WIDTH = 720;
23 $titleStyleClasses = [
25 'u-heading-v2-3--bottom',
26 'u-heading-v2-8--bottom',
27 'u-heading-v2-3--top',
28 'u-heading-v2-8--top',
29 'u-heading-v2-13-2--left',
30 'u-heading-v2-13-2--right',
33 return $titleStyleClasses[array_rand($titleStyleClasses)];
47 !isset($json[
'blocks'])
48 || !is_array($json[
'blocks'])
54 $blocksData = $siteData->getBlocks();
56 $countBlocksFromResponse =
count($json[
'blocks']);
57 $countBlocksForRequest = 0;
58 foreach ($blocksData as $blockData)
60 if (!$blockData->isSeparator() && !$blockData->isMenu())
62 $countBlocksForRequest++;
66 return $countBlocksFromResponse === $countBlocksForRequest;
78 return in_array($zone, self::ZONES_WHERE_NEED_CHECK_RESPONSE,
true);
91 foreach ($nodeDataFromResponse as $dataItem)
93 if (is_string($dataItem))
95 $preparedData[] = self::replaceWordsForZone($dataItem);
97 if (is_array($dataItem))
99 $preparedData[] = $dataItem;
103 return $preparedData;
117 $tagsWithClass = self::findTagsWithClass(substr($selector, 1), $blockContent);
118 $defaultImageLinks = self::findImageLinks($tagsWithClass);
120 return self::getSizeDataImages($defaultImageLinks);
137 $baseUrl =
'https://cdn.bitrix24.site/bitrix/images/landing/default/';
139 foreach ($dataImages as $dataImage)
141 if (!isset($dataImage[
'aspectRatio'], $dataImage[
'width']))
146 $aspectRatio = $dataImage[
'aspectRatio'];
147 $width = (int)$dataImage[
'width'];
149 $defaultSrc[
'src'][] =
"{$baseUrl}{$aspectRatio}/{$width}.png";
150 $defaultSrc[
'src2x'][] =
"{$baseUrl}{$aspectRatio}/" . (
$width * 2) .
'.png';
166 if (str_starts_with($nodeCode,
'.'))
168 $nodeCode = substr($nodeCode, 1);
170 $pattern =
'/class="([^"]*' . $nodeCode .
'(\s|")(?:|")[^"]*)"/';
188 if (preg_match(
'/class="([^"]*landing-block[^"]*)"/', $blockContent,
$matches))
214 $blockInstance =
new Block($blockId);
215 if ($blockInstance->getId() <= 0)
220 $blockManifest = $blockInstance->getManifest();
221 $blockContent = $blockInstance->getContent();
223 $notAllowedSections = [
232 $blockSection = (
array)($blockManifest[
'block'][
'section'] ??
null);
233 $sectionIntersect = array_intersect($notAllowedSections, $blockSection);
234 if (!empty($sectionIntersect))
239 $notAllowedNodeTypes = [
'embed'];
241 foreach ($blockManifest[
'nodes'] as $node)
243 if (isset($node[
'type']) && in_array($node[
'type'], $notAllowedNodeTypes,
true))
248 if (isset($node[
'type']) && $node[
'type'] ===
'img')
250 $nodeCode = ltrim($node[
'code'],
'.');
251 $imageElements += substr_count($blockContent, $nodeCode .
' ');
252 $imageElements += substr_count($blockContent, $nodeCode .
'"');
256 if ($imageElements > 4)
261 if (self::hasNotAllowedTagInBlockContent($blockContent))
266 if ($blockInstance->getRepoId())
274 private static function hasNotAllowedTagInBlockContent(
string $blockContent): bool
276 $notAllowedTags = [
'table'];
278 foreach ($notAllowedTags as $tag)
280 if (preg_match(
'/<\s*' . preg_quote($tag,
'/') .
'\b/i', $blockContent))
296 private static function replaceWordsForZone(
string $dataItem): string
302 'fa-square-instagram' =>
'fa-pinterest',
303 'fa-instagram' =>
'fa-pinterest',
304 'fa-meta' =>
'fa-vk',
305 'fa-square-facebook' =>
'fa-vk',
306 'fa-facebook-messenger' =>
'fa-vk',
307 'fa-facebook-f' =>
'fa-vk',
308 'fa-facebook' =>
'fa-vk',
309 'Instagram' =>
'Pinterest',
314 if (isset($replacementMap[$zone]))
316 foreach ($replacementMap[$zone] as $search => $replace)
318 $dataItem = preg_replace_callback(
319 '/' . preg_quote($search,
'/') .
'/i',
320 static function() use ($replace) {
339 private static function findTagsWithClass(
string $class,
string $contentBlock):
array
341 $patternPart1 =
'/<([a-z]+)\b[^>]*class=["][^"]*\b';
342 $patternPart2 =
'\b(?:["\s][^"]*)?["][^>]*>/i';
343 $pattern = $patternPart1 . $class . $patternPart2;
363 private static function findImageLinks(
array $tags):
array
367 foreach ($tags as $tag)
369 $pattern =
'/\b(?:https?:\/\/|www\.)\S+\.(?:jpg|jpeg|png)(?=\b|[^a-z0-9])/i';
370 if (preg_match(
$pattern, $tag, $match))
372 $links[] = $match[0];
390 private static function getSizeDataImages(
array $defaultImageLinks):
array
394 foreach ($defaultImageLinks as $defaultImageLink)
396 [
$width, $height, $aspectRatio] = Images::getImageData($defaultImageLink);
398 $closestAspectRatioKey = self::getClosestAspectRatioKey($aspectRatio);
400 $closestWidth = self::getClosestWidth((
int)
$width, $closestAspectRatioKey);
403 'width' => $closestWidth,
405 'aspectRatio' => $closestAspectRatioKey,
417 private static function getAllowedWidths():
array
420 '9by16' => [
'180',
'270',
'360',
'450',
'540',
'720'],
421 '2by3' => [
'240',
'320',
'360',
'480',
'600',
'720',
'880'],
422 '1by1' => [
'180',
'256',
'512',
'720',
'1024',
'1280',
'1440',
'1920'],
423 '3by2' => [
'360',
'480',
'540',
'720',
'900',
'1080',
'1320',
'1620',
'1920'],
424 '16by9' => [
'320',
'450',
'480',
'640',
'800',
'960',
'1280',
'1440',
'1600',
'1920'],
437 $allowedAspectRatios = self::getAllowedAspectRatios();
438 $closestAspectRatioKey =
null;
439 $closestAspectRatioDiff = PHP_FLOAT_MAX;
441 foreach ($allowedAspectRatios as
$key => $value)
443 $diff = abs($aspectRatio - $value);
444 if ($diff < $closestAspectRatioDiff)
446 $closestAspectRatioDiff = $diff;
447 $closestAspectRatioKey =
$key;
451 return $closestAspectRatioKey;
471 foreach ($gendersData as $gender)
473 $gender = in_array($gender, [
'male',
'female']) ? $gender :
'unisex';
475 if (!isset($usedRandInt[$gender]))
477 $usedRandInt[$gender] = [];
482 $randInt = rand(1, $genderMaxValues[$gender]);
484 while (in_array($randInt, $usedRandInt[$gender],
true));
486 $usedRandInt[$gender][] = $randInt;
488 $links[] =
'https://cdn.bitrix24.site/bitrix/images/landing/default/' . $gender .
'/' . $randInt .
'.png';
496 return self::DEFAULT_ASPECT_RATIO;
501 $allowedWidths = self::getAllowedWidths();
503 if (!isset($allowedWidths[$aspectRatio]))
505 return self::DEFAULT_WIDTH;
508 $widths = $allowedWidths[$aspectRatio];
509 $middleIndex = (int)(
count($widths) / 2);
511 return (
int)$widths[$middleIndex];
516 $defaultAvatarLink =
'https://cdn.bitrix24.site/bitrix/images/landing/default/1by1/512.png';
517 $defaultAvatarLink2x =
'https://cdn.bitrix24.site/bitrix/images/landing/default/1by1/1024.png';
519 $countLinks =
count($gendersData);
520 for (
$i = 0;
$i < $countLinks;
$i++)
523 'src' => $defaultAvatarLink,
524 'src2x' => $defaultAvatarLink2x,
541 $allowedWidths = self::getAllowedWidths();
543 if ($closestAspectRatioKey ===
null)
548 $closest = $allowedWidths[$closestAspectRatioKey][0] ??
null;
549 $smallestDifference = abs(
$width - $closest);
551 foreach ($allowedWidths[$closestAspectRatioKey] as $allowedWidth)
553 $difference = abs(
$width - $allowedWidth);
554 if ($difference < $smallestDifference)
556 $smallestDifference = $difference;
557 $closest = $allowedWidth;
561 return (
int)$closest;
static isBlockAvailableForScenarioChangeBlock(int $blockId)
static getClosestAspectRatioKey(float $aspectRatio)
static getAllowedAspectRatios()
static getClosestWidth(int $width, ?string $closestAspectRatioKey)
static getDefaultAvatarLinks(array $gendersData)
static getTitleStyleClass()
static getDefaultSrc(array $dataImages)
static checkBlocksAmount(Data\Site $siteData, array $json)
static getDefaultAspectRatio()
static getAvatarLinks(array $gendersData)
static extractWrapperClasses(string $blockContent)
static extractNodeClasses(string $nodeCode, string $blockContent)
static isNeedCheckDataFromResponse()
static getDefaultWidth(string $aspectRatio)
static prepareDataFromResponse(array $nodeDataFromResponse)
static getSizeDataImagesBySelector(string $selector, string $blockContent)
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
if(empty($signedUserToken)) $key
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
if(!Loader::includeModule('sale')) $pattern