Skip to content

Commit da1e90f

Browse files
authored
Merge pull request #206 from FriendsOfREDAXO/cs_fixer_and_removed_deprecated
Favs extended
2 parents e5338b3 + 6a877ff commit da1e90f

File tree

9 files changed

+407
-13
lines changed

9 files changed

+407
-13
lines changed

.php-cs-fixer.cache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"php":"8.3.25","version":"3.64.0:v3.64.0#58dd9c931c785a79739310aef5178928305ffa67","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"new_with_parentheses":true,"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":true,"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"visibility_required":true,"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true,"array_syntax":{"syntax":"short"},"no_unused_imports":true,"single_quote":true,"trailing_comma_in_multiline":true},"hashes":{"fragments\/QuickNavigation\/Dropdown.php":"7cc52d767a1b8fa704e4d89c9a3e48a7","fragments\/QuickNavigation\/List.php":"e90ddecd29ce153eec1083841a3088e2","fragments\/QuickNavigation\/NoResult.php":"9b879a1abf902a8aa81cb9e6ce5d921a","fragments\/QuickNavigation\/MinibarList.php":"6c40eb3f991f48d730f45b8d222914b1","pages\/config.php":"cae53f73bf533cc8bb59dadf1cbdebe4","pages\/index.php":"daf2b1a819e7a27391553c599d053802","lib\/LinkMap\/QuickNavigationLinkMap.php":"3060d0975067e724f1dd427eadb02d47","lib\/Utility\/BuildNavigationArray.php":"d2a23cc394de4fd4e83bb34da8b3c0bc","lib\/Minibar\/ArticleHistoryElement.php":"fa606bdfb8e44afdcd46695f36b5d327","lib\/QuickNavigationApi.php":"4eabc25eae94790b9095085102dc278a","lib\/ApiFunction\/MenuRender.php":"fa555351a229780f110eba970ed42a59","lib\/ApiFunction\/MediaSearch.php":"04d4e816aa6766f1f2bf889482187287","lib\/Button\/FavoriteButton.php":"c8163f9adb12699453fe458de325515e","lib\/Button\/ButtonRegistry.php":"0ecf7951feeb0b3524fa1b8c92ac6288","lib\/Button\/YformButton.php":"cb3c1d7608735d18b5732b7425f3c14a","lib\/Button\/ArticleHistoryButton.php":"3851f59535b0647f184a5d706da08aba","lib\/Button\/ButtonInterface.php":"943bf3db82d39b6854401e16fe7e36b6","lib\/Button\/ArticleNavigationButton.php":"a81f2e97e73f235cba29ffcad4db1854","lib\/Button\/WatsonButton.php":"ef0d3641591e83b6e7dfec54008e36a8","lib\/Button\/CategoryButton.php":"3854696ad9b32dffad7d25d881fd2b18","lib\/Media\/MediaSorter.php":"4af98d56992a2e58b4d440ff1545af50","lib\/Media\/QuickNavigationMedia.php":"aa21d3042a12fc77d87e15ccb9c66319","lib\/QuickNavigation.php":"9a208b43632faa9d39923ff64c22f056","update.php":"d6e8377314743b0306a045ec165b99ea","boot.php":"85e4410621c51370487316f2c7de01b4"}}
1+
{"php":"8.4.12","version":"3.64.0:v3.64.0#58dd9c931c785a79739310aef5178928305ffa67","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"new_with_parentheses":true,"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":true,"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"visibility_required":true,"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true,"array_syntax":{"syntax":"short"},"no_unused_imports":true,"single_quote":true,"trailing_comma_in_multiline":true},"hashes":{"update.php":"599fd370563dc5811b440c0ae86309d7","fragments\/QuickNavigation\/NoResult.php":"9b879a1abf902a8aa81cb9e6ce5d921a","fragments\/QuickNavigation\/MinibarList.php":"6c40eb3f991f48d730f45b8d222914b1","fragments\/QuickNavigation\/List.php":"e90ddecd29ce153eec1083841a3088e2","fragments\/QuickNavigation\/Dropdown.php":"7cc52d767a1b8fa704e4d89c9a3e48a7","lib\/QuickNavigationApi.php":"4eabc25eae94790b9095085102dc278a","lib\/ApiFunction\/MenuRender.php":"fa555351a229780f110eba970ed42a59","lib\/ApiFunction\/MediaSearch.php":"04d4e816aa6766f1f2bf889482187287","lib\/QuickNavigation.php":"9a208b43632faa9d39923ff64c22f056","lib\/Minibar\/ArticleHistoryElement.php":"fa606bdfb8e44afdcd46695f36b5d327","lib\/Button\/ArticleNavigationButton.php":"a81f2e97e73f235cba29ffcad4db1854","lib\/Button\/YformButton.php":"cb3c1d7608735d18b5732b7425f3c14a","lib\/Button\/ButtonInterface.php":"943bf3db82d39b6854401e16fe7e36b6","lib\/Button\/ButtonRegistry.php":"0ecf7951feeb0b3524fa1b8c92ac6288","lib\/Button\/WatsonButton.php":"ef0d3641591e83b6e7dfec54008e36a8","lib\/Button\/ArticleHistoryButton.php":"3851f59535b0647f184a5d706da08aba","lib\/Button\/FavoriteButton.php":"c8163f9adb12699453fe458de325515e","lib\/Button\/CategoryButton.php":"3854696ad9b32dffad7d25d881fd2b18","lib\/LinkMap\/QuickNavigationLinkMap.php":"3060d0975067e724f1dd427eadb02d47","lib\/Utility\/BuildNavigationArray.php":"d2a23cc394de4fd4e83bb34da8b3c0bc","lib\/Media\/QuickNavigationMedia.php":"aa21d3042a12fc77d87e15ccb9c66319","lib\/Media\/MediaSorter.php":"4af98d56992a2e58b4d440ff1545af50","boot.php":"85e4410621c51370487316f2c7de01b4","pages\/index.php":"daf2b1a819e7a27391553c599d053802","pages\/config.php":"cae53f73bf533cc8bb59dadf1cbdebe4"}}

assets/quick-navigation.css

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,65 @@
152152
{
153153
color: var(--quick-navigation-color-offline);
154154
}
155+
156+
/* Favoriten Sections */
157+
.quick-navigation-section-header {
158+
padding: 10px 12px 6px;
159+
font-weight: 600;
160+
font-size: 11px;
161+
text-transform: uppercase;
162+
color: #666;
163+
background-color: #f5f5f5;
164+
border-top: 1px solid #e0e0e0;
165+
margin: 0;
166+
}
167+
168+
.quick-navigation-section-header:first-child {
169+
border-top: none;
170+
}
171+
172+
.quick-navigation-section-divider {
173+
display: none;
174+
}
175+
176+
.quick-navigation-addon-fav {
177+
padding: 0;
178+
}
179+
180+
.quick-navigation-addon-fav a {
181+
display: flex;
182+
align-items: center;
183+
gap: 8px;
184+
padding: 6px 12px;
185+
color: inherit;
186+
text-decoration: none;
187+
}
188+
189+
.quick-navigation-addon-fav a:hover {
190+
background-color: #f0f0f0;
191+
}
192+
193+
.quick-navigation-addon-fav a i {
194+
width: 16px;
195+
text-align: center;
196+
flex-shrink: 0;
197+
}
198+
199+
/* Dark Theme Support */
200+
.rex-theme-dark .quick-navigation-section-header {
201+
color: #aaa;
202+
background-color: #2a2d33;
203+
border-top-color: #404040;
204+
}
205+
206+
.rex-theme-dark .quick-navigation-addon-fav a:hover {
207+
background-color: #35383e;
208+
}
209+
210+
.rex-theme-dark .quick-navigation-menu-header {
211+
border-bottom-color: #404040;
212+
}
213+
214+
.rex-theme-dark .quick-navigation-no-results {
215+
background-color: rgba(42, 45, 51, 0.59);
216+
}

boot.php

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,44 @@
5151

5252
$userId = rex::getUser()->getId();
5353
if (rex_addon::get('quick_navigation')->getConfig('quick_navigation_artdirections' . $userId) != '1') {
54-
ButtonRegistry::registerButton(new ArticleNavigationButton(), 10);
54+
ButtonRegistry::registerButton(
55+
new ArticleNavigationButton(),
56+
10,
57+
'article_navigation',
58+
rex_addon::get('quick_navigation')->i18n('quick_navigation_button_article_navigation')
59+
);
5560
}
5661

57-
ButtonRegistry::registerButton(new WatsonButton(), 20);
58-
ButtonRegistry::registerButton(new CategoryButton(), 30);
59-
ButtonRegistry::registerButton(new ArticleHistoryButton('structure', 20), 40);
60-
ButtonRegistry::registerButton(new YformButton(), 50);
61-
ButtonRegistry::registerButton(new FavoriteButton(), 60);
62+
ButtonRegistry::registerButton(
63+
new WatsonButton(),
64+
20,
65+
'watson',
66+
rex_addon::get('quick_navigation')->i18n('quick_navigation_button_watson')
67+
);
68+
ButtonRegistry::registerButton(
69+
new CategoryButton(),
70+
30,
71+
'category',
72+
rex_addon::get('quick_navigation')->i18n('quick_navigation_button_category')
73+
);
74+
ButtonRegistry::registerButton(
75+
new ArticleHistoryButton('structure', 20),
76+
40,
77+
'article_history',
78+
rex_addon::get('quick_navigation')->i18n('quick_navigation_button_article_history')
79+
);
80+
ButtonRegistry::registerButton(
81+
new YformButton(),
82+
50,
83+
'yform',
84+
rex_addon::get('quick_navigation')->i18n('quick_navigation_button_yform')
85+
);
86+
ButtonRegistry::registerButton(
87+
new FavoriteButton(),
88+
60,
89+
'favorite',
90+
rex_addon::get('quick_navigation')->i18n('quick_navigation_button_favorite')
91+
);
6292

6393
// Addonrechte (permissions) registieren
6494
rex_perm::register('quick_navigation[]');

fragments/QuickNavigation/List.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@
77

88
<ul>
99
<?php foreach($this->getVar('listItems', []) as $listItem): ?>
10+
<?php if (str_contains($listItem, 'quick-navigation-section-header') || str_contains($listItem, 'quick-navigation-section-divider')): ?>
11+
<?= $listItem ?>
12+
<?php else: ?>
1013
<li>
1114
<div class="quick-navigation-item">
1215
<?= $listItem ?>
1316
</div>
1417
</li>
18+
<?php endif ?>
1519
<?php endforeach ?>
1620
</ul>

lang/de_de.lang

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ quick_navigation_favorite = Favoriten
2121
quick_navigation_manage_favorite = Favoriten anlegen
2222
quick_navigation_favorite_article_add = Artikel hinzufügen in:
2323
quick_navigation_favorite_category_add = Kategorie hinzufügen in:
24+
quick_navigation_addon_pages = AddOn-Seiten
25+
quick_navigation_structure_favs = Struktur
26+
quick_navigation_addon_pages_selection = AddOn-Seiten Favoriten
2427
quick_navigation_yform = YForm
2528
quick_navigation_yform_add = Datensatz hinzufügen in:
2629

@@ -35,3 +38,13 @@ quick_navigation_media_live_search_placeholder = Live-Suche...
3538

3639
# Live Search
3740
quick_navigation_media_live_search_placeholder = Live-Suche...
41+
42+
# Button Management
43+
quick_navigation_button_management = Buttons ausblenden (Opt-Out)
44+
quick_navigation_button_management_note = Wähle die Buttons aus, die du NICHT sehen möchtest. Alle anderen Buttons bleiben sichtbar.
45+
quick_navigation_button_article_navigation = Artikelnavigation (Blättern)
46+
quick_navigation_button_watson = Watson
47+
quick_navigation_button_category = Kategorie
48+
quick_navigation_button_article_history = Artikel-Historie
49+
quick_navigation_button_yform = YForm
50+
quick_navigation_button_favorite = Favoriten

lang/en_gb.lang

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ quick_navigation_favorite = Favorites
2121
quick_navigation_manage_favorite = Add favorites
2222
quick_navigation_favorite_article_add = Add article to:
2323
quick_navigation_favorite_category_add = Add category to:
24+
quick_navigation_addon_pages = AddOn Pages
25+
quick_navigation_structure_favs = Structure
26+
quick_navigation_addon_pages_selection = AddOn Pages Favorites
2427
quick_navigation_yform = YForm
2528
quick_navigation_yform_add = Add dataset to:
2629

@@ -32,3 +35,13 @@ quick_navigation_media_sort_title = Sort by title (A-Z)
3235
# Media Live-Search
3336
quick_navigation_media_livesearch = Enable media live search?
3437
quick_navigation_media_live_search_placeholder = Live search...
38+
39+
# Button Management
40+
quick_navigation_button_management = Hide buttons (Opt-Out)
41+
quick_navigation_button_management_note = Select the buttons you DON'T want to see. All other buttons remain visible.
42+
quick_navigation_button_article_navigation = Article Navigation (Browse)
43+
quick_navigation_button_watson = Watson
44+
quick_navigation_button_category = Category
45+
quick_navigation_button_article_history = Article History
46+
quick_navigation_button_yform = YForm
47+
quick_navigation_button_favorite = Favorites

lib/Button/ButtonRegistry.php

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,103 @@
22

33
namespace FriendsOfRedaxo\QuickNavigation\Button;
44

5+
use rex;
6+
use rex_addon;
7+
58
class ButtonRegistry
69
{
710
/**
8-
* @var array<array{instance: mixed, priority: int}> an array that contains button instances and their priorities
11+
* @var array<array{id: string, label: string, instance: mixed, priority: int}> an array that contains button instances and their priorities
912
*/
1013
protected static array $buttons = [];
1114

1215
/**
1316
* Registers a button with an optional priority.
1417
* Lower priority values cause the button to appear earlier in the list.
18+
*
19+
* @param string $id Unique identifier for the button (e.g. 'article_navigation', 'watson')
20+
* @param string $label Human readable label for config (e.g. 'Artikelnavigation', 'Watson')
1521
*/
16-
public static function registerButton(ButtonInterface $buttonInstance, int $priority = 10): void
22+
public static function registerButton(ButtonInterface $buttonInstance, int $priority = 10, string $id = '', string $label = ''): void
1723
{
18-
self::$buttons[] = ['instance' => $buttonInstance, 'priority' => $priority];
24+
// Generate ID from class name if not provided
25+
if ($id === '') {
26+
$className = get_class($buttonInstance);
27+
$id = strtolower(str_replace('Button', '', substr($className, strrpos($className, '\\') + 1)));
28+
}
29+
30+
// Use ID as label if not provided
31+
if ($label === '') {
32+
$label = ucfirst(str_replace('_', ' ', $id));
33+
}
34+
35+
self::$buttons[] = [
36+
'id' => $id,
37+
'label' => $label,
38+
'instance' => $buttonInstance,
39+
'priority' => $priority
40+
];
1941
}
2042

2143
/**
22-
* Returns the buttons sorted by their priority.
44+
* Returns the buttons sorted by their priority, filtered by user preferences.
2345
*/
2446
public static function getButtonsOutput(): string
2547
{
48+
$user = rex::getUser();
49+
if (!$user) {
50+
return '';
51+
}
52+
53+
$userId = $user->getId();
54+
$addon = rex_addon::get('quick_navigation');
55+
56+
// Get disabled buttons for this user (Opt-Out)
57+
$disabledButtons = $addon->getConfig('quick_navigation_disabled_buttons' . $userId, []);
58+
if (!is_array($disabledButtons)) {
59+
$disabledButtons = [];
60+
}
61+
2662
// Sorts the buttons based on their priority
2763
usort(self::$buttons, static function (array $a, array $b): int {
2864
return $a['priority'] <=> $b['priority'];
2965
});
3066

3167
$resultString = '';
3268
foreach (self::$buttons as $button) {
69+
// Skip if button is disabled for this user
70+
if (in_array($button['id'], $disabledButtons, true)) {
71+
continue;
72+
}
73+
3374
// Since all instances implement ButtonInterface, it's guaranteed that get() exists.
3475
$resultString .= $button['instance']->get();
3576
}
3677

3778
return $resultString;
3879
}
80+
81+
/**
82+
* Returns all available buttons with their metadata for configuration.
83+
* @return array<array{id: string, label: string, priority: int}>
84+
*/
85+
public static function getAvailableButtons(): array
86+
{
87+
// Sort by priority
88+
$sortedButtons = self::$buttons;
89+
usort($sortedButtons, static function (array $a, array $b): int {
90+
return $a['priority'] <=> $b['priority'];
91+
});
92+
93+
$result = [];
94+
foreach ($sortedButtons as $button) {
95+
$result[] = [
96+
'id' => $button['id'],
97+
'label' => $button['label'],
98+
'priority' => $button['priority']
99+
];
100+
}
101+
102+
return $result;
103+
}
39104
}

0 commit comments

Comments
 (0)