11 private static $instance;
27 AssetLocation::BEFORE_CSS => [],
28 AssetLocation::AFTER_CSS => [],
29 AssetLocation::AFTER_JS_KERNEL => [],
30 AssetLocation::AFTER_JS => [],
34 private $moduleInfo = [
'CSS' => [],
'JS' => []];
35 private $kernelAsset = [
'CSS' => [],
'JS' => []];
36 private $assetList = [
'CSS' => [],
'SOURCE_CSS' => [],
'JS' => [],
'SOURCE_JS' => []];
37 private $fileList = [
'CSS' => [],
'JS' => []];
38 private $mode = AssetMode::STANDARD;
41 private $xhtmlStyle =
'/';
43 private $optimizeCss =
true;
44 private $optimizeJs =
true;
46 private $headString =
false;
47 private $headScript =
false;
48 private $bodyScript =
false;
49 private $moveJsToBody =
null;
51 private $templateExists =
false;
52 private $siteTemplateID =
'';
53 private $templatePath =
'';
54 private $documentRoot =
'';
55 private $dbType =
'MYSQL';
56 private $assetCSSCnt = 0;
57 private $assetJSCnt = 0;
59 const SOURCE_MAP_TAG =
"\n//# sourceMappingURL=";
60 const HEADER_START_TAG =
"; /* Start:\"";
61 const HEADER_END_TAG =
"\"*/";
67 $this->targetList[
'KERNEL'] = [
78 'MODE' => AssetMode::ALL
81 $this->targetList[
'BODY'] = $this->targetList[
'TEMPLATE'] = $this->targetList[
'PAGE'] = $this->targetList[
'KERNEL'];
82 $this->targetList[
'PAGE'][
'NAME'] =
'PAGE';
83 $this->targetList[
'PAGE'][
'UNIQUE'] =
false;
84 $this->targetList[
'PAGE'][
'PREFIX'] =
'page';
85 $this->targetList[
'TEMPLATE'][
'NAME'] =
'TEMPLATE';
86 $this->targetList[
'TEMPLATE'][
'UNIQUE'] =
false;
87 $this->targetList[
'TEMPLATE'][
'PREFIX'] =
'template';
88 $this->targetList[
'BODY'][
'NAME'] =
'BODY';
89 $this->targetList[
'BODY'][
'UNIQUE'] =
false;
90 $this->targetList[
'BODY'][
'PREFIX'] =
'body';
93 $this->targetList[
'KERNEL'][
'CSS_LIST'][
'KERNEL_main'] = [];
94 $this->targetList[
'KERNEL'][
'JS_LIST'][
'KERNEL_main'] = [];
96 $this->target = &$this->targetList[
'TEMPLATE'];
97 $this->documentRoot = Main\Loader::getDocumentRoot();
114 public static function getInstance()
116 if (is_null(self::$instance))
118 self::$instance =
new Asset();
121 return self::$instance;
129 public function setMode($mode = AssetMode::STANDARD)
138 public static function gzipEnabled()
144 Option::get(
'main',
'compres_css_js_files',
'N') ==
'Y'
145 && extension_loaded(
'zlib')
146 && function_exists(
'gzopen')
156 public function enableOptimizeCss()
158 $this->optimizeCss =
true;
165 public function disableOptimizeCss()
167 $this->optimizeCss =
false;
174 public function enableOptimizeJs()
176 $this->optimizeJs =
true;
183 public function disableOptimizeJs()
185 $this->optimizeJs =
false;
192 public function setXhtml($value)
194 $this->xhtmlStyle = ($value ===
true ?
'/':
'');
202 public function setMaxCss($value)
212 public function setShowHeadString($value =
true)
214 $this->headString = $value;
221 public function getShowHeadString()
223 return $this->headString;
231 public function setShowHeadScript($value =
true)
233 $this->headScript = $value;
241 public function setShowBodyScript($value =
true)
243 $this->bodyScript = $value;
250 public function setAjax()
252 $newInstance = self::$instance =
new Asset();
253 $newInstance->ajax =
true;
260 public function getTargetName()
262 return $this->target[
'NAME'];
268 public function getTarget()
270 return $this->target;
279 public function startSet($id =
'', $mode = AssetMode::ALL)
281 return $this->startTarget($id, $mode);
290 public function startTarget($id =
'', $mode = AssetMode::ALL)
292 $id = strtoupper(trim($id));
298 if ($id ==
'TEMPLATE')
300 $this->templateExists =
true;
304 ($this->target[
'NAME'] ==
'TEMPLATE' || $this->target[
'NAME'] ==
'PAGE')
305 && ($id ==
'TEMPLATE' || $id ==
'PAGE')
308 $this->target[
'START'] =
false;
309 $this->targetList[$id][
'START'] =
true;
310 $this->target = &$this->targetList[$id];
312 elseif ($id !=
'TEMPLATE' && $id !=
'PAGE')
314 if (isset($this->targetList[$id]))
320 $this->targetList[$id] = [
332 $this->target = &$this->targetList[$id];
342 public function stopTarget($id =
'')
344 $id = strtoupper(trim($id));
345 if ($id ==
'TEMPLATE')
347 if($this->target[
'NAME'] ==
'TEMPLATE')
349 $this->target[
'START'] =
false;
350 $this->target = &$this->targetList[
'PAGE'];
354 $this->targetList[
'TEMPLATE'][
'START'] =
false;
359 if ($this->target[
'NAME'] ==
'TEMPLATE')
363 elseif ($this->targetList[
'TEMPLATE'][
'START'])
365 $this->target[
'START'] =
false;
366 $this->target = &$this->targetList[
'TEMPLATE'];
370 $this->target[
'START'] =
false;
371 $this->target = &$this->targetList[
'PAGE'];
384 public function getAssetInfo($id, $mode)
386 $id = strtoupper(trim($id));
387 $emptyData = [
'JS' => [],
'BUNDLE_JS' => [],
'CSS' => [],
'BUNDLE_CSS' => [],
'STRINGS' => []];
389 if (!isset($this->targetList[$id]))
394 static $cacheInfo = [
395 AssetMode::STANDARD =>
null,
396 AssetMode::COMPOSITE =>
null,
397 AssetMode::ALL =>
null,
398 AssetMode::SPECIAL => null
401 if ($cacheInfo[$mode] ===
null)
403 $cacheInfo[$mode] = $emptyData;
405 foreach ($this->strings as $location)
407 foreach ($location as $item)
409 if ($mode == $item[
'MODE'])
411 $cacheInfo[$mode][
'STRINGS'][$item[
'TARGET'][0]][] = $item[
'CONTENT'];
416 foreach ([
'JS',
'CSS'] as $type)
418 foreach ($this->getTargetList($type) as $set)
420 $cache = &$cacheInfo[$mode][$type][$set[
'NAME']];
421 $cacheFull = &$cacheInfo[$mode][
'BUNDLE_'.$type][$set[
'NAME']];
423 if (!is_array($cache))
428 if (!is_array($cacheFull))
433 $fileList = $this->fileList[$type][$set[
'NAME']] ?? [];
434 $targetList = $this->targetList[
'KERNEL'][$type.
'_LIST'][$set[
'NAME']] ?? [];
437 if ($mode === $set[
'MODE'] && isset($fileList[
'FILES']))
439 $items = $fileList[
'FILES'];
441 elseif (isset($fileList[
'UP_NEW_FILES']))
443 $items = $fileList[
'UP_NEW_FILES'];
451 foreach ($items as $item)
455 if (isset($fileList[
'FULL_FILES'][$item]))
457 $cacheFull = array_merge($cacheFull, $fileList[
'FULL_FILES'][$item]);
460 if ($set[
'PARENT_NAME'] ==
'KERNEL')
462 foreach ($targetList[
'WHERE_USED'] as $target => $tmp)
464 $cacheInfo[$mode][$type][$target][] = $item;
466 if (isset($fileList[
'FULL_FILES'][$item]))
468 if (!isset($cacheInfo[$mode][
'BUNDLE_'.$type][$target]))
470 $cacheInfo[$mode][
'BUNDLE_'.$type][$target] = [];
473 $cacheInfo[$mode][
'BUNDLE_'.$type][$target] = array_merge(
474 $cacheInfo[$mode][
'BUNDLE_'.$type][$target],
475 $fileList[
'FULL_FILES'][$item]
486 'JS' => $cacheInfo[$mode][
'JS'][$id] ?? [],
487 'BUNDLE_JS' => $cacheInfo[$mode][
'BUNDLE_JS'][$id] ?? [],
488 'CSS' => $cacheInfo[$mode][
'CSS'][$id] ?? [],
489 'BUNDLE_CSS' => $cacheInfo[$mode][
'BUNDLE_CSS'][$id] ?? [],
490 'STRINGS' => $cacheInfo[$mode][
'STRINGS'][$id] ?? []
499 public function compositeTarget($id =
'')
501 $id = strtoupper(trim($id));
502 if ($id ==
'' || !isset($this->targetList[$id]))
508 $this->targetList[$id][
'MODE'] = AssetMode::COMPOSITE;
518 public function getTargetList($type =
'CSS')
520 static $res = [
'CSS_LIST' =>
null,
'JS_LIST' =>
null];
521 $key = ($type ==
'CSS' ?
'CSS_LIST' :
'JS_LIST');
523 if ($res[$key] ===
null)
525 foreach ($this->targetList as $targetName => $targetInfo)
528 'NAME' => $targetName,
529 'PARENT_NAME' => $targetName,
530 'UNIQUE' => $targetInfo[
'UNIQUE'],
531 'PREFIX' => ($targetInfo[
'PREFIX'] ??
''),
532 'MODE' => $targetInfo[
'MODE'],
533 'MODULE_NAME' => ($targetInfo[
'MODULE_NAME'] ??
''),
536 if (!empty($targetInfo[$key]))
538 foreach ($targetInfo[$key] as $subSetName => $val)
541 'NAME' => $subSetName,
542 'PARENT_NAME' => $targetName,
543 'UNIQUE' => ($val[
'UNIQUE'] ??
''),
544 'PREFIX' => ($val[
'PREFIX'] ??
''),
545 'MODE' => ($val[
'MODE'] ?? 0),
546 'MODULE_NAME' => ($val[
'MODULE_NAME'] ??
''),
563 function addString($str, $unique =
false, $location = AssetLocation::AFTER_JS_KERNEL, $mode =
null)
573 $this->strings[$location][$chkSum][
'CONTENT'] = $str;
574 $this->strings[$location][$chkSum][
'TARGET'][] = $this->getTargetName();
575 $this->strings[$location][$chkSum][
'MODE'] = $mode;
579 $this->strings[$location][] = [
'CONTENT' => $str,
'MODE' => $mode,
'TARGET' => [$this->getTargetName()]];
589 public function getStrings($location = AssetLocation::AFTER_JS_KERNEL)
591 static $firstExec =
true;
594 $this->prepareString();
599 if ($location == AssetLocation::AFTER_CSS && \CJSCore::IsCoreLoaded())
601 $res =
"<script>if(!window.BX)window.BX={};if(!window.BX.message)window.BX.message=function(mess){if(typeof mess==='object'){for(let i in mess) {BX.message[i]=mess[i];} return true;}};</script>\n";
604 if (isset($this->strings[$location]))
606 foreach ($this->strings[$location] as $item)
608 if ($this->mode & $item[
'MODE'])
610 $res .= $item[
'CONTENT'].
"\n";
615 return ($res ==
'') ?
'' : $res.
"\n";
624 public function addCss($path, $additional =
false)
631 $css = $this->getAssetPath($path);
632 $this->css[$css][
'TARGET'][] = $this->getTargetName();
633 $this->css[$css][
'ADDITIONAL'] = (isset($this->css[$css][
'ADDITIONAL']) && $this->css[$css][
'ADDITIONAL'] ? true : $additional);
643 public function addJs($path, $additional =
false)
650 $js = $this->getAssetPath($path);
651 $this->js[$js][
'TARGET'][] = $this->getTargetName();
652 $this->js[$js][
'ADDITIONAL'] = (isset($this->js[$js][
'ADDITIONAL']) && $this->js[$js][
'ADDITIONAL'] ? true : $additional);
662 public static function fixCssIncludes($content, $path)
664 $path = IO\Path::getDirectory($path);
665 $content = preg_replace_callback(
666 '#([;\s:]*(?:url|@import)\s*\(\s*)(\'|"|)(.+?)(\2)\s*\)#si',
667 function ($matches) use ($path)
669 return $matches[1].Asset::replaceUrlCSS($matches[3], $matches[2], addslashes($path)).
")";
674 $content = preg_replace_callback(
675 '#(\s*@import\s*)([\'"])([^\'"]+)(\2)#si',
676 function ($matches) use ($path)
678 return $matches[1].Asset::replaceUrlCSS($matches[3], $matches[2], addslashes($path));
692 public function groupJs($from =
'', $to =
'')
694 if (empty($from) || empty($to))
699 $to = $this->movedJsTo($to);
700 if (array_key_exists($from, $this->moduleInfo[
'JS']))
702 $this->moduleInfo[
'JS'][$from][
'MODULE_ID'] = $to;
706 $this->moduleInfo[
'JS'][$from] = [
'MODULE_ID' => $to,
'FILES_INFO' =>
false,
'BODY' =>
false];
709 foreach ($this->moduleInfo[
'JS'] as $moduleID => $moduleInfo)
711 if ($moduleInfo[
'MODULE_ID'] == $from)
713 $this->moduleInfo[
'JS'][$moduleID][
"MODULE_ID"] = $to;
724 public function groupCss($from =
'', $to =
'')
726 if (empty($from) || empty($to))
731 $to = $this->movedCssTo($to);
732 if (array_key_exists($from, $this->moduleInfo[
'CSS']))
734 $this->moduleInfo[
'CSS'][$from][
'MODULE_ID'] = $to;
738 $this->moduleInfo[
'CSS'][$from] = [
'MODULE_ID' => $to,
'FILES_INFO' =>
false];
741 foreach ($this->moduleInfo[
'CSS'] as $moduleID => $moduleInfo)
743 if($moduleInfo[
'MODULE_ID'] == $from)
745 $this->moduleInfo[
'CSS'][$moduleID][
"MODULE_ID"] = $to;
754 private function movedJsTo($to)
756 if (isset($this->moduleInfo[
'JS'][$to][
'MODULE_ID']) && $this->moduleInfo[
'JS'][$to][
'MODULE_ID'] != $to)
758 $to = $this->movedJsTo($this->moduleInfo[
'JS'][$to][
'MODULE_ID']);
768 private function movedCssTo($to)
770 if (isset($this->moduleInfo[
'CSS'][$to][
'MODULE_ID']) && $this->moduleInfo[
'CSS'][$to][
'MODULE_ID'] != $to)
772 $to = $this->movedCssTo($this->moduleInfo[
'JS'][$to][
'MODULE_ID']);
783 public function moveJs($module =
'')
785 if (empty($module) || $module ===
"main")
790 if (array_key_exists($module, $this->moduleInfo[
'JS']))
792 $this->moduleInfo[
'JS'][$module][
'BODY'] =
true;
796 $this->moduleInfo[
'JS'][$module] = [
'MODULE_ID' => $module,
'FILES_INFO' =>
false,
'BODY' =>
true];
805 public function setJsToBody($flag)
807 $this->moveJsToBody = (bool)$flag;
813 protected function getJsToBody()
815 if ($this->moveJsToBody ===
null)
817 $this->moveJsToBody = Option::get(
"main",
"move_js_to_body") ===
"Y" && (!defined(
"ADMIN_SECTION") || ADMIN_SECTION !==
true);
819 return $this->moveJsToBody;
828 public function moveJsToBody(&$content)
830 if (!$this->getJsToBody())
838 $areas = $this->getScriptAreas($content);
839 foreach ($areas as $area)
841 if (str_contains($area->attrs,
"data-skip-moving") || !self::isValidScriptType($area->attrs))
846 $js .= substr($content, $area->openTagStart, $area->closingTagEnd - $area->openTagStart);
847 $newContent .= substr($content, $offset, $area->openTagStart - $offset);
848 $offset = $area->closingTagEnd;
856 $newContent .= substr($content, $offset);
857 $bodyEnd = strripos($newContent,
"</body>");
858 if ($bodyEnd ===
false)
860 $content = $newContent.$js;
864 $content = substr_replace($newContent, $js, $bodyEnd, 0);
873 private function getScriptAreas($content)
875 $openTag =
"<script";
876 $closingTag =
"</script";
881 $content = strtolower($content);
882 while (($openTagStart = strpos($content, $openTag, $offset)) !==
false)
884 $endingPos = strpos($content, $ending, $openTagStart);
885 if ($endingPos ===
false)
890 $attrsStart = $openTagStart + strlen($openTag);
891 $attrs = substr($content, $attrsStart, $endingPos - $attrsStart);
892 $openTagEnd = $endingPos + strlen($ending);
894 $realClosingTag = $closingTag.$ending;
895 $closingTagStart = strpos($content, $realClosingTag, $openTagEnd);
896 if ($closingTagStart ===
false)
898 $offset = $openTagEnd;
902 $closingTagEnd = $closingTagStart + strlen($realClosingTag);
903 while (isset($content[$closingTagEnd]) && $content[$closingTagEnd] ===
"\n")
908 $area = new \stdClass();
909 $area->attrs = $attrs;
910 $area->openTagStart = $openTagStart;
911 $area->openTagEnd = $openTagEnd;
912 $area->closingTagStart = $closingTagStart;
913 $area->closingTagEnd = $closingTagEnd;
916 $offset = $closingTagEnd;
925 public function canMoveJsToBody()
928 $this->getJsToBody() &&
929 !Main\Application::getInstance()->getContext()->getRequest()->isAjaxRequest() &&
930 !defined(
"BX_BUFFER_SHUTDOWN");
939 private static function isValidScriptType($attrs)
941 if ($attrs ===
"" || !preg_match(
"/type\\s*=\\s*(['\"]?)(.*?)\\1/i", $attrs, $match))
946 $type = mb_strtolower($match[2]);
947 return $type ===
"" || $type ===
"text/javascript" || $type ===
"application/javascript";
958 public static function replaceUrlCss($url, $quote, $path)
961 str_contains($url,
"://")
962 || str_contains($url,
"data:")
963 || str_starts_with($url,
"#")
966 return $quote.$url.$quote;
969 $url = trim(stripslashes($url),
"'\" \r\n\t");
970 if (mb_substr($url, 0, 1) ==
"/")
972 return $quote.$url.$quote;
975 return $quote.$path.
'/'.$url.$quote;
983 public static function getAssetPath($src)
985 if (($p = mb_strpos($src,
"?")) > 0 && !\CMain::IsExternalLink($src))
987 $src = mb_substr($src, 0, $p);
995 public function optimizeCss()
997 $optimize = $this->optimizeCss
998 && (!defined(
"ADMIN_SECTION") || ADMIN_SECTION !==
true)
999 && Option::get(
'main',
'optimize_css_files',
'N') ==
'Y'
1008 public function optimizeJs()
1010 $optimize = $this->optimizeJs
1011 && (!defined(
"ADMIN_SECTION") || ADMIN_SECTION !==
true)
1012 && Option::get(
'main',
'optimize_js_files',
'N') ==
'Y'
1021 public static function canUseMinifiedAssets()
1023 static $canLoad =
null;
1024 if ($canLoad ===
null)
1026 $canLoad = Option::get(
"main",
"use_minified_assets",
"Y") ==
"Y";
1035 public function sliceKernel()
1037 return (!defined(
"ADMIN_SECTION") || ADMIN_SECTION !==
true);
1047 public function insertCss($css, $label =
false, $inline =
false)
1049 if ($label ===
true)
1051 $label =
' data-template-style="true" ';
1053 elseif ($label ===
false)
1060 return "<style type=\"text/css\" {$label}>\n{$css}\n</style>\n";
1064 return "<link href=\"{$css}\" type=\"text/css\" {$label} rel=\"stylesheet\" {$this->xhtmlStyle}>\n";
1075 public function insertJs($js, $label =
'', $inline =
false)
1079 return "<script {$label}>\n{$js}\n</script>\n";
1083 return "<script {$label} src=\"$js\"></script>\n";
1091 private function setTemplateID()
1093 static $firstExec =
true;
1094 if ($firstExec && !$this->ajax && (!defined(
"ADMIN_SECTION") || ADMIN_SECTION !==
true))
1096 if (defined(
"SITE_TEMPLATE_PREVIEW_MODE"))
1098 $this->templatePath = BX_PERSONAL_ROOT.
'/tmp/templates/__bx_preview';
1100 elseif (defined(
'SITE_TEMPLATE_ID'))
1102 $this->siteTemplateID = SITE_TEMPLATE_ID;
1103 $this->templatePath = SITE_TEMPLATE_PATH;
1107 $this->siteTemplateID =
'.default';
1108 $this->templatePath = BX_PERSONAL_ROOT.
"/templates/.default";
1118 private function addTemplateCss()
1122 && (!defined(
"ADMIN_SECTION") || ADMIN_SECTION !==
true)
1123 && $this->templateExists
1126 $this->css[$this->templatePath .
'/styles.css'][
'TARGET'][] =
'TEMPLATE';
1127 $this->css[$this->templatePath .
'/styles.css'][
'ADDITIONAL'] =
false;
1129 $this->css[$this->templatePath .
'/template_styles.css'][
'TARGET'][] =
'TEMPLATE';
1130 $this->css[$this->templatePath .
'/template_styles.css'][
'ADDITIONAL'] =
false;
1138 private function prepareString()
1140 foreach ($this->strings as $location => $stringLocation)
1142 foreach ($stringLocation as $key => $item)
1145 $this->strings[$location][$key][
'MODE'] = ($item[
'MODE'] ===
null ? $this->targetList[$item[
'TARGET'][0]][
'MODE'] : $item[
'MODE']);
1157 private function getAssetPaths($assetPath)
1159 $paths = [$assetPath];
1160 if (self::canUseMinifiedAssets() && preg_match(
"/(.+)\\.(js|css)$/i", $assetPath, $matches))
1162 array_unshift($paths, $matches[1].
".min.".$matches[2]);
1167 foreach ($paths as $path)
1169 $filePath = $this->documentRoot.$path;
1170 if (file_exists($filePath) && ($mtime = filemtime($filePath)) > $maxMtime && filesize($filePath) > 0)
1175 "FILE_PATH" => $filePath,
1176 "FULL_PATH" => \CUtil::GetAdditionalFileURL($path,
true),
1192 public function getFullAssetPath($sourcePath)
1194 $result = $this->getAssetPaths($sourcePath);
1196 if (is_array($result))
1198 return $result[
"FULL_PATH"];
1200 if (\CMain::IsExternalLink($sourcePath))
1214 private function prepareCss() : void
1218 foreach ($this->css as $css => $set)
1221 $assetTID = $set[
'ADDITIONAL'] ?
'TEMPLATE' : $set[
'TARGET'][0];
1224 'FULL_PATH' =>
false,
1225 'FILE_PATH' =>
false,
1227 'TARGET' => $assetTID,
1228 'EXTERNAL' => \CMain::IsExternalLink($css),
1229 'ADDITIONAL' => $set[
'ADDITIONAL']
1232 if ($cssInfo[
'EXTERNAL'])
1234 if ($set[
'ADDITIONAL'])
1236 $tmpKey =
'TEMPLATE';
1237 $tmpPrefix =
'template';
1242 $tmpPrefix =
'kernel';
1245 $cssInfo[
'MODULE_ID'] = $this->assetCSSCnt;
1246 $cssInfo[
'TARGET'] = $tmpKey.
'_'.$this->assetCSSCnt;
1247 $cssInfo[
'PREFIX'] = $tmpPrefix.
'_'.$this->assetCSSCnt;
1248 $cssInfo[
'FULL_PATH'] = $cssInfo[
'PATH'];
1249 $cssInfo[
'SKIP'] =
true;
1250 $this->assetCSSCnt++;
1252 $this->targetList[$tmpKey][
'CSS_LIST'][$cssInfo[
'TARGET']] = [
1253 'TARGET' => $cssInfo[
'TARGET'],
1254 'PREFIX' => $cssInfo[
'PREFIX'],
1255 'MODE' => $this->targetList[$assetTID][
'MODE'],
1262 if (($paths = $this->getAssetPaths($css)) !==
null)
1264 $cssInfo[
"PATH"] = $css;
1265 $cssInfo[
"FILE_PATH"] = $paths[
"FILE_PATH"];
1266 $cssInfo[
"FULL_PATH"] = $paths[
"FULL_PATH"];
1270 unset($this->css[$css]);
1274 $moduleInfo = $this->isKernelCSS($cssInfo[
'PATH']);
1277 if ($this->sliceKernel() && $this->optimizeCss() && is_array($moduleInfo))
1279 $cssInfo[
'MODULE_ID'] = $moduleInfo[
'MODULE_ID'];
1280 $cssInfo[
'TARGET'] =
'KERNEL_'.$moduleInfo[
'MODULE_ID'];
1281 $cssInfo[
'PREFIX'] =
'kernel_'.$moduleInfo[
'MODULE_ID'];
1282 $cssInfo[
'SKIP'] = $moduleInfo[
'SKIP'] ??
false;
1286 $cssInfo[
'MODULE_ID'] = $this->assetCSSCnt;
1287 $cssInfo[
'TARGET'] =
'KERNEL_'.$this->assetCSSCnt;
1288 $cssInfo[
'PREFIX'] =
'kernel_'.$this->assetCSSCnt;
1289 $cssInfo[
'SKIP'] =
true;
1290 $this->assetCSSCnt++;
1293 if (isset($this->targetList[
'KERNEL'][
'CSS_LIST'][$cssInfo[
'TARGET']][
'MODE']))
1295 $this->targetList[
'KERNEL'][
'CSS_LIST'][$cssInfo[
'TARGET']][
'MODE'] |= $this->targetList[$assetTID][
'MODE'];
1299 $this->targetList[
'KERNEL'][
'CSS_LIST'][$cssInfo[
'TARGET']] = [
1300 'TARGET' => $cssInfo[
'TARGET'],
1301 'PREFIX' => $cssInfo[
'PREFIX'],
1302 'MODE' => $set[
'ADDITIONAL'] ? $this->targetList[$set[
'TARGET'][0]][
'MODE'] : $this->targetList[$assetTID][
'MODE'],
1308 if (is_array($moduleInfo))
1310 $this->targetList[
'KERNEL'][
'CSS_LIST'][$cssInfo[
'TARGET']][
'MODULE_NAME'] = $moduleInfo[
'MODULE_ID'];
1314 foreach ($set[
'TARGET'] as $setID)
1316 $this->targetList[
'KERNEL'][
'CSS_LIST'][$cssInfo[
'TARGET']][
'WHERE_USED'][$setID] =
true;
1319 elseif (strncmp($cssInfo[
'PATH'],
'/bitrix/js/', 11) != 0 )
1321 $cssInfo[
'SKIP'] = !(
1322 strncmp($cssInfo[
'PATH'],
'/bitrix/panel/', 14) != 0
1323 && strncmp($cssInfo[
'PATH'],
'/bitrix/themes/', 15) != 0
1324 && strncmp($cssInfo[
'PATH'],
'/bitrix/modules/', 16) != 0
1329 if ($cssInfo[
'ADDITIONAL'])
1331 $additional[] = $cssInfo;
1335 $this->css[$cssInfo[
'TARGET']][] = $cssInfo;
1338 unset($this->css[$css]);
1341 foreach ($additional as $cssInfo)
1343 $this->css[$cssInfo[
'TARGET']][] = $cssInfo;
1353 private function prepareJs()
1356 foreach ($this->js as $js => $set)
1359 $assetTID = $set[
'ADDITIONAL'] ?
'TEMPLATE' : $set[
'TARGET'][0];
1362 'FULL_PATH' =>
false,
1363 'FILE_PATH' =>
false,
1365 'TARGET' => $assetTID,
1366 'EXTERNAL' => \CMain::IsExternalLink($js),
1368 'ADDITIONAL' => $set[
'ADDITIONAL']
1371 if ($jsInfo[
'EXTERNAL'])
1373 if ($set[
'ADDITIONAL'])
1375 $tmpKey =
'TEMPLATE';
1376 $tmpPrefix =
'template';
1381 $tmpPrefix =
'kernel';
1384 $jsInfo[
'MODULE_ID'] = $this->assetJSCnt;
1385 $jsInfo[
'TARGET'] = $tmpKey.
'_'.$this->assetJSCnt;
1386 $jsInfo[
'PREFIX'] = $tmpPrefix.
'_'.$this->assetJSCnt;
1387 $jsInfo[
'FULL_PATH'] = $jsInfo[
'PATH'];
1388 $jsInfo[
'SKIP'] =
true;
1389 $this->assetJSCnt++;
1391 $this->targetList[$tmpKey][
'JS_LIST'][$jsInfo[
'TARGET']] = [
1392 'TARGET' => $jsInfo[
'TARGET'],
1393 'PREFIX' => $jsInfo[
'PREFIX'],
1394 'MODE' => $this->targetList[$assetTID][
'MODE'],
1401 if (($paths = $this->getAssetPaths($js)) !==
null)
1403 $jsInfo[
"PATH"] = $js;
1404 $jsInfo[
"FILE_PATH"] = $paths[
"FILE_PATH"];
1405 $jsInfo[
"FULL_PATH"] = $paths[
"FULL_PATH"];
1409 unset($this->js[$js]);
1413 if ($moduleInfo = $this->isKernelJS($jsInfo[
'PATH']))
1415 if ($this->sliceKernel() && $this->optimizeJs())
1417 $jsInfo[
'MODULE_ID'] = $moduleInfo[
'MODULE_ID'];
1418 $jsInfo[
'TARGET'] =
'KERNEL_'.$moduleInfo[
'MODULE_ID'];
1419 $jsInfo[
'PREFIX'] =
'kernel_'.$moduleInfo[
'MODULE_ID'];
1420 $jsInfo[
'SKIP'] = $moduleInfo[
'SKIP'] ??
false;
1421 $jsInfo[
'BODY'] = $moduleInfo[
'BODY'];
1425 $jsInfo[
'MODULE_ID'] = $this->assetJSCnt;
1426 $jsInfo[
'TARGET'] =
'KERNEL_'.$this->assetJSCnt;
1427 $jsInfo[
'PREFIX'] =
'kernel_'.$this->assetJSCnt;
1428 $jsInfo[
'SKIP'] =
true;
1429 $this->assetJSCnt++;
1432 if ($jsInfo[
'BODY'])
1434 $this->targetList[
'BODY'][
'JS_LIST'][$jsInfo[
'TARGET']] = [
1435 'TARGET' => $jsInfo[
'TARGET'],
1436 'PREFIX' => $jsInfo[
'PREFIX'],
1437 'MODE' => $this->targetList[$assetTID][
'MODE'],
1444 if (isset($this->targetList[
'KERNEL'][
'JS_LIST'][$jsInfo[
'TARGET']][
'MODE']))
1446 $this->targetList[
'KERNEL'][
'JS_LIST'][$jsInfo[
'TARGET']][
'MODE'] |= $this->targetList[$assetTID][
'MODE'];
1450 $this->targetList[
'KERNEL'][
'JS_LIST'][$jsInfo[
'TARGET']] = [
1451 'TARGET' => $jsInfo[
'TARGET'],
1452 'PREFIX' => $jsInfo[
'PREFIX'],
1453 'MODE' => $set[
'ADDITIONAL'] ? $this->targetList[$set[
'TARGET'][0]][
'MODE'] : $this->targetList[$assetTID][
'MODE'],
1461 foreach ($set[
'TARGET'] as $setID)
1463 $this->targetList[
'KERNEL'][
'JS_LIST'][$jsInfo[
'TARGET']][
'WHERE_USED'][$setID] =
true;
1466 elseif (strncmp($jsInfo[
'PATH'],
'/bitrix/js/', 11) != 0)
1468 $jsInfo[
'SKIP'] = !(
1469 strncmp($jsInfo[
'PATH'],
'/bitrix/panel/', 14) != 0
1470 && strncmp($jsInfo[
'PATH'],
'/bitrix/themes/', 15) != 0
1471 && strncmp($jsInfo[
'PATH'],
'/bitrix/modules/', 16) != 0
1476 if ($jsInfo[
'ADDITIONAL'])
1478 $additional[] = $jsInfo;
1482 $this->js[$jsInfo[
'TARGET']][] = $jsInfo;
1484 unset($this->js[$js]);
1488 foreach ($this->targetList[
'BODY'][
'JS_LIST'] as $item)
1490 unset($this->targetList[
'KERNEL'][
'JS_LIST'][$item[
'TARGET']]);
1493 foreach ($additional as $jsInfo)
1495 $this->js[$jsInfo[
'TARGET']][] = $jsInfo;
1506 public function getCss($type = AssetShowTargetType::ALL)
1510 static $setList = [];
1511 static $ajaxList = [];
1513 if (empty($setList))
1515 $this->setTemplateID();
1516 $this->addTemplateCss();
1517 $this->prepareCss();
1518 $setList = $this->getTargetList();
1519 $optimizeCss = $this->optimizeCss();
1521 foreach ($setList as $setInfo)
1523 if (!isset($this->css[$setInfo[
'NAME']]))
1529 if (!empty($this->moduleInfo[
'CSS'][$setInfo[
'MODULE_NAME']][
'DATA']))
1531 $data = $this->moduleInfo[
'CSS'][$setInfo[
'MODULE_NAME']][
'DATA'];
1535 if (!empty($this->moduleInfo[
'CSS'][$setInfo[
'MODULE_NAME']][
'LOCATION']))
1537 $location = $this->moduleInfo[
'CSS'][$setInfo[
'MODULE_NAME']][
'LOCATION'];
1542 $showLabel = ($setInfo[
'NAME'] ==
'TEMPLATE');
1544 foreach ($this->css[$setInfo[
'NAME']] as $cssFile)
1546 $css = $cssFile[
'FULL_PATH'];
1549 $this->assetList[
'CSS'][] = $cssFile[
'PATH'];
1552 elseif ($cssFile[
'EXTERNAL'])
1554 $resCss .= $this->insertCss($css, $showLabel);
1555 $this->fileList[
'CSS'][$setInfo[
'NAME']][
'FILES'][] = $css;
1557 elseif ($optimizeCss)
1559 if ($cssFile[
'SKIP'])
1561 $resCss .= $this->insertCss($css, $showLabel);
1562 $this->fileList[
'CSS'][$setInfo[
'NAME']][
'FILES'][] = $css;
1566 $listAsset[] = $cssFile;
1571 $resCss .= $this->insertCss($css, $showLabel);
1572 $this->fileList[
'CSS'][$setInfo[
'NAME']][
'FILES'][] = $css;
1576 $optimizedAsset = $this->optimizeAsset($listAsset, $setInfo[
'UNIQUE'], $setInfo[
'PREFIX'], $setInfo[
'NAME'],
'css', $data);
1578 $resCss = $optimizedAsset[
'RESULT'].$resCss;
1579 if ($location == AssetLocation::AFTER_CSS)
1582 'FILES' => $optimizedAsset[
'FILES'],
1583 'SOURCE_FILES' => $optimizedAsset[
'SOURCE_FILES'],
1589 $this->assetList[
'CSS'][$setInfo[
'PARENT_NAME']][$setInfo[
'NAME']] = $optimizedAsset[
'FILES'];
1590 $this->assetList[
'SOURCE_CSS'][$setInfo[
'PARENT_NAME']][$setInfo[
'NAME']] = ($optimizedAsset[
'SOURCE_FILES'] ?? []);
1591 $this->targetList[$setInfo[
'PARENT_NAME']][
'CSS_RES'][$setInfo[
'NAME']][] = $resCss;
1595 foreach ($additional as $bundle)
1597 $templateFiles = $this->assetList[
'CSS'][
'TEMPLATE'][
'TEMPLATE'] ?? [];
1599 $this->assetList[
'CSS'][
'TEMPLATE'][
'TEMPLATE'] = array_merge($templateFiles, $bundle[
'FILES']);
1600 $this->assetList[
'SOURCE_CSS'][
'TEMPLATE'][
'TEMPLATE'] = array_merge($templateFiles, $bundle[
'SOURCE_FILES']);
1601 $this->targetList[
'TEMPLATE'][
'CSS_RES'][
'TEMPLATE'][] = $bundle[
'RES'];
1604 unset($additional, $templateFiles, $bundle);
1607 if ($this->ajax && !empty($ajaxList))
1609 $res .=
'<script>'.
"BX.loadCSS(['".implode(
"','", $ajaxList).
"']);".
'</script>';
1612 if ($type == AssetShowTargetType::KERNEL)
1614 $res .= $this->showAsset($setList,
'css',
'KERNEL');
1616 elseif ($type == AssetShowTargetType::TEMPLATE_PAGE)
1618 foreach ($this->targetList as $setName => $set)
1620 if ($setName !=
'TEMPLATE' && $setName !=
'KERNEL')
1622 $res .= $this->showAsset($setList,
'css', $setName);
1626 $res .= $this->showAsset($setList,
'css',
'TEMPLATE');
1630 foreach ($this->targetList as $setName => $set)
1632 if ($setName !=
'TEMPLATE')
1634 $res .= $this->showAsset($setList,
'css', $setName);
1638 $res .= $this->showAsset($setList,
'css',
'TEMPLATE');
1651 function getJs($type = AssetShowTargetType::ALL)
1653 static $setList = [];
1656 $type = (int) $type;
1657 $type = (($type == AssetShowTargetType::KERNEL && $this->headString && !$this->headScript) ? AssetShowTargetType::ALL : $type);
1658 $optimize = $this->optimizeJs();
1659 if (empty($setList))
1662 $setList = $this->getTargetList(
'JS');
1664 foreach ($setList as $setInfo)
1666 if (!isset($this->js[$setInfo[
'NAME']]))
1672 if (!empty($this->moduleInfo[
'JS'][$setInfo[
'MODULE_NAME']][
'DATA']))
1674 $data = $this->moduleInfo[
'JS'][$setInfo[
'MODULE_NAME']][
'DATA'];
1679 foreach ($this->js[$setInfo[
'NAME']] as $jsFile)
1681 $js = $jsFile[
'FULL_PATH'];
1684 if ($jsFile[
'SKIP'])
1686 $this->fileList[
'JS'][$setInfo[
'NAME']][
'FILES'][] = $js;
1687 $resJs .=
"<script src=\"{$js}\"></script>\n";
1691 $listAsset[] = $jsFile;
1696 $this->fileList[
'JS'][$setInfo[
'NAME']][
'FILES'][] = $js;
1697 $resJs .=
"<script src=\"{$js}\"></script>\n";
1700 $optAsset = $this->optimizeAsset($listAsset, $setInfo[
'UNIQUE'], $setInfo[
'PREFIX'], $setInfo[
'NAME'],
'js', $data);
1701 $this->assetList[
'JS'][$setInfo[
'PARENT_NAME']][$setInfo[
'NAME']] = $optAsset[
'FILES'];
1702 $this->assetList[
'SOURCE_JS'][$setInfo[
'PARENT_NAME']][$setInfo[
'NAME']] = ($optAsset[
'SOURCE_FILES'] ?? []);
1703 $this->targetList[$setInfo[
'PARENT_NAME']][
'JS_RES'][$setInfo[
'NAME']][] = $optAsset[
'RESULT'].$resJs;
1705 unset($optAsset, $resJs, $listAsset);
1708 if ($type == AssetShowTargetType::KERNEL && ($this->mode & $this->targetList[
'KERNEL'][
'MODE']))
1710 $setName =
'KERNEL';
1711 $res .= $this->getStrings(AssetLocation::AFTER_CSS);
1712 $res .= $this->showAsset($setList,
'js', $setName);
1713 $res .= $this->showFilesList();
1714 $res .= $this->getStrings(AssetLocation::AFTER_JS_KERNEL);
1716 if (!$this->bodyScript)
1718 $res .= $this->getStrings(AssetLocation::BODY_END);
1719 $res .= $this->showAsset($setList,
'js',
'BODY');
1722 elseif ($type == AssetShowTargetType::TEMPLATE_PAGE)
1724 foreach ($this->targetList as $setName => $set)
1726 if ($setName !=
'KERNEL' && $setName !=
'BODY')
1728 $setName = $this->fixJsSetOrder($setName);
1729 $res .= $this->showAsset($setList,
'js', $setName);
1732 $res .= $this->getStrings(AssetLocation::AFTER_JS);
1734 elseif ($type == AssetShowTargetType::BODY && ($this->mode & $this->targetList[
'BODY'][
'MODE']))
1737 $res .= $this->getStrings(AssetLocation::BODY_END);
1738 $res .= $this->showAsset($setList,
'js', $setName);
1742 foreach ($this->targetList as $setName => $set)
1744 if ($this->mode & $set[
'MODE'])
1746 $setName = $this->fixJsSetOrder($setName);
1747 if ($setName ==
'KERNEL')
1749 $res .= $this->getStrings(AssetLocation::AFTER_CSS);
1750 $res .= $this->showAsset($setList,
'js', $setName);
1751 $res .= $this->showFilesList();
1752 $res .= $this->getStrings(AssetLocation::AFTER_JS_KERNEL);
1754 if (!$this->bodyScript)
1756 $res .= $this->getStrings(AssetLocation::BODY_END);
1757 $res .= $this->showAsset($setList,
'js',
'BODY');
1760 elseif ($setName !=
'BODY')
1762 $res .= $this->showAsset($setList,
'js', $setName);
1767 $res .= $this->getStrings(AssetLocation::AFTER_JS);
1770 return (trim($res) ==
'' ? $res : $res.
"\n");
1778 public static function getLocationByName($location)
1780 if ($location ===
false || $location ===
'DEFAULT')
1782 $location = AssetLocation::AFTER_JS_KERNEL;
1784 elseif ($location ===
true)
1786 $location = AssetLocation::AFTER_CSS;
1796 public function showFilesList()
1799 if (!\CJSCore::IsCoreLoaded())
1804 if (!empty($this->assetList[
'JS']))
1807 foreach ($this->getTargetList(
'JS') as $set)
1809 if ($this->mode & $set[
'MODE']
1810 && isset($this->assetList[
'SOURCE_JS'][$set[
'PARENT_NAME']][$set[
'NAME']])
1811 && is_array($this->assetList[
'SOURCE_JS'][$set[
'PARENT_NAME']][$set[
'NAME']]))
1813 $assets = array_merge($assets, $this->assetList[
'SOURCE_JS'][$set[
'PARENT_NAME']][$set[
'NAME']]);
1817 if (!empty($assets))
1819 $res .=
'<script>BX.setJSList('.\CUtil::phpToJSObject($assets).
');</script>';
1824 if (!empty($this->assetList[
'CSS']))
1827 foreach ($this->getTargetList(
'CSS') as $set)
1829 if ($this->mode & $set[
'MODE']
1830 && isset($this->assetList[
'SOURCE_CSS'][$set[
'PARENT_NAME']][$set[
'NAME']])
1831 && is_array($this->assetList[
'SOURCE_CSS'][$set[
'PARENT_NAME']][$set[
'NAME']])
1834 $assets = array_merge($assets, $this->assetList[
'SOURCE_CSS'][$set[
'PARENT_NAME']][$set[
'NAME']]);
1838 if (!empty($assets))
1840 $res .=
'<script>BX.setCSSList('.\CUtil::phpToJSObject($assets).
');</script>';
1854 function addCssKernelInfo($module =
'', $css = [], $settings = [])
1856 if (empty($module) || empty($css))
1861 if (!array_key_exists($module, $this->moduleInfo[
'CSS']))
1863 $this->moduleInfo[
'CSS'][$module] = [
1864 'MODULE_ID' => $module,
1866 'FILES_INFO' =>
true,
1867 'IS_KERNEL' =>
true,
1873 foreach ($css as $key)
1875 $key = self::getAssetPath($key);
1876 $this->kernelAsset[
'CSS'][$key] = $module;
1879 $this->moduleInfo[
'CSS'][$module][
'FILES_INFO'] =
true;
1880 if (!empty($settings[
'DATA']))
1882 $this->moduleInfo[
'CSS'][$module][
'DATA'] = $settings[
'DATA'];
1885 if (!empty($settings[
'LOCATION']))
1887 $this->moduleInfo[
'CSS'][$module][
'LOCATION'] = $settings[
'LOCATION'];
1898 function addJsKernelInfo($module =
'', $js = [], $settings = [])
1900 if (empty($module) || empty($js))
1905 if (!array_key_exists($module, $this->moduleInfo[
'JS']))
1907 $this->moduleInfo[
'JS'][$module] = [
1908 'MODULE_ID' => $module,
1910 'FILES_INFO' =>
true,
1911 'IS_KERNEL' =>
true,
1917 foreach ($js as $key)
1919 $key = self::getAssetPath($key);
1920 $this->kernelAsset[
'JS'][$key] = $module;
1923 $this->moduleInfo[
'JS'][$module][
'FILES_INFO'] =
true;
1924 if (!empty($settings[
'DATA']))
1926 $this->moduleInfo[
'JS'][$module][
'DATA'] = $settings[
'DATA'];
1935 function isKernelCSS($css)
1938 if (!($this->sliceKernel() && $this->optimizeCss()))
1940 return ((strncmp($css,
'/bitrix/js/', 11) == 0) || (strncmp($css,
'/bitrix/css/', 12) == 0));
1944 if (array_key_exists($css, $this->kernelAsset[
'CSS']))
1946 return $this->moduleInfo[
'CSS'][$this->kernelAsset[
'CSS'][$css]];
1948 elseif ((strncmp($css,
'/bitrix/js/', 11) == 0) || (strncmp($css,
'/bitrix/css/', 12) == 0))
1950 $tmp = explode(
'/', $css);
1951 $moduleID = $tmp[
'3'];
1954 if (empty($moduleID))
1960 'MODULE_ID' => $moduleID.
'_'.$this->assetCSSCnt++,
1962 'FILES_INFO' =>
false,
1963 'IS_KERNEL' =>
true,
1977 function isKernelJS($js)
1980 if (!($this->sliceKernel() && $this->optimizeJs()))
1982 return (strncmp($js,
'/bitrix/js/', 11) == 0);
1986 if (array_key_exists($js, $this->kernelAsset[
'JS']))
1988 return $this->moduleInfo[
'JS'][$this->kernelAsset[
'JS'][$js]];
1990 elseif (strncmp($js,
'/bitrix/js/', 11) == 0)
1992 $tmp = explode(
'/', $js);
1993 $moduleID = $tmp[
'3'];
1996 if (empty($moduleID))
2002 'MODULE_ID' => $moduleID.
'_'.$this->assetJSCnt++,
2004 'FILES_INFO' =>
false,
2005 'IS_KERNEL' =>
true,
2020 public function setUnique($setID =
'', $uniqueID =
'')
2022 $setID = preg_replace(
'#[^a-z0-9_]#i',
'', $setID);
2023 $uniqueID = preg_replace(
'#[^a-z0-9_]#i',
'', $uniqueID);
2024 if (!(empty($setID) || empty($uniqueID)) && isset($this->targetList[$setID]))
2026 $this->targetList[$setID][
'UNIQUE'] =
true;
2027 $this->targetList[$setID][
'PREFIX'] .= ($uniqueID ==
'' ?
'' :
'_'.$uniqueID);
2040 private function showAsset($setList = [], $type =
'css', $setName =
'')
2043 $type = ($type ==
'css' ?
'CSS_RES' :
'JS_RES');
2044 $skipCheck = ($setName ==
'');
2046 foreach ($setList as $setInfo)
2049 ($skipCheck || $setName == $setInfo[
'PARENT_NAME'])
2050 && $this->mode & $setInfo[
'MODE']
2051 && isset($this->targetList[$setInfo[
'PARENT_NAME']][$type][$setInfo[
'NAME']]))
2053 $res .= implode(
"\n", $this->targetList[$setInfo[
'PARENT_NAME']][$type][$setInfo[
'NAME']]);
2065 private function fixJsSetOrder($setName =
'')
2067 if ($setName ==
'PAGE')
2069 $setName =
'TEMPLATE';
2071 elseif ($setName ==
'TEMPLATE')
2084 public static function getAssetTime($file =
'')
2086 $qpos = mb_strpos($file,
'?');
2087 if ($qpos ===
false)
2093 return mb_substr($file, $qpos);
2101 private function getAssetChecksum($assetList = [])
2104 foreach ($assetList as $asset)
2106 $result[$asset[
'PATH']] = $asset[
'FULL_PATH'];
2110 return md5(implode(
'_', $result));
2121 private function isAssetChanged($assetList = [], $infoFile =
'', $optimFile =
'', $unique =
false)
2126 'FILE_EXIST' =>
false,
2130 if (file_exists($infoFile) && file_exists($optimFile))
2136 $result[
'FILES_INFO'] = is_array($filesInfo) ? $filesInfo : [];
2137 $result[
'FILE_EXIST'] =
true;
2140 if (is_array($filesInfo))
2142 foreach ($assetList as $asset)
2144 if (isset($filesInfo[$asset[
'PATH']]))
2146 if ($this->getAssetTime($asset[
'FULL_PATH']) != $filesInfo[$asset[
'PATH']])
2149 'FILE' => $assetList,
2158 $result[
'FILE'][] = $asset;
2159 $result[
'ACTION'] =
'UP';
2166 'FILE' => $assetList,
2175 $result[
'FILE'] = $assetList;
2176 $result[
'ACTION'] =
'NEW';
2193 private function optimizeAsset($files = [], $unique =
false, $prefix =
'default', $setName =
'', $type =
'css', $data =
'')
2195 if ((!is_array($files) || empty($files)))
2197 return [
'RESULT' =>
'',
'FILES' => []];
2200 $this->setTemplateID();
2201 $res = $comments = $contents =
'';
2202 $prefix = trim($prefix);
2203 $prefix = mb_strlen($prefix) < 1 ?
'default' : $prefix;
2204 $add2End = (strncmp($prefix,
'kernel', 6) == 0);
2205 $type = ($type ==
'js' ?
'js' :
'css');
2208 $noCheckOnly = !defined(
'BX_HEADFILES_CACHE_CHECK_ONLY');
2209 $prefix = ($unique ? $prefix : $prefix.
'_'.$this->getAssetChecksum($files));
2211 $optimPath = BX_PERSONAL_ROOT.
'/cache/'.$type.
'/'.SITE_ID.
'/'.$this->siteTemplateID.
'/'.$prefix.
'/';
2213 $infoFile = $this->documentRoot.BX_PERSONAL_ROOT.
'/managed_cache/'.$this->dbType.
'/'.$type.
'/'.SITE_ID.
'/'.$this->siteTemplateID.
'/'.$prefix.
'/info_v'.self::version.
'.php';
2215 $optimFile = $optimPath.$prefix.
'_v'.self::version.($type ==
'css' ?
'.css' :
'.js');
2216 $optimFName = $this->documentRoot.$optimFile;
2218 $tmpInfo = $this->isAssetChanged($files, $infoFile, $optimFName, $unique);
2219 $filesInfo = $tmpInfo[
'FILES_INFO'];
2220 $action = $tmpInfo[
'ACTION'];
2221 $files = $tmpInfo[
'FILE'];
2222 $optimFileExist = $tmpInfo[
'FILE_EXIST'] ??
false;
2224 $writeResult = ($action !=
'NEW');
2225 $currentFileList = &$this->fileList[strtoupper($type)][$setName];
2227 if ($action !=
'NO')
2229 foreach ($tmpInfo[
'FILE'] as $newFile)
2231 $currentFileList[
'UP_NEW_FILES'][] = $newFile[
'FULL_PATH'];
2234 if ($action ==
'UP')
2238 $contents .= file_get_contents($optimFName);
2242 $writeResult =
false;
2251 foreach ($files as $file)
2253 $assetContent = file_get_contents($file[
'FILE_PATH']);
2256 $comments .=
"/* ".$file[
'FULL_PATH'].
" */\n";
2257 $assetContent = $this->fixCSSIncludes($assetContent, $file[
'PATH']);
2258 $assetContent =
"\n/* Start:".$file[
'FULL_PATH'].
"*/\n".$assetContent.
"\n/* End */\n";
2259 $newContent .=
"\n".$assetContent;
2264 "full" => $file[
'FULL_PATH'],
2265 "source" => $file[
'PATH'],
2270 if (preg_match(
"/\\.min\\.js$/i", $file[
'FILE_PATH']))
2272 $sourceMap = self::cutSourceMap($assetContent);
2273 if ($sourceMap <>
'')
2275 $dirPath = IO\Path::getDirectory($file[
'PATH']);
2276 $info[
"map"] = $dirPath.
"/".$sourceMap;
2277 $info[
"min"] = self::getAssetPath($file[
'FULL_PATH']);
2282 $comments .=
"; /* ".$file[
'FULL_PATH'].
"*/\n";
2283 $newContent .=
"\n".self::HEADER_START_TAG.serialize($info).self::HEADER_END_TAG.
"\n".$assetContent.
"\n/* End */\n;";
2286 $filesInfo[$file[
'PATH']] = $this->getAssetTime($file[
'FULL_PATH']);
2292 $sourceMap = self::cutSourceMap($contents);
2293 $mapNeeded = $mapNeeded || $sourceMap <>
'';
2296 $contents = ($add2End ? $comments.$contents.$newContent : $newContent.$contents.$comments);
2299 $contents .= self::SOURCE_MAP_TAG.$prefix.
".map.js";
2302 if ($writeResult = $this->write($optimFName, $contents))
2304 $cacheInfo =
'<?php $filesInfo = [';
2306 foreach ($filesInfo as $key => $hash)
2308 $cacheInfo .=
'"'.EscapePHPString($key).
'" => "'.$hash.
'",';
2311 $cacheInfo .=
"]; ?>";
2312 $this->write($infoFile, $cacheInfo,
false);
2316 $this->write($this->documentRoot.$optimPath.$prefix.
".map.js", self::generateSourceMap($prefix.
".js", $contents),
false);
2320 elseif ($optimFileExist)
2322 $writeResult =
true;
2328 $label = (($type ==
'css') && ($prefix ==
'template' || mb_substr($prefix, 0, 9) ==
'template_') ?
' data-template-style="true" ' :
'');
2331 $extendData = ($data !=
'' ?
' '.trim($data) :
'');
2332 $extendData .= ($label !=
'' ?
' '.trim($label) :
'');
2334 if ($writeResult || $unique && $action ==
'UP')
2336 $bundleFile = \CUtil::GetAdditionalFileURL($optimFile);
2337 $currentFileList[
'FILES'][] = $bundleFile;
2341 $res .= $this->insertCss($bundleFile, $extendData);
2345 $res .= $this->insertJs($bundleFile, $extendData);
2351 foreach ($files as $file)
2353 $currentFileList[
'FILES'][] = $file[
'FULL_PATH'];
2356 $res .= $this->insertCss($file[
'FULL_PATH'], $extendData);
2360 $res .= $this->insertJs($file[
'FULL_PATH'], $extendData);
2366 if (is_array($filesInfo))
2368 foreach ($filesInfo as $key => $hash)
2370 $resultFiles[] = $key.
'?'.$hash;
2377 if ($bundleFile !=
'')
2379 $currentFileList[
'FULL_FILES'][$bundleFile] = $resultFiles;
2381 return [
'RESULT' => $res,
'FILES' => $resultFiles,
'SOURCE_FILES' => array_keys($filesInfo)];
2389 private static function cutSourceMap(&$content)
2391 $sourceMapName =
"";
2393 $length = strlen($content);
2394 $position = $length > 512 ? $length - 512 : 0;
2395 $lastLine = strpos($content, self::SOURCE_MAP_TAG, $position);
2396 if ($lastLine !==
false)
2398 $nameStart = $lastLine + strlen(self::SOURCE_MAP_TAG);
2399 if (($newLinePos = strpos($content,
"\n", $nameStart)) !==
false)
2401 $sourceMapName = substr($content, $nameStart, $newLinePos - $nameStart);
2405 $sourceMapName = substr($content, $nameStart);
2408 $sourceMapName = trim($sourceMapName);
2409 $content = substr($content, 0, $lastLine);
2412 return $sourceMapName;
2420 private static function getFilesInfo($content)
2426 while (($newLinePos = strpos($content,
"\n", $offset)) !==
false)
2429 $offset = $newLinePos + 1;
2430 if (substr($content, $offset, strlen(self::HEADER_START_TAG)) === self::HEADER_START_TAG)
2432 $endingPos = strpos($content, self::HEADER_END_TAG, $offset);
2433 if ($endingPos ===
false)
2438 $startData = $offset + strlen(self::HEADER_START_TAG);
2439 $data = unserialize(substr($content, $startData, $endingPos - $startData), [
'allowed_classes' =>
false]);
2441 if (is_array($data))
2443 $data[
"line"] = $line + 1;
2447 $offset = $endingPos;
2460 private static function generateSourceMap($fileName, $content)
2462 $files = self::getFilesInfo($content);
2464 foreach ($files as $file)
2466 if (!isset($file[
"map"]) || mb_strlen($file[
"map"]) < 1)
2471 $filePath = Main\Loader::getDocumentRoot().$file[
"map"];
2472 if (file_exists($filePath) && ($content = file_get_contents($filePath)) !==
false)
2474 if ($sections !==
"")
2479 $dirPath = IO\Path::getDirectory($file[
"source"]);
2480 $sourceName = IO\Path::getName($file[
"source"]);
2481 $minName = IO\Path::getName($file[
"min"]);
2483 $sourceMap = str_replace(
2484 [$sourceName, $minName],
2485 [$dirPath.
"/".$sourceName, $dirPath.
"/".$minName],
2488 $sections .=
'{"offset": { "line": '.$file[
"line"].
', "column": 0 }, "map": '.$sourceMap.
'}';
2492 return '{"version":3, "file":"'.$fileName.
'", "sections": ['.$sections.
']}';
2502 function write($filePath, $content, $gzip =
true)
2504 $fnTmp = $filePath.
'.tmp';
2506 if (!CheckDirPath($filePath) || !$fh = fopen($fnTmp,
"wb"))
2511 $written = fwrite($fh, $content);
2512 $len = strlen($content);
2515 if (file_exists($filePath))
2521 if ($written === $len)
2524 rename($fnTmp, $filePath);
2525 @chmod($filePath, BX_FILE_PERMISSIONS);
2526 if ($gzip && self::gzipEnabled())
2528 $fnTmpGz = $filePath.
'.tmp.gz';
2529 $fnGz = $filePath.
'.gz';
2531 if ($gz = gzopen($fnTmpGz,
'wb9f'))
2533 $writtenGz = @gzwrite ($gz, $content);
2536 if (file_exists($fnGz))
2541 if ($writtenGz === $len)
2543 rename($fnTmpGz, $fnGz);
2544 @chmod($fnGz, BX_FILE_PERMISSIONS);
2547 if (file_exists($fnTmpGz))
2555 if (file_exists($fnTmp))