11 parent::__construct();
13 $this->
_fd =
'dbxAdmin|module-admin';
19 $tpl =
dbx()->get_system_obj(
'dbxTPL');
20 $active = (string)($record[
'active'] ??
'1') ===
'1';
21 $record[
'active_label'] = $this->
get_fd_message($active ?
'active' :
'inactive');
23 $record[
'graphic_html'] = $this->renderModuleImages($record);
24 $record[
'groups_html'] = $this->renderGroups($record);
25 $record[
'dd_html'] = $this->renderDdList($record);
26 $record[
'card_state_class'] = ((string)($record[
'active'] ??
'1') ===
'0') ?
' dbx-module-row-inactive' :
'';
27 $record[
'install_button_html'] = $this->renderInstallButton($record);
28 $record[
'active_toggle_button_html'] = $this->renderActiveToggleButton($record);
29 $record[
'delete_button_html'] = $this->renderDeleteButton($record);
30 $record[
'actions_html'] =
$tpl->get_tpl(
'dbxAdmin|module-card-actions', $record);
31 $record[
'access_inline_html'] = $this->renderAccessInline($record);
32 $record[
'select_html'] = $this->_create_row_select
35 return $tpl->get_tpl(
'dbxAdmin|module-card', $record);
39 return $this->renderDdList($record);
43 $record = is_array($this->_record) ? $this->_record : array();
47 if (strpos(
$content,
'[rpt:row]') !==
false) {
57 return $this->buildModuleImagesTargetHtml($record);
61 return $this->buildModuleImagesGalleryHtml($record);
64 private function renderModuleImages(array $record): string {
65 $tpl =
dbx()->get_system_obj(
'dbxTPL');
66 $defaultRun1 = trim((
string)($record[
'default_run1'] ??
'run'));
67 if ($defaultRun1 ===
'') {
70 $defaultRun2 = trim((
string)($record[
'default_run2'] ??
''));
71 $record[
'symbol_preview_html'] = $this->buildModuleSymbolPreviewHtml($record);
72 $record[
'images_gallery_html'] = $this->buildModuleImagesGalleryHtml($record);
73 $record[
'default_run1'] =
dbx()->esc($defaultRun1);
74 $record[
'default_run2'] =
dbx()->esc($defaultRun2);
75 $record[
'image_count'] = (string)count($record[
'image_items'] ?? array());
76 $record[
'images_add_url'] =
dbx()->esc((
string)($record[
'images_add_url'] ??
''));
77 $record[
'images_upload_url'] =
dbx()->esc((
string)($record[
'images_upload_url'] ??
''));
78 $record[
'images_remove_url'] =
dbx()->esc((
string)($record[
'images_remove_url'] ??
''));
79 $record[
'symbol_add_url'] =
dbx()->esc((
string)($record[
'symbol_add_url'] ??
'?dbx_modul=dbxAdmin&dbx_run1=modules&dbx_run2=modul_symbol_add'));
80 $record[
'symbol_media_url'] =
dbx()->esc((
string)($record[
'symbol_media_url'] ??
'?dbx_modul=dbxContent_admin&dbx_run1=cms_media&images=1&media_type=image'));
81 $record[
'symbol_upload_url'] =
dbx()->esc((
string)($record[
'symbol_upload_url'] ??
'?dbx_modul=dbxContent_admin&dbx_run1=cms_upload'));
82 $record[
'symbol_mediafolders_url'] =
dbx()->esc((
string)($record[
'symbol_mediafolders_url'] ??
'?dbx_modul=dbxContent_admin&dbx_run1=cms_media_folders'));
83 $record[
'symbol_mediafoldercreate_url'] =
dbx()->esc((
string)($record[
'symbol_mediafoldercreate_url'] ??
'?dbx_modul=dbxContent_admin&dbx_run1=cms_media_folder_create'));
84 $record[
'symbol_mediafolderdelete_url'] =
dbx()->esc((
string)($record[
'symbol_mediafolderdelete_url'] ??
'?dbx_modul=dbxContent_admin&dbx_run1=cms_media_folder_delete'));
85 $record[
'symbol_deletemedia_url'] =
dbx()->esc((
string)($record[
'symbol_deletemedia_url'] ??
'?dbx_modul=dbxContent_admin&dbx_run1=cms_delete_media'));
86 $record[
'placeholder_url'] =
dbx()->esc((
string)($record[
'placeholder_url'] ??
''));
87 $record[
'placeholder_alt'] =
dbx()->esc($this->moduleImagesPlaceholderAlt());
88 $run1List = $this->buildModuleImagesRun1Datalist($record, $defaultRun1);
89 $record[
'run1_list_id'] =
dbx()->esc((
string)($run1List[
'id'] ??
''));
90 $record[
'run1_options_html'] = (string)($run1List[
'options_html'] ??
'');
91 return $tpl->get_tpl(
'dbxAdmin|module-card-images', $record);
94 private function buildModuleImagesRun1Datalist(array $record,
string $defaultRun1): array {
95 $modul = (string)($record[
'xmodul'] ??
'mod');
96 $listId =
'dbx_modimg_run1_' . preg_replace(
'/[^a-zA-Z0-9_]/',
'_', $modul);
97 $cases = $record[
'run_cases'] ?? array();
101 if (!
$cases && $defaultRun1 !==
'') {
102 $cases = array($defaultRun1);
107 foreach (
$cases as $run1) {
108 $run1 = trim((
string)$run1);
109 if ($run1 ===
'' || isset($seen[$run1])) {
113 $options .=
'<option value="' .
dbx()->esc($run1) .
'"></option>';
122 private function buildModuleSymbolPreviewHtml(array $record): string {
123 $modul =
dbx()->
esc((string)($record[
'xmodul'] ??
''));
124 $url =
dbx()->esc((
string)($record[
'graphic_url'] ??
''));
125 $alt =
dbx()->esc((
string)($record[
'graphic_alt'] ?? $modul));
128 return '<img src="' .
$url .
'" alt="' . $alt .
'" class="dbx-module-symbol-img" loading="lazy">';
131 $placeholder =
dbx()->esc($this->moduleImagesPlaceholderUrl($record));
132 if ($placeholder !==
'') {
133 return '<img src="' . $placeholder .
'" alt="' .
dbx()->esc($this->moduleImagesPlaceholderAlt()) .
'" class="dbx-module-symbol-img is-placeholder" loading="lazy">';
136 return '<span class="dbx-module-images-placeholder-icon" aria-hidden="true"><i class="bi bi-box-seam"></i></span>';
139 private function moduleImagesPlaceholderUrl(array $record): string {
140 return $this->registry->moduleImageEmptyPlaceholderUrl();
143 private function moduleImagesPlaceholderAlt(): string {
144 return $this->get_fd_message(
'placeholder_alt');
147 private function buildModuleImagesPreviewHtml(array $record): string {
148 $modul =
dbx()->
esc((string)($record[
'xmodul'] ??
''));
149 $items = $record[
'image_items'] ?? array();
153 $label =
dbx()->esc((
string)(
$first[
'label'] ?? (
$first[
'file'] ?? $modul)));
155 return '<img src="' .
$url .
'" alt="' . $label .
'" class="dbx-module-images-preview-img" loading="lazy">';
159 $placeholder =
dbx()->esc($this->moduleImagesPlaceholderUrl($record));
160 if ($placeholder !==
'') {
161 $alt =
dbx()->esc($this->moduleImagesPlaceholderAlt());
162 return '<img src="' . $placeholder .
'" alt="' . $alt .
'" class="dbx-module-images-preview-img is-placeholder" loading="lazy">';
165 return '<span class="dbx-module-images-placeholder-icon" aria-hidden="true"><i class="bi bi-box-seam"></i></span>';
168 private function buildModuleImagesTargetHtml(array $record): string {
169 $modul =
dbx()->
esc((string)($record[
'xmodul'] ??
''));
170 $defaultRun1 = trim((
string)($record[
'default_run1'] ??
'run'));
171 if ($defaultRun1 ===
'') {
172 $defaultRun1 =
'run';
174 $defaultRun2 = trim((
string)($record[
'default_run2'] ??
''));
175 $usesRun2 = (string)($record[
'uses_run2'] ??
'0') ===
'1';
176 $cases = $record[
'run_cases'] ?? array();
181 $cases = array($defaultRun1);
184 $listId =
'dbx_modimg_run1_' . preg_replace(
'/[^a-zA-Z0-9_]/',
'_', (
string)($record[
'xmodul'] ??
'mod'));
187 foreach (
$cases as $run1) {
188 $run1 = trim((
string)$run1);
189 if ($run1 ===
'' || isset($seen[$run1])) {
193 $selected = ($run1 === $defaultRun1) ?
' selected' :
'';
194 $options .=
'<option value="' .
dbx()->esc($run1) .
'"' . $selected .
'>' .
dbx()->esc($run1) .
'</option>';
197 $run2Class =
'dbx-module-images-run2-wrap';
200 $images =
new dbxModuleImages();
201 $previewName =
dbx()->esc($images->stemForRuns((
string)($record[
'xmodul'] ??
''), $defaultRun1, $defaultRun2) .
'.*');
203 return '<div class="dbx-module-images-target">'
204 .
'<label class="dbx-module-images-target-field">'
205 .
'<span>dbx_run1</span>'
206 .
'<input type="text" class="form-control form-control-sm dbx-module-images-run1" list="' . $listId .
'" value="' .
dbx()->esc($defaultRun1) .
'" placeholder="' .
dbx()->esc($this->get_fd_message(
'run1_placeholder')) .
'" required>'
207 .
'<datalist id="' . $listId .
'">' .
$options .
'</datalist>'
209 .
'<label class="' . $run2Class .
' dbx-module-images-target-field">'
210 .
'<span>dbx_run2</span>'
211 .
'<input type="text" class="form-control form-control-sm dbx-module-images-run2" value="' .
dbx()->esc($defaultRun2) .
'" placeholder="' .
dbx()->esc($this->get_fd_message(
'optional')) .
'"' . $run2Disabled .
'>'
213 .
'<div class="dbx-module-images-filename">'
214 .
'<span>' .
dbx()->esc($this->get_fd_message(
'filename')) .
'</span>'
215 .
'<code class="dbx-module-images-filename-preview" data-modul="' . $modul .
'">' . $previewName .
'</code>'
220 private function resolveImagePreviewRuns(array $item, array $record): array {
221 $run1 = trim((string)($item[
'run1'] ??
''));
222 $run2 = trim((
string)($item[
'run2'] ??
''));
224 if ($run1 ===
'' || $run2 ===
'') {
225 $params = trim((
string)($item[
'default_params'] ??
''));
226 if ($params !==
'') {
227 if ($run1 ===
'' && preg_match(
'/(?:^|&)dbx_run1=([^&]+)/', $params, $m)) {
228 $run1 = rawurldecode($m[1]);
230 if ($run2 ===
'' && preg_match(
'/(?:^|&)dbx_run2=([^&]+)/', $params, $m)) {
231 $run2 = rawurldecode($m[1]);
237 $run1 = trim((
string)($record[
'default_run1'] ??
''));
240 $run2 = trim((
string)($record[
'default_run2'] ??
''));
243 return array($run1, $run2);
246 private function buildModuleImagesGalleryHtml(array $record): string {
247 $items = $record[
'image_items'] ?? array();
248 $xmodul = (string)($record[
'xmodul'] ??
'');
250 return '<div class="dbx-module-images-empty-list text-muted small">' .
dbx()->esc($this->get_fd_message(
'no_module_images')) .
'</div>';
254 foreach (
$items as $i => $item) {
255 if (!is_array($item)) {
258 $file =
dbx()->esc((
string)($item[
'file'] ??
''));
259 $url =
dbx()->esc((
string)($item[
'url'] ??
''));
260 $label =
dbx()->esc((
string)($item[
'label'] ??
$file));
261 $params = trim((
string)($item[
'default_params'] ??
''));
262 $call =
'dbx_modul=' . rawurlencode($xmodul);
263 if ($params !==
'') {
264 $call .=
'&' . $params;
267 list($run1, $run2) = $this->resolveImagePreviewRuns($item, $record);
268 $run1Esc =
dbx()->esc($run1);
269 $run2Esc =
dbx()->esc($run2);
270 $previewUrl =
dbx()->esc($this->registry->modulUrl($xmodul, $run1, $run2));
271 $previewTitle =
dbx()->esc($this->format_fd_message(
'module_preview', array(
'module' => $xmodul)));
272 $active = ($i === 0) ?
' is-active' :
'';
274 if ($run1 !==
'' || $params !==
'') {
275 $previewBtn =
'<a class="btn btn-outline-secondary btn-sm dbx-win dbx-module-images-preview" href="' . $previewUrl .
'" data-url="' . $previewUrl .
'" data-title="' . $previewTitle .
'" data-width="88%" data-height="88%" title="' .
dbx()->esc($this->get_fd_message(
'open_module')) .
'"><i class="bi bi-box-arrow-up-right"></i></a>';
277 $html .=
'<div class="dbx-module-images-item' . $active .
'" data-file="' .
$file .
'" data-params="' .
dbx()->esc($params) .
'" data-url="' .
$url .
'" data-run1="' . $run1Esc .
'" data-run2="' . $run2Esc .
'">'
278 .
'<span class="dbx-module-images-thumb">'
279 .
'<img src="' .
$url .
'" alt="' . $label .
'" loading="lazy">'
281 .
'<span class="dbx-module-images-meta">'
282 .
'<code class="dbx-module-images-call">' .
$call .
'</code>'
283 .
'<span class="dbx-module-images-file">' .
$file .
'</span>'
285 .
'<span class="dbx-module-images-actions">'
287 .
'<button type="button" class="btn btn-outline-danger btn-sm dbx-module-images-remove" title="' .
dbx()->esc($this->get_fd_message(
'remove_image')) .
'"><i class="bi bi-trash"></i></button>'
292 return $html !==
'' ?
$html :
'<div class="dbx-module-images-empty-list text-muted small">' .
dbx()->esc($this->get_fd_message(
'no_module_images')) .
'</div>';
296 return $this->buildModuleImagesPreviewHtml($record);
299 private function renderGraphic(array $record): string {
300 $previewUrl =
dbx()->
esc((string)($record[
'preview_url'] ??
''));
301 $title =
dbx()->esc((
string)($record[
'title'] ??
''));
302 $winAttrs =
' class="dbx-module-graphic dbx-win" href="' . $previewUrl .
'" data-url="' . $previewUrl
303 .
'" data-title="' .
dbx()->esc($this->format_fd_message(
'module_preview', array(
'module' => (
string)($record[
'title'] ??
''))))
304 .
'" data-width="88%" data-height="88%" title="' .
dbx()->esc($this->get_fd_message(
'open_preview')) .
'"';
306 $items = $record[
'image_items'] ?? array();
313 foreach (
$items as $i => $item) {
314 if (!is_array($item)) {
317 $url =
dbx()->esc((
string)($item[
'url'] ??
''));
318 $label =
dbx()->esc((
string)($item[
'label'] ??
''));
319 $active = ($i === 0) ?
' is-active' :
'';
320 $slides .=
'<img src="' .
$url .
'" alt="' . $label .
'" class="dbx-module-graphic-img' . $active .
'" loading="lazy">';
323 return '<a' . $winAttrs .
'><div class="dbx-module-graphic-stack">' .
$slides .
'</div></a>';
327 $graphicUrl = trim((
string)($record[
'graphic_url'] ??
''));
328 $alt =
dbx()->esc((
string)($record[
'graphic_alt'] ?? $record[
'title'] ??
''));
330 if ($graphicUrl !==
'') {
331 $badge = trim((
string)($record[
'graphic_badge'] ??
''));
334 $badgeHtml =
'<span class="dbx-module-graphic-badge">' .
dbx()->esc($badge) .
'</span>';
337 return '<a' . $winAttrs .
'>'
338 .
'<img src="' .
dbx()->esc($graphicUrl) .
'" alt="' . $alt .
'" class="dbx-module-graphic-img is-active" loading="lazy">'
343 return '<a' . $winAttrs .
'>'
344 .
'<span class="dbx-module-graphic-placeholder" aria-hidden="true">'
345 .
'<i class="bi bi-box-seam dbx-module-graphic-fallback-icon"></i>'
346 .
'<span class="dbx-module-graphic-placeholder-label">' .
dbx()->esc($this->get_fd_message(
'preview_label')) .
'</span>'
351 private function renderInstallButton(array $record): string {
352 if (empty($record[
'install_url'])) {
356 $url =
dbx()->esc((
string)$record[
'install_url']);
357 $title = (string)($record[
'title'] ??
'');
358 $dialogTitle =
dbx()->esc($this->format_fd_message(
'install_title', array(
'module' => $title)));
360 return '<a class="btn btn-outline-secondary dbx-win" href="' .
$url .
'" data-url="' .
$url .
'" data-title="' . $dialogTitle .
'" data-width="82%" data-height="82%" title="' .
dbx()->esc($this->get_fd_message(
'install_module')) .
'">'
361 .
'<i class="bi bi-database-gear"></i> ' .
dbx()->esc($this->get_fd_message(
'install_module')) .
'</a>';
364 private function renderActiveToggleButton(array $record): string {
365 $modul =
dbx()->
esc((string)($record[
'xmodul'] ??
''));
366 $url =
dbx()->esc((
string)($record[
'active_toggle_url'] ??
''));
367 if ($modul ===
'' ||
$url ===
'') {
370 $active = (string)($record[
'active'] ??
'1') ===
'1';
371 $btnClass = $active ?
'btn-success' :
'btn-outline-secondary';
372 $icon = $active ?
'bi-toggle-on' :
'bi-toggle-off';
373 $label = $this->get_fd_message($active ?
'active' :
'inactive');
374 $state = $active ?
'1' :
'0';
376 return '<button type="button" class="btn ' . $btnClass .
' dbx-module-active-toggle" data-modul="' . $modul
377 .
'" data-active="' .
$state .
'" data-toggle-url="' .
$url .
'" title="' .
dbx()->esc($this->get_fd_message(
'toggle_module')) .
'">'
378 .
'<i class="bi ' . $icon .
'"></i> ' .
dbx()->esc($label) .
'</button>';
381 private function renderDeleteButton(array $record): string {
382 if ((string)($record[
'can_delete'] ??
'0') !==
'1') {
385 $modul =
dbx()->esc((
string)($record[
'xmodul'] ??
''));
386 $title =
dbx()->esc((
string)($record[
'title'] ??
''));
387 $url =
dbx()->esc((
string)($record[
'delete_url'] ??
''));
388 if ($modul ===
'' ||
$url ===
'') {
392 return '<button type="button" class="btn btn-outline-danger dbx-module-delete-btn" data-modul="' . $modul
393 .
'" data-delete-url="' .
$url .
'" data-title="' . $title .
'" title="' .
dbx()->esc($this->get_fd_message(
'delete_module')) .
'">'
394 .
'<i class="bi bi-trash"></i> ' .
dbx()->esc($this->get_fd_message(
'delete_button')) .
'</button>';
397 private function renderAccessInline(array $record): string {
398 $tpl =
dbx()->get_system_obj(
'dbxTPL');
399 $groups = $record[
'groups'] ?? array();
403 $selected = array_flip(
$groups);
405 foreach ($this->registry->groupOptions() as
$value => $label) {
406 $sel = isset($selected[
$value]) ?
' selected' :
'';
407 $options .=
'<option value="' .
dbx()->esc(
$value) .
'"' . $sel .
'>' .
dbx()->esc($this->localizedGroupLabel((
string)
$value, (
string)$label)) .
'</option>';
411 'xmodul' =>
dbx()->
esc((
string)($record[
'xmodul'] ??
'')),
412 'access_save_url' =>
dbx()->
esc((
string)($record[
'access_save_url'] ??
'')),
416 return $tpl->get_tpl(
'dbxAdmin|module-card-access-inline', $data);
419 private function renderGroups(array $record): string {
420 $groups = $record[
'groups'] ?? array();
425 $labels = $this->registry->groupOptions();
428 $group = trim((
string)$group);
432 $label = $this->localizedGroupLabel($group, (
string)($labels[$group] ?? $group));
433 $html .=
'<span class="badge rounded-pill text-bg-light border">' .
dbx()->esc($label) .
'</span>';
437 $html =
'<span class="text-muted small">' .
dbx()->esc($this->get_fd_message(
'no_group')) .
'</span>';
443 private function renderDdList(array $record): string {
444 $tpl =
dbx()->get_system_obj(
'dbxTPL');
445 $items = $record[
'dd_items'] ?? array();
447 return $tpl->get_tpl(
'dbxAdmin|module-card-dd-empty', $record);
451 $selectId = (string)($record[
'dd_select_id'] ??
'');
452 foreach (
$items as $i => $item) {
453 if (!is_array($item)) {
456 $url =
dbx()->esc((
string)($item[
'edit_url'] ??
''));
457 $title =
dbx()->esc($this->format_fd_message(
'edit_dd_title', array(
458 'module' => (
string)($record[
'xmodul'] ??
''),
459 'dd' => (
string)($item[
'label'] ??
''),
461 $label =
dbx()->esc((
string)($item[
'label'] ??
''));
462 $active = ($i === 0) ?
' is-active' :
'';
463 $stripe = ($i % 2 === 0) ?
' odd' :
' even';
464 $gallery .=
'<button type="button" class="dbx-module-dd-item' . $active . $stripe .
'" role="option"'
465 .
' data-edit-url="' .
$url .
'" data-edit-title="' . $title .
'"'
466 .
' aria-selected="' . ($i === 0 ?
'true' :
'false') .
'" title="' . $title .
'">'
467 .
'<span class="dbx-module-dd-item-name">' . $label .
'</span>'
471 $record[
'dd_gallery_html'] = $gallery;
472 return $tpl->get_tpl(
'dbxAdmin|module-card-dd', $record);
475 private function localizedGroupLabel(
string $value,
string $fallback): string {
476 $messageKeys = array(
477 'admin' =>
'group_admin',
478 'guest' =>
'group_guest',
479 'member' =>
'group_member',