From e2ab33b3d17cd28f3015371ec1f617531cac5886 Mon Sep 17 00:00:00 2001 From: Teisha McRae Date: Wed, 18 Sep 2024 13:31:50 -0400 Subject: [PATCH 1/7] Add route for applyTemplate --- ProcessMaker/Http/Controllers/Api/TemplateController.php | 5 +++++ ProcessMaker/Models/Template.php | 5 +++++ routes/api.php | 1 + 3 files changed, 11 insertions(+) diff --git a/ProcessMaker/Http/Controllers/Api/TemplateController.php b/ProcessMaker/Http/Controllers/Api/TemplateController.php index 0cb2426fa7..213f44c2ca 100644 --- a/ProcessMaker/Http/Controllers/Api/TemplateController.php +++ b/ProcessMaker/Http/Controllers/Api/TemplateController.php @@ -242,6 +242,11 @@ public function deleteMediaImages(string $type, Request $request) return $this->template->deleteMediaImages($type, $request); } + public function applyTemplate(string $type, Request $request) + { + return $this->template->applyTemplate($type, $request); + } + private function validateImportedFile($content, $request, $type) { $decoded = null; diff --git a/ProcessMaker/Models/Template.php b/ProcessMaker/Models/Template.php index 6fc29dcd3a..1a7ed2768c 100644 --- a/ProcessMaker/Models/Template.php +++ b/ProcessMaker/Models/Template.php @@ -101,6 +101,11 @@ public function deleteMediaImages(string $type, Request $request) return (new $this->types[$type][1])->deleteMediaImages($request); } + public function applyTemplate(string $type, Request $request) + { + return (new $this->types[$type][1])->applyTemplate($request); + } + public function user() { return $this->belongsTo(User::class, 'user_id'); diff --git a/routes/api.php b/routes/api.php index 4e55539bbe..c2c68b792a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -330,6 +330,7 @@ Route::get('modeler/templates/{type}/{id}', [TemplateController::class, 'show'])->name('modeler.template.show')->middleware('template-authorization'); Route::post('templates/{type}/import/validation', [TemplateController::class, 'preImportValidation'])->name('template.preImportValidation')->middleware('template-authorization'); Route::post('template/{type}/{id}/publish', [TemplateController::class, 'publishTemplate'])->name('template.publishTemplate')->middleware('can:publish-screen-templates'); + Route::post('template/{type}/{id}/apply', [TemplateController::class, 'applyTemplate'])->name('template.applyTemplate')->middleware('template-authorization'); Route::get('screen-builder/{type}/{id}', [TemplateController::class, 'show'])->name('screenBuilder.template.show')->middleware('template-authorization'); // Wizard Templates From 303054f5e5ebaf6a41225ed252e2b453d87998e0 Mon Sep 17 00:00:00 2001 From: Teisha McRae Date: Wed, 18 Sep 2024 13:33:41 -0400 Subject: [PATCH 2/7] Apply CSS to Screen --- ProcessMaker/Helpers/ScreenTemplateHelper.php | 68 +++++++++++++++++++ ProcessMaker/Templates/ScreenTemplate.php | 33 +++++++++ 2 files changed, 101 insertions(+) diff --git a/ProcessMaker/Helpers/ScreenTemplateHelper.php b/ProcessMaker/Helpers/ScreenTemplateHelper.php index b8360b3496..b2c64b5e23 100644 --- a/ProcessMaker/Helpers/ScreenTemplateHelper.php +++ b/ProcessMaker/Helpers/ScreenTemplateHelper.php @@ -250,4 +250,72 @@ private static function flattenNestedItems($items) return $flattenedItems; } + + // Parse the CSS string into an associative array + public static function parseCss($cssString) + { + $rules = []; + // Regex to match complex CSS selectors, allowing for any selector pattern + preg_match_all('/\[selector="([\w-]+)"\]\s*([^{]+)\s*{([^}]+)}/', $cssString, $matches, PREG_SET_ORDER); + + foreach ($matches as $match) { + $baseSelector = $match[1]; + $additionalSelector = trim($match[2]); + $fullSelector = "[selector=\"$baseSelector\"] " . $additionalSelector; + $propertiesString = trim($match[3]); + + // Split properties into key-value pairs + $propertiesArray = explode(';', $propertiesString); + $properties = []; + + foreach ($propertiesArray as $property) { + $propertyParts = explode(':', $property); + if (count($propertyParts) == 2) { + $key = trim($propertyParts[0]); + $value = trim($propertyParts[1]); + if (!empty($key) && !empty($value)) { + $properties[$key] = $value; + } + } + } + + $rules[$fullSelector] = $properties; + } + + return $rules; + } + + // Merge the two CSS arrays + public static function mergeCss($currentCss, $templateCss) + { + foreach ($templateCss as $selector => $properties) { + if (isset($currentCss[$selector])) { + // Merge properties from Template CSS into the Current Screen CSS for the same selector + $currentCss[$selector] = array_merge($currentCss[$selector], $properties); + } else { + // Add new selector and properties from Template CSS + $currentCss[$selector] = $properties; + } + } + + return $currentCss; + } + + public static function generateCss($cssArray) + { + // Convert the CSS array back into a string and output the final CSS + $cssString = ''; + + foreach ($cssArray as $selector => $properties) { + $cssString .= "$selector {\n"; + + foreach ($properties as $key => $value) { + $cssString .= " $key: $value;\n"; + } + + $cssString .= "}\n\n"; + } + + return $cssString; + } } diff --git a/ProcessMaker/Templates/ScreenTemplate.php b/ProcessMaker/Templates/ScreenTemplate.php index 7c77db54c2..544f9b9f11 100644 --- a/ProcessMaker/Templates/ScreenTemplate.php +++ b/ProcessMaker/Templates/ScreenTemplate.php @@ -677,6 +677,39 @@ public function syncProjectAssets($data, int $newScreenId): void } } + // Applies the template to an existing screen in screen builder + public function applyTemplate($request) + { + // Get the selected template + $templateId = (int) $request->id; + $template = ScreenTemplates::findOrFail($templateId); + + // Get the selected template options + $templateOptions = $request->get('templateOptions'); + // Get the current screen to apply the template + $screenId = $request->get('screenId'); + $screen = Screen::where('id', $screenId)->first(); + // Define available options and their corresponding components + $availableOptions = ScreenComponents::getComponents(); + + if (is_array($templateOptions)) { + // Iterate through available options to handle each one + foreach ($availableOptions as $option => $components) { + // Apply the CSS to the current screen + if ($option == 'CSS' && in_array($option, $templateOptions)) { + $currentScreenCssArray = ScreenTemplateHelper::parseCss($screen->custom_css); + $templateCssArray = ScreenTemplateHelper::parseCss($template->screen_custom_css); + $mergedCss = ScreenTemplateHelper::mergeCss($currentScreenCssArray, $templateCssArray); + + $finalCss = ScreenTemplateHelper::generateCss($mergedCss); + $screen->custom_css = $finalCss; + } + + $screen->save(); + } + } + } + private function syncTemplateMedia($template, $media) { // Get the UUIDs of updated media From 1c9147646de6c9c526e49090fa616806248c9a94 Mon Sep 17 00:00:00 2001 From: Teisha McRae Date: Wed, 18 Sep 2024 14:45:24 -0400 Subject: [PATCH 3/7] Update regex in ScreenTemplateHelper --- ProcessMaker/Helpers/ScreenTemplateHelper.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ProcessMaker/Helpers/ScreenTemplateHelper.php b/ProcessMaker/Helpers/ScreenTemplateHelper.php index b2c64b5e23..652591f1c9 100644 --- a/ProcessMaker/Helpers/ScreenTemplateHelper.php +++ b/ProcessMaker/Helpers/ScreenTemplateHelper.php @@ -256,13 +256,11 @@ public static function parseCss($cssString) { $rules = []; // Regex to match complex CSS selectors, allowing for any selector pattern - preg_match_all('/\[selector="([\w-]+)"\]\s*([^{]+)\s*{([^}]+)}/', $cssString, $matches, PREG_SET_ORDER); + preg_match_all('/([^{}]+)\s*\{([^}]*)\}/', $cssString, $matches, PREG_SET_ORDER); foreach ($matches as $match) { - $baseSelector = $match[1]; - $additionalSelector = trim($match[2]); - $fullSelector = "[selector=\"$baseSelector\"] " . $additionalSelector; - $propertiesString = trim($match[3]); + $fullSelector = trim($match[1]); // Full CSS selector + $propertiesString = trim($match[2]); // Properties between the brackets // Split properties into key-value pairs $propertiesArray = explode(';', $propertiesString); @@ -279,6 +277,7 @@ public static function parseCss($cssString) } } + // Add rule for the selector $rules[$fullSelector] = $properties; } From 37db6943b43abd9ce4be28043f77da7290603854 Mon Sep 17 00:00:00 2001 From: Teisha McRae Date: Thu, 19 Sep 2024 11:00:41 -0400 Subject: [PATCH 4/7] Remove components where necessary when filtering field and layout options --- ProcessMaker/Helpers/ScreenTemplateHelper.php | 57 +++++++++++++++---- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/ProcessMaker/Helpers/ScreenTemplateHelper.php b/ProcessMaker/Helpers/ScreenTemplateHelper.php index 652591f1c9..20248db94d 100644 --- a/ProcessMaker/Helpers/ScreenTemplateHelper.php +++ b/ProcessMaker/Helpers/ScreenTemplateHelper.php @@ -27,6 +27,33 @@ public static function removeScreenComponents($config, $components) return $updatedConfig; } + /** + * Filters and retrieves screen components from the provided configuration. + * + * This method processes the given screen configuration, iterating through each page + * to filter its items based on the specified components. It can optionally remove + * components from the configuration or keep only the specified components. + * @param array $config The full screen configuration + * @param array $components An array of component names that will be used to filter + * the items in the configuration. + * @param bool $removeComponents (optional) Determines the filtering behavior: + * - If 'true', the components in the `$components` array will be removed from the configuration + * - If 'false', only the components in the `$components` array will be retained + * Defaults to `true`. + * + * @return array The updated configuration after filtering the components. + */ + public static function getScreenComponents($config, $components, $removeComponents = true) + { + foreach ($config as $page) { + $filteredPageItems = self::filterPageItems($page['items'] ?? [], $components, $removeComponents); + $page['items'] = $filteredPageItems; + $updatedConfig[] = $page; + } + + return $updatedConfig; + } + /** * Filter items of a page based on the provided components. * @@ -36,14 +63,15 @@ public static function removeScreenComponents($config, $components) * * @param array $items The items of a page to filter. * @param array $components The components to filter the items against. + * @param bool $removeComponents Whether to remove. * @return array The filtered items of the page. */ - private static function filterPageItems($items, $components) + private static function filterPageItems($items, $components, $removeComponents = true) { $filteredItems = []; foreach ($items as $item) { - $filteredItem = self::filterItemByComponent($item, $components); + $filteredItem = self::filterItemByComponent($item, $components, $removeComponents); if ($filteredItem !== null) { if (is_array($filteredItem) && !isset($filteredItem['component'])) { $filteredItems = array_merge($filteredItems, self::flattenNestedItems($filteredItem)); @@ -67,15 +95,16 @@ private static function filterPageItems($items, $components) * * @param array $item The item to filter. * @param array $components The components to filter against. + * @param bool $removeComponents Whether to remove. * @return array|null The filtered item or null if it should be removed. */ - private static function filterItemByComponent($item, $components) + private static function filterItemByComponent($item, $components, $removeComponents = true) { if ($item['component'] === 'FormMultiColumn') { - return self::filterFormMultiColumn($item, $components); + return self::filterFormMultiColumn($item, $components, $removeComponents); } - return !self::removeNestedComponents($item, $components) ? $item : null; + return !self::removeNestedComponents($item, $components, $removeComponents) ? $item : null; } /** @@ -88,15 +117,16 @@ private static function filterItemByComponent($item, $components) * * @param array $item The 'FormMultiColumn' item to filter. * @param array $components The components to filter against. + * @param bool $removeComponents Whether to remove. * @return array The filtered 'FormMultiColumn' item. */ - private static function filterFormMultiColumn($item, $components) + private static function filterFormMultiColumn($item, $components, $removeComponents = true) { - $removeMultiColumn = self::removeNestedComponents($item, $components); + $removeMultiColumn = self::removeNestedComponents($item, $components, $removeComponents); $filteredMultiColumnItems = $removeMultiColumn ? [] : $item; foreach ($item['items'] as $index => $column) { - $filteredColumnItems = self::filterColumnItems($column, $components, $removeMultiColumn); + $filteredColumnItems = self::filterColumnItems($column, $components, $removeMultiColumn, $removeComponents); if (isset($filteredMultiColumnItems['items'])) { $filteredMultiColumnItems['items'][$index] = $filteredColumnItems; @@ -117,9 +147,10 @@ private static function filterFormMultiColumn($item, $components) * * @param array $item The item to check for removal. * @param array $components The screen components to filter against. + * @param bool $removeComponents Whether to remove. * @return bool Whether the item should be removed. */ - private static function removeNestedComponents($item, $components) + private static function removeNestedComponents($item, $components, $removeComponents = true) { $componentList = ['BFormComponent', 'BWrapperComponent']; if (in_array($item['component'], $componentList)) { @@ -128,7 +159,8 @@ private static function removeNestedComponents($item, $components) return in_array($bootstrapComponent, $components[$item['component']]['bootstrapComponent']); } } else { - return in_array($item['component'], $components); + return in_array($item['component'], $components) && $removeComponents || + !$removeComponents && !in_array($item['component'], $components); } return false; @@ -145,10 +177,11 @@ private static function removeNestedComponents($item, $components) * * @param array $column The column items to filter. * @param array $components The components to filter against. + * @param bool $removeComponents Whether to remove. * @param bool $removeMultiColumn Whether the entire 'FormMultiColumn' should be removed. * @return array The filtered column items. */ - private static function filterColumnItems($column, $components, $removeMultiColumn) + private static function filterColumnItems($column, $components, $removeMultiColumn, $removeComponents = true) { $filteredColumnItems = []; @@ -156,7 +189,7 @@ private static function filterColumnItems($column, $components, $removeMultiColu if (isset($colItem['component']) && $colItem['component'] === 'FormMultiColumn') { self::filterNestedMultiColumns($colItem, $components, $removeMultiColumn); $filteredColumnItems[] = $colItem; - } elseif (!self::removeNestedComponents($colItem, $components)) { + } elseif (!self::removeNestedComponents($colItem, $components, $removeComponents)) { $filteredColumnItems[] = $colItem; } } From 31684362291cb450ed385bde408cebf1f0dac11e Mon Sep 17 00:00:00 2001 From: Teisha McRae Date: Thu, 19 Sep 2024 11:01:20 -0400 Subject: [PATCH 5/7] Update applyTemplate method and handleTemplateImport --- ProcessMaker/Templates/ScreenTemplate.php | 169 ++++++++++++++++++---- 1 file changed, 143 insertions(+), 26 deletions(-) diff --git a/ProcessMaker/Templates/ScreenTemplate.php b/ProcessMaker/Templates/ScreenTemplate.php index 544f9b9f11..1c99968525 100644 --- a/ProcessMaker/Templates/ScreenTemplate.php +++ b/ProcessMaker/Templates/ScreenTemplate.php @@ -6,7 +6,9 @@ use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Log; use ProcessMaker\Events\TemplateCreated; use ProcessMaker\Helpers\ScreenTemplateHelper; use ProcessMaker\ImportExport\Importer; @@ -677,39 +679,154 @@ public function syncProjectAssets($data, int $newScreenId): void } } - // Applies the template to an existing screen in screen builder - public function applyTemplate($request) + /** + * Apply a selected template to the specified screen in screen builder + * @param Request $request + * The request should contain: + * - 'id': The ID of the selected template to apply + * - 'screenId': The ID of the screen where the template will be applied + * - 'templateOptions': An array of options that specify how to apply the template. + * @return void + * @throws ModelNotFoundException If the template or screen is not found in the database + * @throws Exception If there is an error during the template application process. + */ + public function applyTemplate(Request $request) { - // Get the selected template - $templateId = (int) $request->id; - $template = ScreenTemplates::findOrFail($templateId); + try { + // Get the selected template + $templateId = (int) $request->id; + $template = ScreenTemplates::findOrFail($templateId); + + // Import the template to get the screen config + $newScreenId = $this->handleTemplateImport($template); + $newTemplateScreen = Screen::select('config')->where('id', $newScreenId)->firstOrFail(); + // Get the current screen to apply the template + $screenId = $request->get('screenId'); + $screen = Screen::where('id', $screenId)->firstOrFail(); + $currentScreenPage = $request->get('currentScreenPage'); + // Get the selected template options + $templateOptions = $request->get('templateOptions', []); + $supportedOptionComponents = ScreenComponents::getComponents(); + + if (is_array($templateOptions)) { + foreach ($templateOptions as $option) { + $this->applyTemplateOption($option, $supportedOptionComponents, $template, + $newTemplateScreen, $screen, $templateOptions, $currentScreenPage); + } + $screen->save(); // Save the updated screen + } + Screen::where('id', $newScreenId)->delete(); // Clean up the temporary imported template screen + } catch (ModelNotFoundException $e) { + Log::error('Template or screen not found: ' . $e->getMessage()); + throw new ModelNotFoundException('Template or screen not found.'); + } catch (Exception $e) { + Log::error('Error applying template: ' . $e->getMessage()); + throw new Exception('Failed to apply template.'); + } + } - // Get the selected template options - $templateOptions = $request->get('templateOptions'); - // Get the current screen to apply the template - $screenId = $request->get('screenId'); - $screen = Screen::where('id', $screenId)->first(); - // Define available options and their corresponding components - $availableOptions = ScreenComponents::getComponents(); + private function handleTemplateImport($template) + { + $payload = $this->filterPayload(json_decode($template->manifest, true)); + $options = new Options($this->generatePostOptions($payload)); + $importer = new Importer($payload, $options); + $manifest = $importer->doImport(null, true); - if (is_array($templateOptions)) { - // Iterate through available options to handle each one - foreach ($availableOptions as $option => $components) { - // Apply the CSS to the current screen - if ($option == 'CSS' && in_array($option, $templateOptions)) { - $currentScreenCssArray = ScreenTemplateHelper::parseCss($screen->custom_css); - $templateCssArray = ScreenTemplateHelper::parseCss($template->screen_custom_css); - $mergedCss = ScreenTemplateHelper::mergeCss($currentScreenCssArray, $templateCssArray); - - $finalCss = ScreenTemplateHelper::generateCss($mergedCss); - $screen->custom_css = $finalCss; - } + // Return the new screen ID from import log + return $manifest[$payload['root']]->log['newId']; + } - $screen->save(); - } + private function filterPayload($payload) + { + // Exclude screen categories from payload + $payload['export'] = array_filter($payload['export'], function ($asset) { + return $asset['model'] !== 'ProcessMaker\Models\ScreenCategory'; + }); + + return $payload; + } + + private function generatePostOptions($payload) + { + return array_map(function () { + return [ + 'mode' => 'copy', + 'isTemplate' => true, + 'saveAssetMode' => 'saveAllAssets', + ]; + }, $payload['export']); + } + + private function applyTemplateOption($option, $supportedOptionComponents, + $template, $newTemplateScreen, $screen, $templateOptions, $currentScreenPage) + { + // Check if the option is supported before applying + if (!array_key_exists($option, $supportedOptionComponents)) { + return; + } + switch ($option) { + case 'CSS': + $this->mergeCss($screen, $template); + break; + case 'Layout': + $this->mergeLayout($screen, $currentScreenPage, $newTemplateScreen, + $templateOptions, $supportedOptionComponents[$option]); + break; + case 'Fields': + $this->mergeFields($screen, $currentScreenPage, $newTemplateScreen, + $templateOptions, $supportedOptionComponents[$option]); + break; + default: + break; } } + private function mergeCss($screen, $template) + { + $currentScreenCss = ScreenTemplateHelper::parseCss($screen->custom_css); + $templateCss = ScreenTemplateHelper::parseCss($template->screen_custom_css); + + $mergedCss = ScreenTemplateHelper::mergeCss($currentScreenCss, $templateCss); + $screen->custom_css = ScreenTemplateHelper::generateCss($mergedCss); + } + + private function mergeLayout($screen, $currentScreenPage, $newTemplateScreen, + $templateOptions, $supportedComponents) + { + $templateComponents = $this->getTemplateComponents($newTemplateScreen, $templateOptions, $supportedComponents); + + $screenConfig = $screen->config; + $screenConfig[$currentScreenPage]['items'] = + array_merge($screenConfig[$currentScreenPage]['items'], $templateComponents); + + $screen->config = $screenConfig; + } + + private function mergeFields($screen, $currentScreenPage, $newTemplateScreen, + $templateOptions, $supportedComponents) + { + // Skip merging layout if 'Layout' is part of template options + if (!in_array('Layout', $templateOptions)) { + $templateComponents = + $this->getTemplateComponents($newTemplateScreen, $templateOptions, $supportedComponents); + + $screenConfig = $screen->config; + $screenConfig[$currentScreenPage]['items'] = + array_merge($screenConfig[$currentScreenPage]['items'], $templateComponents); + + $screen->config = $screenConfig; + } + } + + private function getTemplateComponents($newTemplateScreen, $templateOptions, $supportedComponents) + { + return !in_array('Fields', $templateOptions) + ? ScreenTemplateHelper::getScreenComponents($newTemplateScreen->config, + $supportedComponents, false)[0]['items'] + ?? [] + : $newTemplateScreen->config[0]['items'] ?? []; + } + private function syncTemplateMedia($template, $media) { // Get the UUIDs of updated media From 694f20ffd590c62752c5217ec754e3edb494071a Mon Sep 17 00:00:00 2001 From: Teisha McRae Date: Thu, 19 Sep 2024 14:31:47 -0400 Subject: [PATCH 6/7] If screen config null, set items array --- ProcessMaker/Templates/ScreenTemplate.php | 29 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/ProcessMaker/Templates/ScreenTemplate.php b/ProcessMaker/Templates/ScreenTemplate.php index 1c99968525..a1dd1d6533 100644 --- a/ProcessMaker/Templates/ScreenTemplate.php +++ b/ProcessMaker/Templates/ScreenTemplate.php @@ -790,27 +790,34 @@ private function mergeCss($screen, $template) $screen->custom_css = ScreenTemplateHelper::generateCss($mergedCss); } - private function mergeLayout($screen, $currentScreenPage, $newTemplateScreen, - $templateOptions, $supportedComponents) + private function mergeLayout($screen, $currentScreenPage, $newTemplateScreen, $templateOptions, $supportedComponents) { $templateComponents = $this->getTemplateComponents($newTemplateScreen, $templateOptions, $supportedComponents); + if (is_null($screen->config)) { + $this->setScreenConfig($screen); + } + $screenConfig = $screen->config; + $screenConfig[$currentScreenPage]['items'] = array_merge($screenConfig[$currentScreenPage]['items'], $templateComponents); - $screen->config = $screenConfig; } - private function mergeFields($screen, $currentScreenPage, $newTemplateScreen, - $templateOptions, $supportedComponents) + private function mergeFields($screen, $currentScreenPage, $newTemplateScreen, $templateOptions, $supportedComponents) { // Skip merging layout if 'Layout' is part of template options if (!in_array('Layout', $templateOptions)) { $templateComponents = $this->getTemplateComponents($newTemplateScreen, $templateOptions, $supportedComponents); + if (is_null($screen->config)) { + $this->setScreenConfig($screen); + } + $screenConfig = $screen->config; + $screenConfig[$currentScreenPage]['items'] = array_merge($screenConfig[$currentScreenPage]['items'], $templateComponents); @@ -827,6 +834,18 @@ private function getTemplateComponents($newTemplateScreen, $templateOptions, $su : $newTemplateScreen->config[0]['items'] ?? []; } + private function setScreenConfig($screen) + { + $screen->config = + [ + [ + 'items' => [], + ], + ]; + + return $screen->config; + } + private function syncTemplateMedia($template, $media) { // Get the UUIDs of updated media From c28c1d224cc3378eaedc03277afeac06098fb2c6 Mon Sep 17 00:00:00 2001 From: Teisha McRae Date: Thu, 19 Sep 2024 15:48:38 -0400 Subject: [PATCH 7/7] Update regex to capture CSS comments --- ProcessMaker/Helpers/ScreenTemplateHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProcessMaker/Helpers/ScreenTemplateHelper.php b/ProcessMaker/Helpers/ScreenTemplateHelper.php index 20248db94d..c3ebf99ed0 100644 --- a/ProcessMaker/Helpers/ScreenTemplateHelper.php +++ b/ProcessMaker/Helpers/ScreenTemplateHelper.php @@ -289,7 +289,7 @@ public static function parseCss($cssString) { $rules = []; // Regex to match complex CSS selectors, allowing for any selector pattern - preg_match_all('/([^{}]+)\s*\{([^}]*)\}/', $cssString, $matches, PREG_SET_ORDER); + preg_match_all('/(?:\/\*.*?\*\*\/|([^{}]+))\s*\{(?:\/\*.*?\*\*\/|([^}]*))\}/', $cssString, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $fullSelector = trim($match[1]); // Full CSS selector