4use \Bitrix\Main\Page\Asset;
5use \Bitrix\Main\Web\Json;
6use \Bitrix\Main\Web\DOM;
7use \Bitrix\Main\Localization\Loc;
8use \Bitrix\Landing\Connector;
9use \Bitrix\Landing\Controller;
10use \Bitrix\Landing\Internals;
11use \Bitrix\Landing\Assets;
12use \Bitrix\Landing\Block\Cache;
13use \Bitrix\Landing\Restriction;
14use \Bitrix\Landing\Node\Type as NodeType;
15use \Bitrix\Landing\Node\Img;
16use \Bitrix\Landing\PublicAction\Utils as UtilsAction;
259 'landing_google_maps_new',
262 'landing_gallery_cards',
274 if (empty($data) || !is_array($data))
276 $data = parent::getList(array(
279 'LANDING_TITLE' =>
'LANDING.TITLE',
280 'LANDING_ACTIVE' =>
'LANDING.ACTIVE',
281 'LANDING_TPL_CODE' =>
'LANDING.TPL_CODE',
282 'SITE_TPL_CODE' =>
'LANDING.SITE.TPL_CODE',
283 'SITE_TYPE' =>
'LANDING.SITE.TYPE',
284 'SITE_ID' =>
'LANDING.SITE_ID'
297 if (!isset($data[
'CONTENT']) || trim($data[
'CONTENT']) ==
'')
299 $data[
'CONTENT'] =
'';
302 $this->
id = intval(
$id);
303 $this->lid = isset($data[
'LID']) ? intval($data[
'LID']) : 0;
304 $this->parentId = isset($data[
'PARENT_ID']) ? intval($data[
'PARENT_ID']) : 0;
305 $this->siteId = isset($data[
'SITE_ID']) ? intval($data[
'SITE_ID']) : 0;
306 $this->sort = isset($data[
'SORT']) ? intval($data[
'SORT']) :
'';
307 $this->code = isset($data[
'CODE']) ? trim($data[
'CODE']) :
'';
308 $this->anchor = isset($data[
'ANCHOR']) ? trim($data[
'ANCHOR']) :
'';
309 $this->active = isset($data[
'ACTIVE']) && $data[
'ACTIVE'] ==
'Y';
310 $this->landingActive = isset($data[
'LANDING_ACTIVE']) && $data[
'LANDING_ACTIVE'] ==
'Y';
311 $this->deleted = isset($data[
'DELETED']) && $data[
'DELETED'] ==
'Y';
312 $this->designed = isset($data[
'DESIGNED']) && $data[
'DESIGNED'] ==
'Y';
313 $this->
public = isset($data[
'PUBLIC']) && $data[
'PUBLIC'] ==
'Y';
314 $this->content = (!$this->deleted && isset($data[
'CONTENT'])) ? trim($data[
'CONTENT']) :
'';
317 if (isset($data[
'ACCESS']))
319 $this->access = $data[
'ACCESS'];
323 if (isset($data[
'ASSETS']))
325 $this->assets = $data[
'ASSETS'];
330 'LID',
'FAVORITE_META',
'CREATED_BY_ID',
'DATE_CREATE',
331 'MODIFIED_BY_ID',
'DATE_MODIFY',
'SITE_TYPE'
333 foreach ($keys as $key)
335 if (isset($data[$key]))
337 $this->metaData[$key] = $data[$key];
340 $this->metaData[
'LANDING_TITLE'] = isset($data[
'LANDING_TITLE']) ? $data[
'LANDING_TITLE'] :
'';
341 $this->metaData[
'LANDING_TPL_CODE'] = isset($data[
'LANDING_TPL_CODE']) ? $data[
'LANDING_TPL_CODE'] :
'';
342 $this->metaData[
'SITE_TPL_CODE'] = isset($data[
'SITE_TPL_CODE']) ? $data[
'SITE_TPL_CODE'] :
'';
343 $this->metaData[
'XML_ID'] = isset($data[
'XML_ID']) ? $data[
'XML_ID'] :
'';
344 $this->metaData[
'DESIGNER_MODE'] = isset($params[
'designer_mode']) && $params[
'designer_mode'] ===
true;
347 if (preg_match(self::REPO_MASK, $this->code, $matches))
349 $this->repoId = $matches[1];
351 if (!$this->content && !$this->deleted)
353 $this->content = self::getContentFromRepository($this->code);
355 $this->error =
new Error;
359 if (isset($data[
'SOURCE_PARAMS']))
361 $this->dynamicParams = (array)$data[
'SOURCE_PARAMS'];
374 if ($landing->exist())
376 $editMode = $landing->getEditMode() || $landing->getPreviewMode();
381 'LID' => $landing->getId(),
382 '=PUBLIC' => $editMode ?
'N' :
'Y',
383 '=DELETED' => (isset($params[
'deleted']) && $params[
'deleted'] ===
true)
387 if (isset($params[
'id']) && $params[
'id'])
389 $filter[
'ID'] = $params[
'id'];
391 $res = parent::getList(array(
394 'LANDING_ACTIVE' =>
'LANDING.ACTIVE',
395 'LANDING_TPL_CODE' =>
'LANDING.TPL_CODE',
396 'SITE_TPL_CODE' =>
'LANDING.SITE.TPL_CODE',
397 'SITE_TYPE' =>
'LANDING.SITE.TYPE',
398 'SITE_ID' =>
'LANDING.SITE_ID'
407 while ($row = $res->fetch())
410 if (!$landing->canEdit())
412 $row[
'ACCESS'] = self::ACCESS_A;
414 $row[
'SITE_ID'] = $landing->getSiteId();
420 if ($block->getRepoId())
422 $repo[] = $block->getRepoId();
424 $blocks[$row[
'ID']] = $block;
432 foreach ($blocks as $block)
435 isset($repo[$block->getRepoId()][
'PAYMENT_ALLOW']) &&
436 $repo[$block->getRepoId()][
'PAYMENT_ALLOW'] !=
'Y'
448 $landing->addBlockToCollection($block);
452 $landing->addBlockToCollection($block);
455 unset($blocks, $block, $repo);
469 if ($landing->exist())
474 $res = parent::getList(array(
476 'ID',
'LID',
'CODE',
'SORT',
'ACTIVE',
477 'CONTENT',
'PUBLIC',
'ACCESS',
'ANCHOR',
481 'LID' => $landing->getId()
484 while ($row = $res->fetch())
486 if ($row[
'PUBLIC'] !=
'Y')
495 $row[
'ANCHOR'] =
'b' . $row[
'ID'];
497 $row[
'PUBLIC'] =
'N';
498 $row[
'PARENT_ID'] = $row[
'ID'];
506 foreach ($forClone as $row)
532 $res = parent::getList(array(
540 while ($row = $res->fetch())
542 $data[$row[
'ID']] = $row[
'LID'];
549 elseif (!empty($data))
551 return array_pop($data);
566 return self::getRowByBlockId(
$id, $select);
578 $res = parent::getList(array(
584 while ($row = $res->fetch())
586 $data[$row[
'ID']] = $row;
593 elseif (!empty($data))
595 return array_pop($data);
610 if (isset($cached[$code]))
612 return $cached[$code];
615 $codeOriginal = $code;
616 [$code, $blockId] = explode(
'@', $code);
624 $filter[
'ID'] = $blockId;
626 $res = Internals\BlockTable::getList([
628 'ID',
'CODE',
'CONTENT',
'SOURCE_PARAMS',
'DESIGNED'
632 if ($row = $res->fetch())
634 $cached[$codeOriginal] = $row;
638 return $cached[$codeOriginal] ??
null;
649 if (!is_string($code))
654 if (strpos($code,
'@'))
656 $normalizedBlock = self::getNormalizedBlock($code);
657 return $normalizedBlock[
'CONTENT'] ??
null;
663 if (preg_match(self::REPO_MASK, $code, $matches))
669 elseif ($path = self::getBlockPath($code, $namespace))
672 if (file_exists($path))
674 $content = file_get_contents($path);
675 if (preg_match(
'/MESS\[[^\]]+\]/',
$content))
681 foreach ($mess as $key => $title)
683 $replace[
'MESS[' . $key .
']'] = $title;
686 array_keys($replace),
687 array_values($replace),
708 $filesFromContent = [];
710 $codeOriginal =
null;
712 $content = $data[
'CONTENT'] ?? self::getContentFromRepository($code);
713 if (isset($data[
'PREPARE_BLOCK_DATA'][
'ACTION']))
716 $data[
'PREPARE_BLOCK_DATA'][
'ACTION'] ===
'changeComponentParams'
717 && isset($data[
'PREPARE_BLOCK_DATA'][
'PARAMS'])
718 && is_array($data[
'PREPARE_BLOCK_DATA'][
'PARAMS'])
721 foreach ($data[
'PREPARE_BLOCK_DATA'][
'PARAMS'] as $paramName => $paramValue)
723 $search =
"'" . $paramName .
"' => '',";
724 $replace =
"'" . $paramName .
"' => '". $paramValue .
"',";
729 if (strpos($code,
'@'))
731 $codeOriginal = $code;
732 $normalizedBlock = self::getNormalizedBlock($code);
733 $designed = $normalizedBlock[
'DESIGNED'] ??
'N';
734 $filesFromContent = $normalizedBlock[
'FILES'] ?? [];
735 $sourceParams = $normalizedBlock[
'SOURCE_PARAMS'] ?? [];
736 [$code, ] = explode(
'@', $code);
738 $manifest = self::getManifestFile($code);
741 isset($manifest[
'block'][
'version']) &&
745 $landing->getError()->addError(
746 'BLOCK_WRONG_VERSION',
752 if (!$landing->exist())
754 $landing->getError()->addError(
762 $landing->getError()->addError(
770 'LID' => $landing->getId(),
772 'SOURCE_PARAMS' => $sourceParams,
777 $availableReplace = array(
778 'ACTIVE',
'PUBLIC',
'ACCESS',
'SORT',
779 'CONTENT',
'ANCHOR',
'SOURCE_PARAMS',
780 'INITIATOR_APP_CODE',
'XML_ID',
781 'DESIGNED',
'FAVORITE_META'
783 foreach ($availableReplace as $replace)
785 if (isset($data[$replace]))
787 $fields[$replace] = $data[$replace];
790 $res = parent::add($fields);
791 if ($res->isSuccess())
793 $block =
new self($res->getId());
794 $manifest = $block->getManifest();
795 if (!$block->getLocalAnchor())
799 $block->setAnchor(
'b' . $block->getId());
802 Assets\PreProcessing::blockAddProcessing($block);
804 isset($manifest[
'callbacks'][
'afteradd']) &&
805 is_callable($manifest[
'callbacks'][
'afteradd'])
808 $manifest[
'callbacks'][
'afteradd']($block);
811 foreach ($block->getClass() as $class)
813 $classBlock = $block->includeBlockClass($class);
814 $classBlock->beforeAdd($block);
817 if ($fields[
'SOURCE_PARAMS'])
819 $block->saveDynamicParams(
820 $fields[
'SOURCE_PARAMS']
823 if (isset($manifest[
'block'][
'app_code']))
826 'INITIATOR_APP_CODE' => $manifest[
'block'][
'app_code']
834 foreach ($filesFromContent as $fileId)
842 $landing->getError()->addFromResult($res);
854 static $newBlocks =
null;
856 if (!is_string($block))
861 if ($newBlocks ===
null)
863 $newBlocks = unserialize(
Manager::getOption(
'new_blocks'), [
'allowed_classes' =>
false]);
864 if (!is_array($newBlocks))
866 $newBlocks = array();
869 !isset($newBlocks[
'date']) ||
871 isset($newBlocks[
'date']) &&
872 ((time() - $newBlocks[
'date']) > self::NEW_BLOCK_LT)
876 $newBlocks = array();
878 if (isset($newBlocks[
'items']))
880 $newBlocks = $newBlocks[
'items'];
884 return in_array($block, $newBlocks);
893 static $paths =
null;
898 BX_ROOT .
'/' . self::BLOCKS_DIR,
899 \getLocalPath(self::BLOCKS_DIR)
901 if ($paths[0] == $paths[1])
928 static $namespaces = [];
935 $paths = self::getGeneralPaths();
936 $disableNamespace = (array)
Config::get(
'disable_namespace');
937 $enableNamespace =
Config::get(
'enable_namespace');
938 $enableNamespace = $enableNamespace ? (array) $enableNamespace : array();
941 foreach ($paths as $path)
947 if (($handle = opendir($path)))
949 while ((($entry = readdir($handle)) !==
false))
951 if (!empty($enableNamespace))
953 if (in_array($entry, $enableNamespace))
955 $namespaces[] = $entry;
959 $entry !=
'.' && $entry !=
'..' &&
960 is_dir($path .
'/' . $entry) &&
961 !in_array($entry, $disableNamespace)
964 $namespaces[] = $entry;
970 $namespaces = array_unique($namespaces);
982 static $blocksCats = array();
985 $returnFunc =
function($blocksCats) use($withManifest)
987 $event = new \Bitrix\Main\Event(
'landing',
'onBlockGetRepository', array(
988 'blocks' => $blocksCats,
989 'withManifest' => $withManifest
992 foreach ($event->getResults() as $result)
994 if ($result->getResultType() != \
Bitrix\Main\EventResult::ERROR)
996 if (($modified = $result->getModified()))
998 if (isset($modified[
'blocks']))
1000 $blocksCats = $modified[
'blocks'];
1009 if (!$withManifest && !empty($blocksCats))
1011 return $returnFunc($blocksCats);
1015 $fillLastUsed =
function($blocksCats)
1017 $blocksCats[
'last'][
'items'] = array();
1018 $lastUsed = self::getLastUsed();
1021 foreach ($lastUsed as $code)
1023 $blocksCats[
'last'][
'items'][$code] = array();
1025 foreach ($blocksCats as $catCode => &$cat)
1027 foreach ($cat[
'items'] as $code => &$block)
1030 in_array($code, $lastUsed) &&
1031 $catCode !=
'last' &&
1035 $block[
'section'][] =
'last';
1036 $blocksCats[
'last'][
'items'][$code] = $block;
1043 foreach ($blocksCats[
'last'][
'items'] as $code => $block)
1047 unset($blocksCats[
'last'][
'items'][$code]);
1055 $disableNamespace = (array)
Config::get(
'disable_namespace');
1056 $enableNamespace =
Config::get(
'enable_namespace');
1057 $enableNamespace = $enableNamespace ? (array) $enableNamespace : array();
1060 $cache = new \CPHPCache();
1062 $cacheStarted =
false;
1063 $cacheId = $withManifest ?
'blocks_manifest' :
'blocks';
1064 $cacheId .= LANGUAGE_ID;
1066 $cacheId .=
'version:2';
1067 $cacheId .=
'disable:' . implode(
',', $disableNamespace);
1068 $cacheId .=
'enable:' . implode(
',', $enableNamespace);
1069 $cachePath =
'landing/blocks';
1070 if ($cache->initCache($cacheTime, $cacheId, $cachePath))
1072 $blocksCats = $cache->getVars();
1073 if (is_array($blocksCats) && !empty($blocksCats))
1075 $blocksCats = $fillLastUsed($blocksCats);
1076 return $returnFunc($blocksCats);
1079 if ($cache->startDataCache($cacheTime, $cacheId, $cachePath))
1081 $cacheStarted =
true;
1091 $sections = array();
1094 $paths = self::getGeneralPaths();
1095 $namespaces = self::getNamespaces();
1099 foreach ($namespaces as $subdir)
1101 foreach ($paths as $path)
1105 is_dir($path .
'/' . $subdir) &&
1106 ($handle = opendir($path .
'/' . $subdir))
1110 $sectionsPath = $path .
'/' . $subdir .
'/.sections.php';
1111 if (file_exists($sectionsPath))
1113 $sections = array_merge(
1115 (array) include $sectionsPath
1118 if (!isset($sections[
'last']))
1120 $sections[
'last'] = [
1125 while ((($entry = readdir($handle)) !==
false))
1127 $descriptionPath = $path .
'/' . $subdir .
'/' . $entry .
'/.description.php';
1128 $previewPathJpg = $path .
'/' . $subdir .
'/' . $entry .
'/' . self::PREVIEW_FILE_NAME;
1129 if ($entry !=
'.' && $entry !=
'..' && file_exists($descriptionPath))
1132 $description = include $descriptionPath;
1133 if (isset($description[
'block'][
'name']))
1137 self::BLOCKS_DIR .
'/' . $subdir .
'/' . $entry .
'/' . self::PREVIEW_FILE_NAME
1140 $blocks[$entry] = array(
1141 'id' => isset($description[
'block'][
'id'])
1142 ? (
string)$description[
'block'][
'id']
1144 'name' => $description[
'block'][
'name'],
1145 'namespace' => $subdir,
1146 'new' => self::isNewBlock($entry),
1147 'version' => isset($description[
'block'][
'version'])
1148 ? $description[
'block'][
'version']
1150 'type' => isset($description[
'block'][
'type'])
1151 ? $description[
'block'][
'type']
1153 'section' => isset($description[
'block'][
'section'])
1154 ? $description[
'block'][
'section']
1156 'description' => isset($description[
'block'][
'description'])
1157 ? $description[
'block'][
'description']
1159 'preview' => file_exists($previewPathJpg)
1162 'restricted' =>
false,
1164 'app_code' =>
false,
1165 'only_for_license' => $description[
'block'][
'only_for_license'] ??
'',
1169 $blocks[$entry][
'manifest'] = self::getManifestFile(
1170 $subdir .
':' . $entry
1172 $blocks[$entry][
'content'] = self::getContentFromRepository(
1175 if (isset($blocks[$entry][
'manifest'][
'block']))
1177 $blocks[$entry][
'manifest'][
'block'][
'preview'] = $blocks[$entry][
'preview'];
1180 if (!isset($blocks[$entry][
'manifest'][
'assets']))
1182 $blocks[$entry][
'manifest'][
'assets'] = array();
1185 if (file_exists($path .
'/' . $subdir .
'/' . $entry .
'/style.min.css'))
1187 if (!isset($blocks[$entry][
'manifest'][
'assets'][
'css']))
1189 $blocks[$entry][
'manifest'][
'assets'][
'css'] = array();
1193 self::BLOCKS_DIR .
'/' . $subdir .
'/' . $entry .
'/style.min.css'
1198 if (file_exists($path .
'/' . $subdir .
'/' . $entry .
'/script.min.js' ))
1200 if (!isset($blocks[$entry][
'manifest'][
'assets'][
'js']))
1202 $blocks[$entry][
'manifest'][
'assets'][
'js'] = array();
1206 self::BLOCKS_DIR .
'/' . $subdir .
'/' . $entry .
'/script.min.js'
1210 if (empty($blocks[$entry][
'manifest'][
'assets']))
1212 unset($blocks[$entry][
'manifest'][
'assets']);
1226 foreach ($blocksRepo as $block)
1228 if ($block[
'app_code'])
1230 $apps[] = $block[
'app_code'];
1235 $apps = array_unique($apps);
1238 foreach ($blocksRepo as &$block)
1241 $block[
'app_code'] &&
1242 isset($apps[$block[
'app_code']]) &&
1243 $apps[$block[
'app_code']][
'PAYMENT_ALLOW'] ==
'N'
1246 $block[
'app_expired'] =
true;
1251 $blocks += $blocksRepo;
1255 $favoriteBlocks = [];
1256 $favoriteMyBlocks = [];
1257 $res = Internals\BlockTable::getList([
1259 'ID',
'CODE',
'FAVORITE_META',
'CREATED_BY_ID'
1268 'limit' => self::FAVOURITE_BLOCKS_LIMIT,
1270 $countFavoriteBlocks = 0;
1271 while ($row = $res->fetch())
1273 $countFavoriteBlocks++;
1274 if (isset($blocks[$row[
'CODE']]))
1276 if (!is_array($row[
'FAVORITE_META']))
1280 $meta = $row[
'FAVORITE_META'];
1281 $meta[
'preview'] = $meta[
'preview'] ?? 0;
1282 $meta[
'favorite'] =
true;
1283 $meta[
'favoriteMy'] = ((int)$row[
'CREATED_BY_ID'] === $currentUser);
1284 if ($meta[
'preview'] > 0 && $countFavoriteBlocks < self::FAVOURITE_BLOCKS_LIMIT_WITH_PREVIEW)
1290 unset($meta[
'preview']);
1292 if (isset($meta[
'section']))
1294 $meta[
'section'] = (array)$meta[
'section'];
1297 $item = array_merge(
1298 $blocks[$row[
'CODE']],
1301 $code = $row[
'CODE'] .
'@' . $row[
'ID'];
1302 if ($item[
'type'] ===
'null')
1308 ? ($favoriteMyBlocks[$code] = $item)
1309 : ($favoriteBlocks[$code] = $item)
1313 $blocks = $favoriteMyBlocks + $blocks + $favoriteBlocks;
1316 $createNewSection =
function($item)
1319 'name' => isset($item[
'name'])
1320 ? (
string) $item[
'name']
1322 'meta' => $item[
'meta'] ?? [],
1324 'type' => $item[
'type'] ??
null,
1325 'separator' =>
false,
1326 'app_code' =>
false,
1333 foreach ($sections as $code => $item)
1335 $title = $item[
'name'] ?? $item;
1336 $title = (string) $title;
1337 $title = trim($title);
1338 $blocksCats[$code] = $createNewSection($item);
1339 $createdSects[$title] = $code;
1341 foreach ($blocks as $key => $block)
1343 if (!is_array($block[
'section']))
1345 $block[
'section'] = array($block[
'section']);
1347 foreach ($block[
'section'] as $section)
1349 $section = trim($section);
1355 if (!isset($blocksCats[$section]))
1357 if (isset($createdSects[$section]))
1359 $section = $createdSects[$section];
1363 $blocksCats[$section] = $createNewSection($section);
1366 $blocksCats[$section][
'items'][$key] = $block;
1369 $blocksCats[$section][
'new'] =
true;
1375 if (!empty($blocksRepo) && !empty($apps))
1377 $blocksCats[
'separator_apps'] = array(
1379 'separator' =>
true,
1382 foreach ($apps as $app)
1384 $blocksCats[$app[
'CODE']] = array(
1385 'name' => $app[
'APP_NAME'],
1387 'separator' =>
false,
1388 'app_code' => $app[
'CODE'],
1393 foreach ($blocksRepo as $key => $block)
1395 if ($block[
'app_code'])
1397 $blocksCats[$block[
'app_code']][
'items'][$key] = $block;
1403 foreach ($blocksCats as $codeCat => &$blocksCat)
1405 $codeCat = mb_strtoupper($codeCat);
1406 uasort($blocksCat[
'items'],
function($item1, $item2) use($codeCat)
1408 if ($item1[
'repo_id'])
1412 if ($item2[
'repo_id'])
1417 ($item1[
'id'] && $item2[
'id']) &&
1418 mb_strpos($item1[
'id'],
'BX_'.$codeCat.
'_') === 0 &&
1419 mb_strpos($item2[
'id'],
'BX_'.$codeCat.
'_') === 0
1422 return ($item1[
'id'] > $item2[
'id']) ? 1 : -1;
1432 $cache->endDataCache($blocksCats);
1439 $blocksCats = $fillLastUsed($blocksCats);
1441 return $returnFunc($blocksCats);
1453 $res = Internals\BlockLastUsedTable::getList([
1461 'DATE_CREATE' =>
'DESC'
1465 while ($row = $res->fetch())
1467 $blocks[] = $row[
'CODE'];
1480 $res = Internals\BlockLastUsedTable::getList([
1486 '=CODE' => $blockCode
1490 if ($row = $res->fetch())
1492 Internals\BlockLastUsedTable::update($row[
'ID'], [
1498 Internals\BlockLastUsedTable::add([
1499 'CODE' => $blockCode,
1513 $res = Internals\BlockLastUsedTable::getList([
1518 '=CODE' => $blockCode
1521 while ($row = $res->fetch())
1523 Internals\BlockLastUsedTable::delete($row[
'ID']);
1533 return self::getSpecialManifest(
'style');
1542 return self::getSpecialManifest(
'semantic');
1551 return self::getSpecialManifest(
'attrs');
1562 if (array_key_exists($type, $style))
1564 return $style[$type];
1568 $paths = self::getGeneralPaths();
1571 foreach ($paths as $path)
1574 if (($handle = opendir($path)))
1576 while ((($entry = readdir($handle)) !==
false))
1579 $entry !=
'.' && $entry !=
'..' &&
1580 is_dir($path .
'/' . $entry) &&
1581 file_exists($path .
'/' . $entry .
'/.' . $type .
'.php')
1584 $style[$type][$entry] = include $path .
'/' . $entry .
'/.' . $type .
'.php';
1585 if (!is_array($style[$type][$entry]))
1587 unset($style[$type][$entry]);
1594 return $style[$type];
1606 if (!isset($params[
'wrapper_show']))
1608 $params[
'wrapper_show'] =
true;
1612 $params[
'force_unactive'] =
true;
1614 $params[
'skip_system_script'] =
true;
1618 $block =
new self(
$id);
1620 if (($ext = $block->getExt()))
1622 $extContent = \CUtil::initJSCore($ext,
true);
1623 $extContent = preg_replace(
1624 '#<script type="text/javascript"(\sdata\-skip\-moving\="true")?>.*?</script>#is',
1630 $block->getLandingId(),
1632 'skip_blocks' =>
true
1641 $landing->exist() ? $landing :
null,
1650 if ($landing->exist() && mb_strpos(
$content,
'#crm') !==
false)
1652 $replace = Connector\Crm::getReplacesForContent($landing->getSiteId(),
false);
1654 array_keys($replace),
1655 array_values($replace),
1660 if ($block->exist())
1663 $availableJS = !$editMode || !$block->getRepoId();
1664 $manifest = $block->getManifest();
1666 !isset($manifest[
'requiredUserAction']) &&
1667 $block->getRuntimeRequiredUserAction()
1670 $manifest[
'requiredUserAction'] = $block->getRuntimeRequiredUserAction();
1672 $sections = (array)(($manifest[
'block'][
'section']) ??
null);
1675 'sections' => implode(
',', $sections),
1676 'active' => $block->isActive(),
1677 'access' => $block->getAccess(),
1678 'anchor' => $block->getLocalAnchor(),
1679 'php' => mb_strpos($block->getContent(),
'<?') !==
false,
1680 'designed' => $block->isDesigned(),
1681 'repoId' => $block->repoId ? (
int)$block->repoId :
null,
1683 'content_ext' => $extContent,
1684 'css' => $block->getCSS(),
1685 'js' => $availableJS ? $block->getJS() : array(),
1686 'manifest' => $manifest,
1687 'dynamicParams' => $block->dynamicParams
1691 isset($return[
'manifest'][
'requiredUserAction'])
1694 $return[
'requiredUserAction'] = $return[
'manifest'][
'requiredUserAction'];
1698 $ajaxAssets = self::getAjaxInitiatedAssets();
1699 $return[
'js'] = array_merge($return[
'js'], $ajaxAssets[
'js']);
1700 $return[
'css'] = array_merge($return[
'css'], $ajaxAssets[
'css']);
1719 return 'block' . (int)
$id;
1729 static $paths = array();
1730 static $namespace = array();
1732 if (!is_string($code))
1737 $code = trim($code);
1739 if (isset($paths[$code]))
1741 return $paths[$code];
1746 $namespaces = self::getNamespaces();
1747 $generalPaths = self::getGeneralPaths();
1750 foreach (array_reverse($namespaces) as $subdir)
1752 foreach ($generalPaths as $path)
1755 if (file_exists($path .
'/' . $subdir .
'/' . $code .
'/.description.php'))
1757 $paths[$code] = $subdir;
1763 return $paths[$code];
1774 if (!is_string($code))
1779 if (strpos($code,
'@'))
1781 [$code, ] = explode(
'@', $code);
1786 $namespace = self::getBlockNamespace($code);
1790 return \getLocalPath(
1791 self::BLOCKS_DIR .
'/' . $namespace .
'/' . $code
1804 return $this->
id > 0;
1831 return $this->siteId;
1849 return $this->anchor;
1858 return $this->content;
1868 $class = !empty($class) ? $class[0] :
null;
1869 if ($class !==
null)
1884 $this->allowedByTariff = $mark;
1893 $data = parent::getList([
1903 $this->content = $data[
'CONTENT'];
1913 return $this->active;
1922 return $this->public;
1931 return $this->designed;
1940 return $this->access;
1950 if (is_string($letter))
1952 $this->access = $letter;
1963 if ($this->access < $this::ACCESS_W)
1965 $this->error->addError(
1971 $this->active = (boolean)
$active;
1981 return $this->repoId;
1990 static $site =
null;
1997 $site = Site::getList(array(
1999 'ID' => $this->siteId
2013 $path = self::getBlockPath($this->code);
2014 if ($path && file_exists($this->docRoot .
'/' . $path .
'/' . self::PREVIEW_FILE_NAME))
2016 return $path .
'/' . self::PREVIEW_FILE_NAME;
2027 return $this->error;
2041 return Node\Type::getClassName($type);
2050 static $manifests = [];
2052 if (!$this->
id || !$this->designed)
2056 if (array_key_exists($this->
id, $manifests))
2058 return $manifests[$this->id];
2061 $manifests[$this->id] = Block\Designer::parseManifest($this->content);
2063 return $manifests[$this->id];
2073 if (isset($manifest[
'block'][
'name']))
2076 if (!empty($designerBlockManifest[
'nodes']))
2078 foreach ($designerBlockManifest[
'nodes'] as $keyNode => $node)
2080 if (isset($manifest[
'nodes'][$keyNode]))
2084 $node[
'code'] = $keyNode;
2085 $class = Node\Type::getClassName($node[
'type']);
2086 if (isset($node[
'type']) && class_exists($class))
2088 $node[
'handler'] = call_user_func(
2094 $manifest[
'nodes'][$keyNode] = $node;
2098 if (!empty($designerBlockManifest[
'style']))
2100 $manifest[
'style'][
'nodes'] = array_merge(
2101 $designerBlockManifest[
'style'],
2102 $manifest[
'style'][
'nodes']
2117 public function getManifest($extended =
false, $missCache =
false, array $params = array())
2119 static $manifestStore = array();
2123 isset($manifestStore[$this->code])
2127 !isset($manifestStore[$this->code][
'disableCache']) ||
2128 $manifestStore[$this->code][
'disableCache'] !==
true
2140 else if ($path = self::getBlockPath($this->code))
2143 $includeDesc =
function($path)
2146 $manifest = include $path .
'/.description.php';
2147 $manifest[
'timestamp'] = file_exists($path .
'/block.php')
2148 ? filectime($path .
'/block.php')
2153 $manifest = $includeDesc($this->docRoot . $path);
2157 if (isset($manifest[
'block'][
'name']))
2161 isset($manifest[
'block'][
'subtype'])
2163 !isset($params[
'miss_subtype'])
2164 || $params[
'miss_subtype'] !==
true
2168 $subtypes = $manifest[
'block'][
'subtype'];
2169 if (!is_array($subtypes))
2171 $subtypes = [$subtypes];
2174 foreach ($subtypes as $subtype)
2176 $subtypeClass =
'\\Bitrix\\Landing\\Subtype\\';
2177 $subtypeClass .= $subtype;
2178 if (class_exists($subtypeClass))
2180 $manifest = $subtypeClass::prepareManifest(
2183 isset($manifest[
'block'][
'subtype_params'])
2184 ? (array)$manifest[
'block'][
'subtype_params']
2191 foreach ([
'cards',
'nodes',
'attrs',
'menu'] as $code)
2193 if (!isset($manifest[$code]) || !is_array($manifest[$code]))
2195 $manifest[$code] = array();
2199 foreach ($manifest[
'nodes'] as $keyNode => &$node)
2201 if (is_callable($node) && !$this->repoId)
2205 $node[
'code'] = $keyNode;
2206 $class = Node\Type::getClassName($node[
'type']);
2207 if (isset($node[
'type']) && class_exists($class))
2209 $node[
'handler'] = call_user_func(array(
2213 if (method_exists($class,
'prepareManifest'))
2215 $node = call_user_func_array(array(
2223 if (!is_array($node))
2225 unset($manifest[
'nodes'][$keyNode]);
2231 unset($manifest[
'nodes'][$keyNode]);
2236 foreach ($manifest[
'attrs'] as $keyNode => &$node)
2238 if (is_callable($node) && !$this->repoId)
2245 if (isset($manifest[
'callbacks']) && is_array($manifest[
'callbacks']))
2247 $callbacks = array();
2248 foreach ($manifest[
'callbacks'] as $code => $callback)
2250 $callbacks[mb_strtolower($code)] = $callback;
2252 $manifest[
'callbacks'] = $callbacks;
2255 if (!isset($manifest[
'namespace']))
2260 isset($manifest[
'style'])
2262 isset($manifest[
'style'][
'block'])
2263 && isset($manifest[
'style'][
'nodes'])
2264 && count($manifest[
'style']) == 2
2268 $manifest[
'style'] = [
2270 'nodes' => is_array($manifest[
'style'])
2271 ? $manifest[
'style']
2276 !isset($manifest[
'style'])
2277 || !is_array($manifest[
'style'])
2280 $manifest[
'style'] = [
2288 !is_array($manifest[
'style'][
'block'])
2289 || empty($manifest[
'style'][
'block'])
2292 $manifest[
'style'][
'block'] = [
'type' => self::DEFAULT_WRAPPER_STYLE];
2297 foreach ($manifest[
'style'][
'nodes'] as $selector => $styleNode)
2299 if (!isset($manifest[
'nodes'][$selector]) && isset($styleNode[
'type']) && is_array($styleNode))
2301 $styleNodes[$selector] = is_array($styleNode[
'type']) ? $styleNode[
'type'] : [$styleNode[
'type']];
2304 $styleNodes[
'#wrapper'] = is_array($manifest[
'style'][
'block'][
'type'])
2305 ? $manifest[
'style'][
'block'][
'type']
2306 : [$manifest[
'style'][
'block'][
'type']];
2308 foreach ($styleNodes as $selector => $type)
2312 $manifest[
'nodes'][$selector] = [
2313 'type' => Node\Type::STYLE_IMAGE,
2314 'code' => $selector,
2320 $manifest[
'code'] = $this->code;
2324 $manifest = array();
2331 $manifestStore[$this->code] = $manifest;
2336 isset($manifest[
'lang']) &&
2337 isset($manifest[
'lang_original']) &&
2338 is_array($manifest[
'lang'])
2343 $langPortal = LANGUAGE_ID;
2344 if (in_array($langPortal, [
'ru',
'kz',
'by']))
2348 $langArray = $manifest[
'lang'];
2349 $langOrig = $manifest[
'lang_original'];
2350 if (isset($langArray[$langPortal]))
2352 $lang = $langArray[$langPortal];
2355 $langOrig != $langPortal &&
2356 isset($langArray[
'en'])
2359 $lang = $langArray[
'en'];
2369 unset($manifest[
'lang']);
2383 foreach ($manifest as $key => &$value)
2385 if (is_array($value))
2391 isset($lang[$value])
2394 $value = $lang[$value];
2406 static $manifests = array();
2408 if (!is_string($code))
2413 if (preg_match(
'/[^a-z0-9_.:-]+/i', $code))
2418 if (isset($manifests[$code]))
2420 return $manifests[$code];
2423 $manifests[$code] = array();
2426 if (mb_strpos($code,
':') !==
false)
2428 [$namespace, $code] = explode(
':', $code);
2431 if ($path = self::getBlockPath($code ,$namespace))
2435 $manifests[$code] = include
$docRoot . $path .
'/.description.php';
2438 return $manifests[$code];
2448 static $asset = array();
2450 if (!is_string($type))
2455 if (!isset($asset[$this->code]))
2457 $asset[$this->code] = array(
2469 else if ($path = self::getBlockPath($this->code))
2471 $manifest = include $this->docRoot . $path .
'/.description.php';
2472 $manifest[
'timestamp'] = file_exists($this->docRoot . $path .
'/.description.php')
2473 ? filectime($this->docRoot . $path .
'/.description.php')
2477 if (isset($manifest[
'block'][
'namespace']))
2479 $classFile = self::BLOCKS_DIR;
2480 $classFile .=
'/' . $manifest[
'block'][
'namespace'] .
'/';
2481 $classFile .= $this->code .
'/class.php';
2482 $classFile = \getLocalPath($classFile);
2485 $asset[$this->code][
'class'][] = $this->docRoot . $classFile;
2491 isset($manifest[
'block'][
'subtype']) &&
2493 !isset($params[
'miss_subtype']) ||
2494 $params[
'miss_subtype'] !==
true
2498 $subtypes = $manifest[
'block'][
'subtype'];
2499 if (!is_array($subtypes))
2501 $subtypes = [$subtypes];
2504 foreach ($subtypes as $subtype)
2506 $subtypeClass =
'\\Bitrix\\Landing\\Subtype\\';
2507 $subtypeClass .= $subtype;
2508 if (class_exists($subtypeClass))
2510 $manifest = $subtypeClass::prepareManifest(
2513 isset($manifest[
'block'][
'subtype_params'])
2514 ? (array)$manifest[
'block'][
'subtype_params']
2521 foreach (array_keys($asset[$this->code]) as $ass)
2524 isset($manifest[
'assets'][$ass]) &&
2525 !empty($manifest[
'assets'][$ass])
2528 foreach ($manifest[
'assets'][$ass] as $file)
2530 if (!is_string($file))
2536 $asset[$this->code][$ass][] = trim($file);
2541 in_array($file, $this->allowedExtensions)
2544 $asset[$this->code][$ass][] = trim($file);
2547 $asset[$this->code][$ass] = array_unique($asset[$this->code][$ass]);
2552 if (isset($path) && $path)
2555 $file = $path .
'/' . ($this->metaData[
'DESIGNER_MODE'] ?
'design_' :
'') . self::CSS_FILE_NAME;
2556 if (file_exists($this->docRoot . $file))
2558 $asset[$this->code][
'css'][] = $file;
2560 $file = $path .
'/' . self::JS_FILE_NAME;
2561 if (file_exists($this->docRoot . $file))
2563 $asset[$this->code][
'js'][] = $file;
2569 if (!empty($designerBlockManifest[
'assets']))
2571 foreach ($designerBlockManifest[
'assets'] as $key =>
$assets)
2573 $asset[$this->code][$key] = array_merge($asset[$this->code][$key],
$assets);
2574 $asset[$this->code][$key] = array_unique($asset[$this->code][$key]);
2578 return $asset[$this->code][$type] ?? $asset[$this->code];
2624 static $classes = [];
2625 static $calledClasses = [];
2627 if (!isset($classes[$path]))
2630 $beforeClasses = get_declared_classes();
2631 $beforeClassesCount = count($beforeClasses);
2632 include_once($path);
2633 $afterClasses = get_declared_classes();
2634 $afterClassesCount = count($afterClasses);
2637 for ($i = $beforeClassesCount; $i < $afterClassesCount; $i++)
2639 if (is_subclass_of($afterClasses[$i],
'\\Bitrix\\Landing\\LandingBlock'))
2641 $classes[$path] = $afterClasses[$i];
2647 $landingPath = $path .
'@' . $landingId;
2650 if (!isset($calledClasses[$landingPath]))
2652 $calledClasses[$landingPath] =
new $classes[$path];
2653 $calledClasses[$landingPath]->init([
2659 return $calledClasses[$landingPath];
2672 'bitrix:landing.blocks.message',
2677 $blockMesage = ob_get_contents();
2680 return $blockMesage;
2692 global $APPLICATION;
2694 if ($this->dynamicParams)
2699 if (!isset($params[
'wrapper_show']))
2701 $params[
'wrapper_show'] =
true;
2703 if (!isset($params[
'force_unactive']))
2705 $params[
'force_unactive'] =
false;
2707 if (!isset($params[
'skip_system_script']))
2709 $params[
'skip_system_script'] =
false;
2713 $params[
'wrapper_show'] &&
2717 $params[
'wrapper_show'] =
false;
2725 if ($edit || $this->active || $params[
'force_unactive'])
2727 $assets = Assets\Manager::getInstance();
2728 if ($css = $this->
getCSS())
2732 if ($ext = $this->
getExt())
2736 if (!$edit || !$this->repoId)
2738 if ($js = $this->
getJS())
2744 foreach ($this->
getClass() as $class)
2747 if ($classBlock->beforeView($this) ===
false)
2755 if ($edit && !$params[
'skip_system_script'])
2763 !$params[
'skip_system_script'] &&
2764 defined(
'LANDING_DEVELOPER_MODE') &&
2765 LANDING_DEVELOPER_MODE ===
true
2768 if (!isset($manifest))
2772 if (isset($this->metaData[
'DATE_MODIFY']))
2774 $modifyTime = $this->metaData[
'DATE_MODIFY']->getTimeStamp();
2780 if ($modifyTime < $manifest[
'timestamp'])
2784 Update\Block::executeStep([
2786 ], $count, $limit, $paramsUpdater = []);
2792 if (!\
Bitrix\Main\ModuleManager::isModuleInstalled(
'bitrix24'))
2794 if (mb_strpos($this->content,
'/upload/') !==
false)
2796 $this->content = preg_replace(
2797 '#"//[^\'^"]+/upload/#',
2804 if (mb_strpos($this->content,
'srcset="') !==
false)
2806 $this->content = str_replace(
2808 'data-srcset-bad="',
2812 if (mb_strpos($this->content,
'2x)') !==
false)
2814 $this->content = preg_replace(
2815 "#(, url\('[^'^\"]+'\) 2x)#",
2824 if ($params[
'wrapper_show'])
2835 ? \htmlspecialcharsbx($this->anchor)
2841 $anchor =
'block' . rand(10000, 100000);
2843 $classFromCode =
'block-' . $this->code;
2844 $classFromCode = preg_replace(
'/([^a-z0-9-])/i',
'-', $classFromCode);
2845 $classFromCode =
' ' . $classFromCode;
2847 if ($landing && $landing->getPreviewMode())
2849 $content .=
"<a id=\"editor{$this->getId()}\"></a>";
2852 ($edit ?
'data-id="' . $this->
id .
'" ' :
'') .
2853 (($edit && isset($manifest[
'block'][
'subtype'])) ?
'data-subtype="' . $manifest[
'block'][
'subtype'] .
'" ' :
'') .
2854 'class="block-wrapper' .
2855 (!$this->active ?
' landing-block-deactive' :
'') .
2856 ($this->metaData[
'DESIGNER_MODE'] ?
' landing-designer-block-mode' :
'') .
2868 if (mb_strpos($this->content,
'#requisiteCompanyTitle') !==
false)
2870 $replace = Connector\Crm::getReplaceRequisiteCompanyNameForContent($landing->getXmlId());
2872 array_keys($replace),
2873 array_values($replace),
2882 if ($manifest ??
null)
2885 !isset($manifest[
'requiredUserAction']) &&
2886 $this->runtimeRequiredUserAction
2889 $manifest[
'requiredUserAction'] = $this->runtimeRequiredUserAction;
2891 $sections = (array)($manifest[
'block'][
'section'] ??
null);
2892 $designerRepository = $this->metaData[
'DESIGNER_MODE'] ? \Bitrix\Landing\Block\Designer::getRepository() : [];
2897 ?
'block' . $this->parentId
2900 $autoPublicationEnabled = Site\Type::isPublicScope() && \CUserOptions::getOption(
'landing',
'auto_publication',
'Y') ===
'Y';
2901 echo
'<script type="text/javascript">'
2902 .
'BX.ready(function(){'
2903 .
'if (typeof BX.Landing.Block !== "undefined")'
2905 .
'new BX.Landing.' . ($this->metaData[
'DESIGNER_MODE'] ?
'DesignerBlock' :
'Block') .
'('
2906 .
'BX("block' . $this->
id .
'"), '
2908 .
'id: ' . $this->
id .
', '
2909 .
'lid: ' . $this->lid .
', '
2910 .
'code: "' . $this->code .
'", '
2911 .
'sections: "' . implode(
',', $sections) .
'", '
2912 .
'repoId: ' . ($this->repoId ? (int)$this->repoId :
"null") .
', '
2913 .
'php: ' . (mb_strpos(
$content,
'<?') !==
false ?
'true' :
'false') .
', '
2914 .
'designed: ' . ($this->designed ?
'true' :
'false') .
', '
2915 .
'active: ' . ($this->active ?
'true' :
'false') .
', '
2916 .
'allowedByTariff: ' . ($this->allowedByTariff ?
'true' :
'false') .
', '
2917 .
'autoPublicationEnabled: ' . ($autoPublicationEnabled ?
'true' :
'false') .
', '
2918 .
'anchor: ' .
'"' . \CUtil::jsEscape(
$anchor) .
'"' .
', '
2919 .
'access: ' .
'"' . $this->access .
'"' .
', '
2920 .
'dynamicParams: ' . Json::encode($this->dynamicParams) .
','
2921 . ($this->metaData[
'DESIGNER_MODE'] ?
'repository: ' . Json::encode($designerRepository) .
',' :
'')
2922 .
'manifest: ' . Json::encode($manifest)
2924 isset($manifest[
'requiredUserAction'])
2925 ?
', requiredUserAction: ' . Json::encode($manifest[
'requiredUserAction'])
2936 $event = new \Bitrix\Main\Event(
'landing',
'onBlockEditView', [
2941 foreach ($event->getResults() as $result)
2943 $content = $result->getParameters();
2956 catch (\ParseError $e)
2958 $errMessage = $this::getMessageBlock([
2961 if ($params[
'wrapper_show'])
2963 echo
'<div id="' .
$anchor .
'" class="block-wrapper' .
2964 (!$this->active ?
' landing-block-deactive' :
'') .
'">' .
2975 elseif ($this->active || $params[
'force_unactive'])
2978 static $sysPagesSites = [];
2980 if (!array_key_exists($this->siteId, $sysPagesSites))
2982 $sysPages = array();
2985 $sysPages[
'@#system_' . $syspage[
'TYPE'] .
'@'] = $syspage[
'LANDING_ID'];
2988 if (!isset($sysPages[
'@#system_mainpage@']))
2990 $currentSite = $this->
getSite();
2991 if ($currentSite[
'LANDING_ID_INDEX'])
2993 $sysPages[
'@#system_mainpage@'] = $currentSite[
'LANDING_ID_INDEX'];
2996 if (!empty($sysPages))
2998 $urls = $landing->getPublicUrl($sysPages);
2999 foreach ($sysPages as $code =>
$lid)
3001 if (isset($urls[
$lid]))
3003 $sysPages[$code] = \htmlspecialcharsbx($urls[$lid]);
3007 unset($sysPages[$code]);
3012 $sysPagesSites[$this->siteId] = $sysPages;
3015 $sysPages = $sysPagesSites[$this->siteId];
3019 $sysPages[
'@' . Connector\Disk::FILE_MASK_HREF .
'@i'] = str_replace(
3025 if (!empty($sysPages))
3028 array_keys($sysPages),
3029 array_values($sysPages),
3034 $event = new \Bitrix\Main\Event(
'landing',
'onBlockPublicView', [
3039 foreach ($event->getResults() as $result)
3041 $content = $result->getParameters();
3054 catch (\ParseError $e)
3059 Assets\PreProcessing::blockViewProcessing($this, $edit);
3069 if ($this->access < $this::ACCESS_W)
3071 $this->error->addError(
3078 foreach ([
'font',
'icon',
'ext'] as $assetCode)
3080 if (isset($this->assets[$assetCode]) && !isset($assets[$assetCode]))
3082 $assets[$assetCode] = $this->assets[$assetCode];
3084 if (isset($assets[$assetCode]) && !$assets[$assetCode])
3086 unset($assets[$assetCode]);
3090 $this->assets = $assets;
3099 return $this->assets;
3110 if (!is_string($content))
3115 if ($this->access < $this::ACCESS_W)
3117 $this->error->addError(
3125 $this->designed =
true;
3127 $this->content = trim($content);
3136 public function save(array $additionalFields = [])
3138 if ($this->access == $this::ACCESS_A)
3140 $this->error->addError(
3148 'SORT' => $this->sort,
3149 'ACTIVE' => $this->active ?
'Y' :
'N',
3150 'ANCHOR' => $this->anchor,
3151 'DELETED' => $this->deleted ?
'Y' :
'N',
3152 'DESIGNED' => $this->designed ?
'Y' :
'N',
3153 'ASSETS' => $this->assets ? $this->assets : null
3155 if ($additionalFields)
3157 $data = array_merge($data, $additionalFields);
3161 $data[
'CONTENT'] = $this->content;
3162 $data[
'SEARCH_CONTENT'] = $this->getSearchContent();
3165 $res = parent::update($this->
id, $data);
3166 $this->error->addFromResult($res);
3167 return $res->isSuccess();
3178 if ($this->access < $this::ACCESS_W)
3180 $this->error->addError(
3186 $res = parent::update($this->
id, array(
3188 'PARENT_ID' =>
null,
3191 $this->error->addFromResult($res);
3192 return $res->isSuccess();
3202 $res = parent::update($this->
id, [
3203 'TPL_CODE' => $meta[
'tpl_code'] ??
null,
3204 'FAVORITE_META' => $meta
3206 $this->error->addFromResult($res);
3207 return $res->isSuccess();
3216 if ($this->access < $this::ACCESS_X)
3218 $this->error->addError(
3226 $res = self::parentDelete($this->
id);
3227 if (!$res->isSuccess())
3229 $this->error->addFromResult($res);
3231 return $res->isSuccess();
3241 if ($this->access < $this::ACCESS_X)
3243 $this->error->addError(
3249 $this->deleted = (boolean) $mark;
3259 $this->sort =
$sort;
3274 $check = !
$anchor || preg_match_all(
'/^[a-z]{1}[a-z0-9\-\_\.\:]+$/i',
$anchor);
3277 $this->error->addError(
3287 $history->push(
'CHANGE_ANCHOR', [
3289 'valueBefore' => $this->anchor,
3305 if ($this->access < $this::ACCESS_W)
3307 $this->error->addError(
3314 $this->sort =
$sort;
3315 Internals\BlockTable::update($this->
id, array(
3341 $res = parent::getList([
3349 if ($row = $res->fetch())
3351 $params = $row[
'SOURCE_PARAMS'];
3357 $params = $this->dynamicParams;
3368 private function dynamicLinkReplacer(array $data, array $replace)
3370 foreach ($data as $key => $value)
3372 if (is_array($value))
3374 $data[$key] = $this->dynamicLinkReplacer($value, $replace);
3378 $data[$key] = str_replace(
3379 array_keys($replace),
3380 array_values($replace),
3385 unset($key, $value);
3398 if ($this->access < $this::ACCESS_W)
3400 $this->error->addError(
3408 isset($params[
'linkReplace']) &&
3409 is_array($params[
'linkReplace'])
3412 $sourceParams = $this->dynamicLinkReplacer(
3414 $params[
'linkReplace']
3418 $paramsBefore = $this->dynamicParams;
3419 $this->dynamicParams = $sourceParams;
3420 $resUpdate = Internals\BlockTable::update($this->
id, [
3421 'SOURCE_PARAMS' => $sourceParams
3424 if ($resUpdate->isSuccess())
3429 $history->push(
'UPDATE_DYNAMIC', [
3431 'valueBefore' => $paramsBefore,
3432 'valueAfter' => $sourceParams,
3437 unset($sourceParams, $params);
3447 static $sourceList =
null;
3448 static $isDetailDynamic =
null;
3449 static $dynamicElementId =
null;
3450 static $dynamicFilter =
null;
3452 $data = $this->dynamicParams;
3457 if (!$this->active || !$this->content)
3461 if (!is_array($data) || empty($data))
3467 $availableFeature = Restriction\Manager::isAllowed(
3468 'limit_sites_dynamic_blocks',
3469 [
'targetBlockId' => $this->
id]
3471 if (!$availableFeature)
3473 $hackContent = preg_replace(
3475 '<$1 style="display: none;" ',
3481 $this::getMessageBlock([
3482 'HEADER' =>
Loc::getMessage(
'LANDING_BLOCK_MESSAGE_ERROR_DYNAMIC_LIMIT_TITLE'),
3483 'MESSAGE' => Restriction\Manager::getSystemErrorMessage(
'limit_sites_dynamic_blocks'),
3484 'BUTTON' =>
Loc::getMessage(
'LANDING_BLOCK_MESSAGE_ERROR_LIMIT_BUTTON'),
3492 if ($isDetailDynamic ===
null)
3496 if ($dynamicElementId ===
null)
3500 if ($dynamicFilter ===
null)
3507 $cache = new \CPHPCache();
3509 $cacheId =
'block_' . $this->
id .
'_' . $dynamicElementId .
'_';
3510 $cacheId .= md5(serialize($dynamicFilter));
3511 $cachePath =
'/landing/dynamic/' . $this->id;
3512 if ($cache->initCache($cacheTime, $cacheId, $cachePath))
3514 $result = $cache->getVars();
3515 if ($result[
'title'])
3518 Landing\Seo::changeValue(
'title', $result[
'title']);
3520 $rememberAccess = $this->access;
3521 $this->access = $this::ACCESS_W;
3523 $this->access = $rememberAccess;
3524 header(
'X-Bitrix24-Page: dynamic');
3530 $cache->startDataCache($cacheTime, $cacheId, $cachePath);
3541 if ($sourceList ===
null)
3547 $getDetailPage =
function(array $detailPage, $filterId = 0, $elemId = 0)
3549 $filterId = intval($filterId);
3550 $elemId = intval($elemId);
3553 if (isset($detailPage[
'query']))
3555 $query = (array) $detailPage[
'query'];
3556 unset($detailPage[
'query']);
3560 $detailPage = array_merge(
3561 array_fill_keys([
'text',
'href',
'target'],
''),
3564 foreach ($detailPage as $key => &$detailPageItem)
3566 if (!is_array($detailPageItem))
3568 $detailPageItem = trim($detailPageItem);
3570 if (empty($detailPageItem))
3572 unset($detailPage[$key]);
3575 unset($detailPageItem);
3577 if ($filterId && $elemId && $detailPage[
'href'])
3579 $detailPage[
'href'] = str_replace(
3584 $detailPage[
'href'] .=
'_' . $filterId;
3585 $detailPage[
'href'] .=
'_' . $elemId;
3587 else if ($filterId && $elemId)
3589 $detailPage[
'href'] =
'#';
3592 if ($detailPage[
'href'] && $query)
3594 $detailPage[
'query'] = http_build_query($query);
3601 $disableUpdate =
false;
3603 foreach ($data as $cardSelector => $item)
3606 $itemDetail = $cardSelector ==
'wrapper';
3608 !isset($item[
'source']) ||
3609 !isset($item[
'settings']) ||
3610 !isset($item[
'references'])
3616 $sourceId = $item[
'source'];
3617 $settings = $item[
'settings'];
3618 $references = (array)$item[
'references'];
3619 $filterId = isset($item[
'filterId'])
3620 ? intval($item[
'filterId'])
3622 $detailPage = isset($settings[
'detailPage'])
3623 ? (array)$settings[
'detailPage']
3626 isset($settings[
'pagesCount']) &&
3627 $settings[
'pagesCount'] > 0
3629 ? (
int)$settings[
'pagesCount']
3631 $filter = isset($settings[
'source'][
'filter'])
3632 ? (array)$settings[
'source'][
'filter']
3634 $order = isset($settings[
'source'][
'sort'])
3635 ? (array)$settings[
'source'][
'sort']
3637 $additional = isset($settings[
'source'][
'additional'])
3638 ? (array)$settings[
'source'][
'additional']
3640 $stubs = isset($item[
'stubs'])
3641 ? (array)$item[
'stubs']
3645 $isDetailDynamic && $itemDetail &&
3646 $dynamicFilter[
'SOURCE_ID'] == $sourceId
3649 $filter = $dynamicFilter[
'FILTER'];
3651 $sourceParameters = [
3652 'select' => array_values($references),
3653 'filter' => $filter,
3655 'limit' => $pagesCount,
3656 'additional' => $additional
3660 $source = $sourceList->getDataLoader(
3664 'context_filter' => [
3665 'SITE_ID' => $this->siteId,
3666 'LANDING_ID' => $this->lid,
3667 'LANDING_ACTIVE' => $this->landingActive ?
'Y' : [
'Y',
'N']
3673 if (is_object($source))
3676 if ($isDetailDynamic && $itemDetail)
3678 $sourceData = $source->getElementData($dynamicElementId);
3681 $disableUpdate =
true;
3684 $pageTitle = $source->getSeoTitle();
3686 Landing\Seo::changeValue(
'title', $pageTitle);
3691 $sourceData = $source->getElementListData();
3692 $pagesCount = max(1, count($sourceData));
3696 if (!empty($sourceData) && is_array($sourceData))
3699 foreach ($references as $selector => $field)
3701 if (empty($field) || !is_array($field))
3705 if (empty($field[
'id']))
3709 if (mb_strpos($selector,
'@') !==
false)
3711 [$selector,] = explode(
'@', $selector);
3713 if (!isset($update[$selector]))
3715 $update[$selector] = [];
3717 $fieldCode = $field[
'id'];
3718 $fieldType = isset($manifest[
'nodes'][$selector][
'type'])
3719 ? $manifest[
'nodes'][$selector][
'type']
3722 $detailPageData = [];
3723 foreach ($sourceData as $dataItem)
3729 isset($field[
'action'])
3732 switch ($field[
'action'])
3736 $detailPage[
'text'] = isset($field[
'text'])
3739 $update[$selector][] = $detailPageData[$selector][] = $getDetailPage(
3748 if (isset($field[
'link']))
3750 $field[
'link'] = (array) $field[
'link'];
3751 if (isset($field[
'text']))
3753 $field[
'link'][
'text'] = $field[
'text'];
3755 $update[$selector][] = $getDetailPage(
3763 if (isset($dataItem[
'LINK']))
3765 $update[$selector][] = $detailPageData[$selector][] = $getDetailPage([
3766 'text' => isset($field[
'text'])
3769 'href' => $dataItem[
'LINK'],
3770 'target' =>
'_self',
3771 'query' => isset($dataItem[
'_GET']) ? $dataItem[
'_GET'] : []
3779 $value = isset($dataItem[$fieldCode])
3780 ? $dataItem[$fieldCode]
3782 $update[$selector][] = $value;
3785 $detailPageData[$selector][] = $getDetailPage(
3791 else if (isset($dataItem[
'LINK']))
3793 $detailPageData[$selector][] = $getDetailPage([
3794 'text' => isset($field[
'text'])
3797 'href' => $dataItem[
'LINK'],
3798 'target' =>
'_self',
3799 'query' => isset($dataItem[
'_GET']) ? $dataItem[
'_GET'] : []
3805 if (!$update[$selector])
3807 unset($update[$selector]);
3812 isset($field[
'link']) &&
3819 if (!isset($detailPageData[$selector]))
3823 foreach ($update[$selector] as $i => &$value)
3827 $value = (array) $value;
3832 'text' => (string) $value
3836 $detailPageData[$selector][$i] &&
3840 $detailPageData[$selector][$i][
'enabled'] =
true;
3844 $detailPageData[$selector][$i][
'enabled'] =
false;
3846 if ($detailPageData[$selector][$i][
'enabled'])
3848 $value[
'url'] = $detailPageData[$selector][$i];
3856 $rememberAccess = $this->access;
3857 $this->access = $this::ACCESS_W;
3862 $this->access = $rememberAccess;
3869 foreach ($stubs as $selector => $stub)
3871 if (mb_strpos($selector,
'@') !==
false)
3873 [$selector,] = explode(
'@', $selector);
3875 $update[$selector] = array_fill(0, $pagesCount, $stub);
3883 $rememberAccess = $this->access;
3884 $this->access = $this::ACCESS_W;
3888 'sanitize' =>
false,
3889 'skipCheckAffected' =>
true
3894 Assets\PreProcessing::blockSetDynamicProcessing($this);
3896 $this->access = $rememberAccess;
3898 header(
'X-Bitrix24-Page: dynamic');
3901 $cache->endDataCache([
3902 'title' => $pageTitle,
3903 'content' => $this->content
3910 $this->runtimeRequiredUserAction = [
3911 'header' =>
Loc::getMessage(
'LANDING_BLOCK_MESSAGE_ERROR_NO_DATA_TITLE'),
3912 'description' =>
Loc::getMessage(
'LANDING_BLOCK_MESSAGE_ERROR_NO_DATA_TEXT')
3924 $cache->abortDataCache();
3926 $this->deleted =
true;
3945 return $this->runtimeRequiredUserAction;
3954 $this->runtimeRequiredUserAction = $action;
3964 static $doc = array();
3968 isset($doc[$this->
id])
3971 unset($doc[$this->
id]);
3974 if (!isset($doc[$this->
id]))
3976 $doc[$this->id] =
new DOM\Document;
3979 $doc[$this->id]->loadHTML($this->content);
3981 catch (\Exception $e) {}
3984 return $doc[$this->id];
3993 return $this->metaData;
4005 if (!is_string($selector))
4010 if ($this->access < $this::ACCESS_W)
4012 $this->error->addError(
4020 if (isset($manifest[
'cards'][$selector]))
4022 $count = (int)$count;
4024 $resultList = $doc->querySelectorAll($selector);
4025 $resultCount = count($resultList);
4026 if ($count > $resultCount)
4028 for ($i = $resultCount; $i < $count; $i++)
4034 elseif ($count < $resultCount)
4036 for ($i = $resultCount; $i > $count; $i--)
4045 $this->error->addError(
4060 public function cloneCard($selector, $position, $content =
'')
4062 if (!is_string($selector))
4067 if ($this->access < $this::ACCESS_W)
4069 $this->error->addError(
4077 if (isset($manifest[
'cards'][$selector]))
4079 $position = intval($position);
4080 $position = max($position, -1);
4081 $realPosition = max($position, 0);
4083 $resultList = $doc->querySelectorAll($selector);
4084 if (isset($resultList[$realPosition]))
4086 $parentNode = $resultList[$realPosition]->getParentNode();
4087 $refChild = isset($resultList[$position + 1])
4088 ? $resultList[$position + 1]
4093 foreach ($parentNode->getChildNodes() as $child)
4095 if ($child === $refChild)
4102 if ($parentNode && (!$refChild || $haveChild))
4107 $tmpCardName = mb_strtolower(
'tmpcard'.randString(10));
4108 $newChild =
new DOM\Element($tmpCardName);
4109 $newChild->setOwnerDocument($doc);
4114 $newChild = $resultList[$realPosition];
4116 $parentNode->insertBefore(
4126 $history->push(
'ADD_CARD', [
4128 'selector' => $selector,
4129 'position' => $position,
4135 if (isset($tmpCardName))
4139 array(
'<' . $tmpCardName .
'>',
'</' . $tmpCardName .
'>'),
4156 $this->error->addError(
4172 if (!is_string($selector))
4177 if ($this->access < $this::ACCESS_W)
4179 $this->error->addError(
4187 $position = intval($position);
4188 $resultList = $doc->querySelectorAll($selector);
4189 if (isset($resultList[$position]))
4191 $resultList[$position]->setInnerHTML(
4198 $this->error->addError(
4213 if (!is_string($selector))
4219 $position = intval($position);
4220 $resultList = $doc->querySelectorAll($selector);
4221 if (isset($resultList[$position]))
4223 return $resultList[$position]->getOuterHtml();
4236 if (!is_string($selector))
4242 $resultList = $doc->querySelectorAll($selector);
4243 return count($resultList);
4254 if (!is_string($selector))
4259 if ($this->access < $this::ACCESS_W)
4261 $this->error->addError(
4269 $position = intval($position);
4270 if (isset($manifest[
'cards'][$selector]))
4273 $resultList = $doc->querySelectorAll($selector);
4274 if (isset($resultList[$position]))
4276 $resultList[$position]->getParentNode()->removeChild(
4277 $resultList[$position]
4284 $history->push(
'REMOVE_CARD', [
4286 'selector' => $selector,
4287 'position' => $position,
4292 Assets\PreProcessing::blockUpdateNodeProcessing($this);
4298 $this->error->addError(
4312 if ($this->access < $this::ACCESS_W)
4314 $this->error->addError(
4325 foreach ($manifest[
'nodes'] as $selector => $node)
4327 if (isset($data[$selector]))
4329 $resultList = $doc->querySelectorAll($selector);
4331 foreach ($data[$selector] as $pos => $value)
4333 $value = trim($value[
'tagName'] ?? $value);
4335 preg_match(
'/^[a-z0-9]+$/i', $value) &&
4336 isset($resultList[$pos]))
4338 $valueBefore[$selector][$pos] = $resultList[$pos]->getNodeName();
4339 $resultList[$pos]->setNodeName($value);
4348 $history->push(
'CHANGE_NODE_NAME_ACTION', [
4350 'valueBefore' => $valueBefore,
4351 'valueAfter' => $data,
4369 if ($this->access < $this::ACCESS_W)
4371 $this->error->addError(
4383 $manifest[
'nodes'] = $manifest[
'nodes'] ?? [];
4384 foreach ($manifest[
'nodes'] as $selector => $node)
4388 if (isset($data[$selector]))
4390 if (!is_array($data[$selector]))
4392 $data[$selector] = array(
4396 $dataSelector = $data[$selector];
4399 if (!$isFind && ($node[
'isWrapper'] ??
false) ===
true)
4401 if (isset($data[
'#wrapper']) && $node[
'type'] ===
'styleimg')
4403 if (!is_array($data[
'#wrapper']))
4405 $data[
'#wrapper'] = array(
4409 $dataSelector = $data[
'#wrapper'];
4413 $selector =
'#wrapper';
4414 if (!is_array($data[$selector]))
4416 $data[$selector] = array(
4420 $dataSelector = $data[$selector];
4424 if ($node[
'type'] ===
'img')
4431 $affected[$selector] = call_user_func_array(array(
4432 Node\Type::getClassName($node[
'type']),
4444 if (isset($additional[
'appendMenu']) && $additional[
'appendMenu'])
4446 $export = $this->export();
4450 $additional[
'appendMenu'] =
false;
4452 $manifest[
'menu'] = $manifest[
'menu'] ?? [];
4453 foreach ($manifest[
'menu'] as $selector => $node)
4455 if (isset($data[$selector]) && is_array($data[$selector]))
4457 if (isset($data[$selector][0][0]))
4459 $data[$selector] = array_shift($data[$selector]);
4461 if ($additional[
'appendMenu'] && isset($export[
'menu'][$selector]))
4463 $data[$selector] = array_merge(
4464 $export[
'menu'][$selector],
4469 $resultList = $doc->querySelectorAll($selector);
4470 foreach ($resultList as $pos => $resultNode)
4472 $parentNode = $resultNode->getParentNode();
4475 $parentNode->setInnerHtml(
4491 if (!($additional[
'skipCheckAffected'] ??
false) &&
Manager::getOption(
'strict_verification_update') ===
'Y')
4497 foreach ($affected as $selector => $resultItem)
4499 $selector = trim($selector,
'.');
4504 '/class="[^"]*[\s]+(' . $selector .
')[\s"]+[^"]*"[^>]*>/s',
4505 function($match) use(&$pos)
4507 return str_replace($match[1], $match[1] .
'@' . ($pos++), $match[0]);
4512 if (is_array($resultItem))
4514 foreach ($resultItem as $pos => $affectedItem)
4516 if ($affectedItem[
'content'] ??
null)
4518 $affectedItem[
'content'] = str_replace(
'/',
'\/', $affectedItem[
'content']);
4519 $mask =
'/class="[^"]*[\s]+' . $selector .
'@' . $pos .
'[\s"]+[^"]*"[^>]*>' . $affectedItem[
'content'] .
'<\//s';
4520 $domCorrect = preg_match_all($mask,
$content);
4532 $this->error->addError(
4533 'INCORRECT_AFFECTED',
4540 Assets\PreProcessing::blockUpdateNodeProcessing($this);
4554 if (!is_array($data) || !isset($manifestNode[$level]))
4560 $rootSelector = $manifestNode[$level];
4563 isset($rootSelector[
'ulClassName']) &&
4564 isset($rootSelector[
'liClassName']) &&
4565 isset($rootSelector[
'aClassName']) &&
4566 is_string($rootSelector[
'ulClassName']) &&
4567 is_string($rootSelector[
'liClassName']) &&
4568 is_string($rootSelector[
'aClassName'])
4571 foreach ($data as $menuItem)
4574 isset($menuItem[
'text']) && is_string($menuItem[
'text']) &&
4575 isset($menuItem[
'href']) && is_string($menuItem[
'href'])
4578 if ($menuItem[
'href'] ===
'page:#landing0')
4580 $res = Landing::addByTemplate(
4584 'TITLE' => $menuItem[
'text']
4587 if ($res->isSuccess())
4589 $menuItem[
'href'] =
'#landing' . $res->getId();
4592 if (isset($menuItem[
'target']) && is_string($menuItem[
'target']))
4594 $target = $menuItem[
'target'];
4600 $htmlContent .=
'<li class="' . \htmlspecialcharsbx($rootSelector[
'liClassName']) .
'">';
4601 $htmlContent .=
'<a href="' . \htmlspecialcharsbx($menuItem[
'href']) .
'" target="' . $target .
'"
4602 class="' . \htmlspecialcharsbx($rootSelector[
'aClassName']) .
'">';
4603 $htmlContent .= \htmlspecialcharsbx($menuItem[
'text']);
4604 $htmlContent .=
'</a>';
4605 if (isset($menuItem[
'children']))
4608 $menuItem[
'children'],
4613 $htmlContent .=
'</li>';
4618 $htmlContent =
'<ul class="' . \htmlspecialcharsbx($rootSelector[
'ulClassName']) .
'">' .
4622 else if ($level ==
'root')
4624 $htmlContent =
'<ul class="' . \htmlspecialcharsbx($rootSelector[
'ulClassName']) .
'"></ul>';
4628 return $htmlContent;
4638 if ($this->access < $this::ACCESS_W)
4640 $this->error->addError(
4649 foreach ($data as $selector => $item)
4651 $cardManifest = $manifest[
'cards'][$selector];
4653 $cardContent = array();
4655 for ($i = 0; $i < $cardCount; $i++)
4664 isset($item[
'source']) &&
4665 is_array($item[
'source'])
4668 $newContent = array();
4669 foreach ($item[
'source'] as $i => $source)
4671 $type = isset($source[
'type'])
4673 : self::CARD_SYM_CODE;
4674 $value = isset($source[
'value'])
4679 $type == self::CARD_SYM_CODE &&
4680 isset($cardContent[$value])
4683 $newContent[$i] = $cardContent[$value];
4687 $type ==
'preset' &&
4688 isset($cardManifest[
'presets'][$value][
'html'])
4691 $newContent[$i] = $cardManifest[
'presets'][$value][
'html'];
4695 $newContent[$i] =
'';
4698 $newContent = trim(implode(
'', $newContent));
4702 $resultList = $dom->querySelectorAll($selector);
4703 if (isset($resultList[0]))
4705 $resultList[0]->getParentNode()->setInnerHtml(
4716 isset($item[
'values']) &&
4717 is_array($item[
'values'])
4720 $updNodes = array();
4721 foreach ($item[
'values'] as $upd)
4727 if(mb_strpos($sel,
'@'))
4729 [$sel, $pos] = explode(
'@', $sel);
4731 if (!isset($updNodes[$sel]))
4733 $updNodes[$sel] = array();
4739 if (!empty($updNodes))
4757 foreach ($node->getChildNodesArray() as $nodeChild)
4759 if ($nodeChild instanceof DOM\
Element)
4761 $styles = DOM\StyleInliner::getStyle($nodeChild,
false);
4762 if (!empty($styles))
4764 foreach ($styleToRemove as $remove)
4766 if (!is_array($remove))
4768 $remove = [$remove => $remove];
4770 $styles = array_diff_key($styles, $remove);
4772 DOM\StyleInliner::setStyle($nodeChild, $styles);
4775 $node = $this->
removeStyle($nodeChild, $styleToRemove);
4788 if ($this->access < $this::ACCESS_V)
4790 $this->error->addError(
4803 foreach ((array)$data as $selector => $item)
4805 if (mb_strpos($selector,
'@') !==
false)
4807 [$selector, $position] = explode(
'@', $selector);
4813 if ($selector ===
'#wrapper')
4815 $selector =
'#block' . $this->id;
4819 if (!isset($positions[$selector]))
4821 $positions[$selector] = [];
4823 $positions[$selector][] = (int)$position;
4825 $data[$selector] = $item;
4829 $wrapper =
'#' . $this->
getAnchor($this->
id);
4832 $styles = $manifest[
'style'][
'nodes'];
4833 $styles[$wrapper] = $manifest[
'style'][
'block'];
4834 foreach ($styles as $selector => $node)
4836 if (isset($data[$selector]))
4839 if (!is_array($data[$selector]))
4841 $data[$selector] = [
4846 if (!isset($data[$selector][
'classList']))
4848 $data[$selector] = [
4849 'classList' => $data[$selector]
4852 if (!isset($data[$selector][
'affect']))
4854 $data[$selector][
'affect'] = [];
4857 if ($selector === $wrapper)
4859 $nodesArray = $doc->getChildNodesArray();
4860 $resultList = [array_pop($nodesArray)];
4865 $resultList = $doc->querySelectorAll($selector);
4867 foreach ($resultList as $pos => $resultNode)
4869 $relativeSelector = $selector;
4870 if (isset($positions[$selector]))
4872 if (!in_array($pos, $positions[$selector],
true))
4876 $relativeSelector .=
'@' . $pos;
4879 $contentBefore = $resultNode->getOuterHTML();
4883 if ((
int)$resultNode->getNodeType() === $resultNode::ELEMENT_NODE)
4885 $resultNode->setClassName(
4886 implode(
' ', $data[$relativeSelector][
'classList'])
4891 if (!empty($data[$relativeSelector][
'affect']))
4895 $data[$relativeSelector][
'affect']
4900 if (!empty($data[$relativeSelector][
'style']))
4902 $stylesInline = DOM\StyleInliner::getStyle($resultNode,
false);
4903 DOM\StyleInliner::setStyle(
4905 array_merge($stylesInline, $data[$relativeSelector][
'style'])
4908 else if (preg_match_all(
'/background-image:.*;/i', $resultNode->getAttribute(
'style'), $matches))
4910 $resultNode->removeAttribute(
'style');
4911 $resultNode->setAttribute(
'style', implode(
'', $matches[0]));
4917 $history->push(
'EDIT_STYLE', [
4919 'selector' => $selector,
4920 'isWrapper' => ($selector === $wrapper),
4921 'position' => $position >= 0 ? (
int)$pos : -1,
4922 'affect' => $data[$relativeSelector][
'affect'],
4923 'contentBefore' => $contentBefore,
4924 'contentAfter' => $resultNode->getOuterHTML(),
4933 Assets\PreProcessing::blockUpdateClassesProcessing($this);
4945 foreach ($mixed as $itemSelector => $item)
4947 if (!is_string($itemSelector))
4949 $itemSelector = $selector;
4952 isset($item[
'attrs']) &&
4953 is_array($item[
'attrs'])
4956 self::collectAllowedAttrs($item[
'attrs'], $allowed, $itemSelector);
4959 isset($item[
'additional'][
'attrsType']) ||
4960 $itemSelector ===
'additional'
4963 $manifestAttrs = self::getAttrs();
4964 $attrs = $manifestAttrs[
'bitrix'][
'attrs'];
4965 if (is_array($item[
'additional'][
'attrsType']))
4967 foreach ($attrs as $attr) {
4968 $allowed[$itemSelector][] = $attr[
'attribute'];
4971 if (is_array($item[
'attrsType']))
4973 foreach ($attrs as $attr) {
4974 $allowed[
'#wrapper'][] = $attr[
'attribute'];
4979 isset($item[
'additional'][
'attrs']) &&
4980 is_array($item[
'additional'][
'attrs'])
4983 self::collectAllowedAttrs($item[
'additional'][
'attrs'], $allowed, $itemSelector);
4986 isset($item[
'additional']) &&
4987 is_array($item[
'additional'])
4990 self::collectAllowedAttrs($item[
'additional'], $allowed, $itemSelector);
4993 isset($item[
'attribute']) &&
4994 is_string($item[
'attribute'])
4998 isset($item[
'selector']) &&
4999 is_string($item[
'selector'])
5002 $itemSelector = trim($item[
'selector']);
5006 if (!isset($allowed[$itemSelector]))
5008 $allowed[$itemSelector] = [];
5010 $allowed[$itemSelector][] = $item[
'attribute'];
5013 else if (is_array($item))
5015 self::collectAllowedAttrs($item, $allowed, $itemSelector);
5027 if ($this->access < $this::ACCESS_W)
5029 $this->error->addError(
5038 $wrapper =
'#' . $this->
getAnchor($this->
id);
5042 self::collectAllowedAttrs($manifest[
'style'][
'nodes'], $allowedAttrs);
5043 self::collectAllowedAttrs($manifest[
'attrs'], $allowedAttrs);
5044 self::collectAllowedAttrs($manifest[
'cards'], $allowedAttrs);
5045 self::collectAllowedAttrs($manifest[
'style'][
'block'], $allowedAttrs);
5051 foreach ($allowedAttrs as $selector => $allowed)
5054 if ((isset($data[$selector]) && is_array($data[$selector])) || isset($data[$wrapper]) )
5057 if ($selector ===
'#wrapper')
5059 $selector = $wrapper;
5061 if ($selector == $wrapper)
5063 $nodesArray = $doc->getChildNodesArray();
5064 $resultList = [array_pop($nodesArray)];
5069 $resultList = $doc->querySelectorAll($selector);
5072 foreach ($data[$selector] as $attrKey => $attrData)
5075 if (!($attrKey == (
string)(
int)$attrKey))
5077 $attrData = [$attrKey => $attrData];
5080 if (!is_array($attrData))
5085 foreach ($attrData as $key => $value)
5087 if (!in_array($key, $allowed))
5091 $key = \htmlspecialcharsbx($key);
5092 $value = is_array($value) ? json_encode($value) : $value;
5095 foreach ($resultList as $pos => $resultNode)
5098 if ($attrKey == -1 || $attrKey == $pos)
5100 $valueBefore = $resultNode->getAttribute($key);
5102 $resultNode->setAttribute($key, $value);
5106 $history->push(
'EDIT_ATTRIBUTES', [
5108 'selector' => $selector,
5109 'isWrapper' => ($selector === $wrapper),
5110 'attribute' => $key,
5111 'position' => (
int)$attrKey,
5112 'valueBefore' => $valueBefore,
5113 'valueAfter' => $value,
5135 if (mb_strpos(
$content,
'#breadcrumb#') !==
false)
5159 $strChainTemplate = getLocalPath(
'templates/' . $tplId .
'/chain_template.php');
5161 if (file_exists($strChainTemplate))
5163 echo include $strChainTemplate;
5165 $breadcrumb = ob_get_contents();
5174 if (mb_strpos(
$content,
'#title#') !==
false)
5193 if (!is_array($code))
5195 $code = array($code);
5197 $res = parent::getList(array(
5205 while ($row = $res->fetch())
5207 self::parentDelete($row[
'ID']);
5216 private static function parentDelete($id)
5218 return parent::delete($id);
5228 $res = parent::getList([
5236 while ($row = $res->fetch())
5238 parent::delete($row[
'ID']);
5246 public function getSearchContent()
5248 $manifest = $this->getManifest();
5252 if (isset($manifest[
'nodes']))
5254 foreach ($manifest[
'nodes'] as $selector => $node)
5257 $class = NodeType::getClassName($node[
'type']);
5258 if (is_callable([$class,
'getSearchableNode']))
5260 $search = array_merge($search, $class::getSearchableNode($this, $selector));
5265 return $search ? implode(
' ', $search) :
'';
5273 public function export(array $params = [])
5285 if (!isset($params[
'clear_form']))
5287 $params[
'clear_form'] =
true;
5291 if (isset($manifest[
'cards']))
5293 foreach ($manifest[
'cards'] as $selector => $node)
5295 $cards[$selector] = [
5298 $resultList = $doc->querySelectorAll($selector);
5299 $resultListCnt = count($resultList);
5300 foreach ($resultList as $pos => $result)
5302 $cards[$selector][
'source'][$pos] = array(
5303 'value' => $result->getAttribute(
'data-card-preset'),
5304 'type' => Block::PRESET_SYM_CODE
5306 if (!$cards[$selector][
'source'][$pos][
'value'])
5309 if (mb_strpos($this->
getCode(),
'menu') !==
false)
5311 $cards[$selector][
'source'][$pos][
'value'] = $resultListCnt > 0 ? 1 : 0;
5315 $cards[$selector][
'source'][$pos][
'value'] = 0;
5317 $cards[$selector][
'source'][$pos][
'type'] = Block::CARD_SYM_CODE;
5322 isset($node[
'additional'][
'attrs']) &&
5323 is_array($node[
'additional'][
'attrs'])
5326 foreach ($node[
'additional'][
'attrs'] as $attr)
5328 if (isset($attr[
'attribute']))
5330 if (!isset($allAttrs[$selector]))
5332 $allAttrs[$selector] = [];
5334 $allAttrs[$selector][] = $attr[
'attribute'];
5341 if (isset($manifest[
'nodes']))
5343 foreach ($manifest[
'nodes'] as $selector => $node)
5346 $class = NodeType::getClassName($node[
'type']);
5347 $nodes[$selector] = $class::getNode($this, $selector);
5350 if (isset($manifest[
'menu']))
5353 $exportMenu =
function($resultList) use(&$exportMenu)
5361 foreach ($resultList->getChildNodesArray() as $pos => $node)
5364 if ($node->getNodeName() ==
'LI')
5366 foreach ($node->getChildNodesArray() as $nodeInner)
5368 if ($nodeInner->getNodeName() ==
'A')
5370 $menu[$pos][
'text'] = trim($nodeInner->getTextContent());
5371 $menu[$pos][
'href'] = trim($nodeInner->getAttribute(
'href'));
5372 $menu[$pos][
'target'] = trim($nodeInner->getAttribute(
'target'));
5374 else if ($nodeInner->getNodeName() ==
'UL')
5376 $menu[$pos][
'children'] = $exportMenu($nodeInner);
5385 return array_values($menu);
5387 foreach ($manifest[
'menu'] as $selector => $menuNode)
5389 $menu[$selector] = $exportMenu($doc->querySelector($selector));
5393 if (isset($manifest[
'style'][
'nodes']))
5395 foreach ($manifest[
'style'][
'nodes'] as $selector => $node)
5397 $nodeStyle = Node\Style::getStyle($this, $selector);
5400 $styles[$selector] = $nodeStyle;
5404 isset($node[
'additional'][
'attrs']) &&
5405 is_array($node[
'additional'][
'attrs'])
5408 foreach ($node[
'additional'][
'attrs'] as $attr)
5410 if (isset($attr[
'attribute']))
5412 if (!isset($allAttrs[$selector]))
5414 $allAttrs[$selector] = [];
5416 $allAttrs[$selector][] = $attr[
'attribute'];
5423 if (!empty($manifest[
'style'][
'block']))
5425 $selector =
'#wrapper';
5426 $wrapperStyle = Node\Style::getStyle($this, $selector);
5429 $styles[$selector] = $wrapperStyle;
5434 isset($manifest[
'style'][
'block'][
'additional'][
'attrs']) &&
5435 is_array($manifest[
'style'][
'block'][
'additional'][
'attrs'])
5438 $selector =
'#wrapper';
5439 foreach ($manifest[
'style'][
'block'][
'additional'][
'attrs'] as $attr)
5441 if (isset($attr[
'attribute']))
5443 if (!isset($allAttrs[$selector]))
5445 $allAttrs[$selector] = [];
5447 $allAttrs[$selector][] = $attr[
'attribute'];
5452 if (isset($manifest[
'attrs']))
5454 foreach ($manifest[
'attrs'] as $selector => $item)
5456 if (isset($item[
'attribute']))
5458 if (!isset($allAttrs[$selector]))
5460 $allAttrs[$selector] = [];
5462 $allAttrs[$selector][] = $item[
'attribute'];
5464 else if (is_array($item))
5466 foreach ($item as $itemAttr)
5468 if (isset($itemAttr[
'attribute']))
5470 if (!isset($allAttrs[$selector]))
5472 $allAttrs[$selector] = [];
5474 $allAttrs[$selector][] = $itemAttr[
'attribute'];
5482 $params[
'clear_form'] &&
5483 isset($allAttrs[
'.bitrix24forms'])
5486 unset($allAttrs[
'.bitrix24forms']);
5490 if (isset($allAttrs[
'#wrapper']))
5492 $allAttrsNew[
'#wrapper'] = [];
5493 $nodesArray = $doc->getChildNodesArray();
5494 $resultList = [array_pop($nodesArray)];
5495 foreach ($resultList as $pos => $result)
5497 foreach ($allAttrs[
'#wrapper'] as $attrKey)
5499 if (!isset($allAttrsNew[
'#wrapper'][$pos]))
5501 $allAttrsNew[
'#wrapper'][$pos] = [];
5503 $allAttrsNew[
'#wrapper'][$pos][$attrKey] = $result->getAttribute($attrKey);
5506 unset($allAttrs[
'#wrapper']);
5508 foreach ($allAttrs as $selector => $attr)
5510 $resultList = $doc->querySelectorAll($selector);
5511 foreach ($resultList as $pos => $result)
5513 if (!isset($allAttrsNew[$selector]))
5515 $allAttrsNew[$selector] = [];
5517 if (!isset($allAttrsNew[$selector][$pos]))
5519 $allAttrsNew[$selector][$pos] = [];
5521 foreach ($attr as $attrKey)
5523 $allAttrsNew[$selector][$pos][$attrKey] = $result->getAttribute($attrKey);
5528 $allAttrs = $allAttrsNew;
5529 unset($allAttrsNew);
5536 'attrs' => $allAttrs,
5537 'dynamic' => $this->dynamicParams
5549 public static function search($query, array $filter = [], array $select = [
'LID'], array $group = [
'LID'])
5553 $filter[
'*%SEARCH_CONTENT'] = $query;
5554 $filter[
'=DELETED'] =
'N';
5556 $res = Internals\BlockTable::getList([
5557 'select' => $select,
5558 'filter' => $filter,
5560 'order' => [
'SORT' =>
'desc']
5562 while ($row = $res->fetch())
5575 public static function add($fields)
5578 !defined(
'LANDING_MUTATOR_MODE') ||
5579 LANDING_MUTATOR_MODE !==
true
5582 throw new \Bitrix\Main\SystemException(
5583 'Disabled for direct access.'
5588 return parent::add($fields);
5598 public static function update($id, $fields = array())
5601 !defined(
'LANDING_MUTATOR_MODE') ||
5602 LANDING_MUTATOR_MODE !==
true
5605 throw new \Bitrix\Main\SystemException(
5606 'Disabled for direct access.'
5611 return parent::update(
$id, $fields);
5620 public static function delete(
$id)
5623 !defined(
'LANDING_MUTATOR_MODE') ||
5624 LANDING_MUTATOR_MODE !== true
5627 throw new \Bitrix\Main\SystemException(
5628 'Disabled for direct access.'
5633 return parent::delete(
$id);
5644 return parent::getList([
5648 '=TPL_CODE' => $tplCode
5664 !defined(
'LANDING_MUTATOR_MODE') ||
5665 LANDING_MUTATOR_MODE !==
true
5668 throw new \Bitrix\Main\SystemException(
5669 'Disabled for direct access.'
5674 return parent::getList($fields);
5687 Asset::getInstance()->getJs();
5688 Asset::getInstance()->getCss();
5689 Asset::getInstance()->getStrings();
5691 $targetTypeList = array(
'JS',
'CSS');
5692 $CSSList = $JSList = $stringsList = [];
5694 foreach ($targetTypeList as $targetType)
5696 $targetAssetList = Asset::getInstance()->getTargetList($targetType);
5698 foreach ($targetAssetList as $targetAsset)
5700 $assetInfo = Asset::getInstance()->getAssetInfo($targetAsset[
'NAME'], \
Bitrix\Main\
Page\AssetMode::ALL);
5702 if (!empty($assetInfo[
'JS']))
5704 $JSList = array_merge($JSList, $assetInfo[
'JS']);
5707 if (!empty($assetInfo[
'CSS']))
5709 $CSSList = array_merge($CSSList, $assetInfo[
'CSS']);
5712 if (!empty($assetInfo[
'STRINGS']))
5714 $stringsList = array_merge($stringsList, $assetInfo[
'STRINGS']);
5720 'js' => array_unique($JSList),
5721 'css' => array_unique($CSSList),
5722 'strings' => array_unique($stringsList),
5734 public static function isContains(
int $entityId,
string $needed,
bool $isLanding =
false): bool
5739 'CONTENT' =>
'%' . $needed .
'%',
5743 $filter[
'LID'] = $entityId;
5747 $filter[
'ID'] = $entityId;
5749 $res = parent::getList([
5752 'SITE_ID' =>
'LANDING.SITE_ID',
5754 'filter' => $filter,
5756 if ($row = $res->fetch())
5786 $path2Component = \CComponentEngine::MakeComponentPath($componentName);
5787 if ($path2Component !==
'')
5789 $componentPath = getLocalPath(
"components" . $path2Component);
5790 $componentFile = $_SERVER[
"DOCUMENT_ROOT"] . $componentPath .
"/component.php";
5792 return file_exists($componentFile) && is_file($componentFile);
const LOCATION_AFTER_TEMPLATE
getMenuHtml($data, $manifestNode, $level='root')
save(array $additionalFields=[])
getManifest($extended=false, $missCache=false, array $params=array())
getRuntimeRequiredUserAction()
static getList($fields=array())
static getFavorites(?string $tplCode)
adjustCards($selector, $count, &$changed=false)
static getBlockContent($id, $editMode=false, array $params=array())
static getAjaxInitiatedAssets()
static getMessageBlock($params, $template='')
saveAssets(array $assets)
static getNormalizedBlock(string $code)
static removeAsUsed(string $blockCode)
checkDesignedManifest(array $manifest)
static update($id, $fields=array())
static getManifestFile($code)
static getBlockNamespace($code)
static getContentFromRepository(string $code, string $namespace=null)
static getSpecialManifest(string $type)
updateNodes($data, $additional=array())
setCardContent($selector, $position, $content)
const DEFAULT_WRAPPER_STYLE
changeFavoriteMeta(array $meta)
$runtimeRequiredUserAction
saveContent(string $content, $designed=false)
static getRepository($withManifest=false)
saveDynamicParams(array $sourceParams=[], array $params=[])
static getLandingRowByBlockId($id, array $select=array('ID'))
static getBlockPath($code, $namespace=null)
removeStyle(DOM\Node $node, array $styleToRemove)
static collectAllowedAttrs(array $mixed, array &$allowed, $selector=null)
static getRowByBlockId($id, array $select=array('ID'))
static clearRepositoryCache()
updateCards(array $data=array())
const FAVOURITE_BLOCKS_LIMIT_WITH_PREVIEW
setAllowedByTariff(bool $mark)
setRuntimeRequiredUserAction(array $action)
cloneCard($selector, $position, $content='')
static deleteByCode($code)
static fillLanding(Landing $landing, $limit=0, array $params=array())
removeCard($selector, $position)
static createFromRepository(Landing $landing, string $code, array $data=array())
localizationManifest(array &$manifest, array $lang)
static getLastUsed(int $count=15)
getCardContent($selector, $position)
static markAsUsed(string $blockCode)
view($edit=false, \Bitrix\Landing\Landing $landing=null, array $params=array())
static replaceMetaMarkers($content)
static getLandingIdByBlockId($id)
static checkComponentExists(string $componentName)
static isNewBlock($block)
static cloneForEdit(\Bitrix\Landing\Landing $landing)
static isContains(int $entityId, string $needed, bool $isLanding=false)
__construct($id, $data=[], array $params=[])
getDynamicParams($id=null)
static search($query, array $filter=[], array $select=['LID'], array $group=['LID'])
static publicationBlocks(\Bitrix\Landing\Landing $landing)
const FAVOURITE_BLOCKS_LIMIT
static getDownloadLink(string $scope, int $blockId, ?int $fileId=null)
static addToBlock(int $blockId, $fileId, bool $temp=false)
static getFilesFromBlockContent($blockId, $content)
static getFilePath($fileId)
const ENTITY_TYPE_LANDING
static getDynamicFilter()
static isDynamicDetailPage()
static getDynamicElementId()
static createInstance($id, array $params=array())
static getOption($code, $default=null)
static setPageTitle($title, $single=false)
static getTemplateId($siteId=null)
static getUrlFromFile($file)
static blocksPublication(\Bitrix\Landing\Landing $landing, $_591201104=null)
static changeNodeType(array $node, \Bitrix\Landing\Block $block)
static getAppByCode($code)
static get(int $id, bool $active=false, bool $force=false)
static loadLanguageFile($file, $language=null, $normalize=true)
static loadMessages($file)
static getMessage($code, $replace=null, $language=null)
static getList(array $parameters=array())