Passed
Push — master ( 7308b3...27e0ff )
by Nicolaas
02:27
created

DashboardWelcomeQuicklinks::createInnerLink()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 12
c 0
b 0
f 0
nc 4
nop 4
dl 0
loc 17
rs 9.8666
1
<?php
2
3
namespace Sunnysideup\DashboardWelcomeQuicklinks\Admin;
4
5
use SilverStripe\Admin\LeftAndMain;
0 ignored issues
show
Bug introduced by
The type SilverStripe\Admin\LeftAndMain was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use SilverStripe\Core\ClassInfo;
7
use SilverStripe\Core\Config\Config;
8
use SilverStripe\Core\Injector\Injector;
9
use SilverStripe\Forms\LiteralField;
10
use SilverStripe\ORM\ArrayList;
11
use SilverStripe\ORM\DataObject;
12
use SilverStripe\SiteConfig\SiteConfig;
0 ignored issues
show
Bug introduced by
The type SilverStripe\SiteConfig\SiteConfig was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
use SilverStripe\View\ArrayData;
14
use Sunnysideup\DashboardWelcomeQuicklinks\Api\DefaultDashboardProvider;
15
use Sunnysideup\DashboardWelcomeQuicklinks\Interfaces\DashboardWelcomeQuickLinksProvider;
16
17
class DashboardWelcomeQuicklinks extends LeftAndMain
18
{
19
    protected static int $item_counter = 0;
20
21
    protected static int $group_counter = 0;
22
23
    protected static array $links = [];
24
25
    public static function add_group(string $groupCode, string $title, ?int $sort = 0)
26
    {
27
        self::$group_counter++;
28
29
        self::$links[$groupCode] = [
30
            'Title' => $title,
31
            'SortOrder' => $sort ?: self::$group_counter,
32
        ];
33
    }
34
35
    public static function add_link(string $groupCode, string $title, string $link, ?array $insideLink = [])
36
    {
37
        self::$item_counter++;
38
        if (array_key_exists(0, $insideLink) && array_key_exists(1, $insideLink)) {
39
            $keys = ['Title', 'Link'];
40
            $insideLink = array_combine($keys, $insideLink);
41
        }
42
        self::$links[$groupCode]['Items'][] = [
43
            'Title' => $title,
44
            'Link' => $link,
45
            'InsideLink' => $insideLink,
46
        ];
47
    }
48
49
    public static function get_links()
50
    {
51
        return self::$links;
52
    }
53
54
    public static function get_base_phrase(string $phrase): string
55
    {
56
        if (! in_array($phrase, ['add', 'review', 'edit', 'more'])) {
57
            user_error('Phrase must be one of "add", "review", or "edit"', E_USER_ERROR);
58
        }
59
        $phrase = Config::inst()->get(static::class, $phrase . '_phrase');
60
        return _t('DashboardWelcomeQuicklinks.' . $phrase, $phrase);
61
    }
62
63
    private static string $add_phrase = '+';
0 ignored issues
show
introduced by
The private property $add_phrase is not used, and could be removed.
Loading history...
64
65
    private static string $review_phrase = '☑';
0 ignored issues
show
introduced by
The private property $review_phrase is not used, and could be removed.
Loading history...
66
67
    private static string $edit_phrase = '✎';
0 ignored issues
show
introduced by
The private property $edit_phrase is not used, and could be removed.
Loading history...
68
69
    private static string $url_segment = 'go';
0 ignored issues
show
introduced by
The private property $url_segment is not used, and could be removed.
Loading history...
70
71
    private static $more_phrase = '... More';
0 ignored issues
show
introduced by
The private property $more_phrase is not used, and could be removed.
Loading history...
72
73
    private static bool $use_default_dashboard_provider = true;
0 ignored issues
show
introduced by
The private property $use_default_dashboard_provider is not used, and could be removed.
Loading history...
74
75
    private static $menu_title = 'Quick-links';
0 ignored issues
show
introduced by
The private property $menu_title is not used, and could be removed.
Loading history...
76
77
    private static $menu_icon_class = 'font-icon-dashboard';
0 ignored issues
show
introduced by
The private property $menu_icon_class is not used, and could be removed.
Loading history...
78
79
    private static $menu_priority = 99999;
0 ignored issues
show
introduced by
The private property $menu_priority is not used, and could be removed.
Loading history...
80
81
    private static $colour_options = [];
0 ignored issues
show
introduced by
The private property $colour_options is not used, and could be removed.
Loading history...
82
83
    private static $max_shortcuts_per_group = 7;
0 ignored issues
show
introduced by
The private property $max_shortcuts_per_group is not used, and could be removed.
Loading history...
84
85
    private static $default_colour_options = [
0 ignored issues
show
introduced by
The private property $default_colour_options is not used, and could be removed.
Loading history...
86
        '#0D47A1',
87
        '#01579B',
88
        '#006064',
89
        '#004D40',
90
        '#1B5E20',
91
        '#33691E',
92
        '#827717',
93
        '#F57F17',
94
        '#FF6F00',
95
        '#E65100',
96
        '#BF360C',
97
        '#3E2723',
98
        '#212121',
99
        '#B71C1C',
100
        '#880E4F',
101
        '#4A148C',
102
        '#311B92',
103
        '#1A237E',
104
    ];
105
106
    /**
107
     * easy to distinguish colours
108
     *
109
     * @var array
110
     */
111
    private static $default_colour_options1 = [
0 ignored issues
show
introduced by
The private property $default_colour_options1 is not used, and could be removed.
Loading history...
112
        '#F2F3F4',
113
        '#222222',
114
        '#F3C300',
115
        '#875692',
116
        '#F38400',
117
        '#A1CAF1',
118
        '#BE0032',
119
        '#C2B280',
120
        '#848482',
121
        '#008856',
122
        '#E68FAC',
123
        '#0067A5',
124
        '#F99379',
125
        '#604E97',
126
        '#F6A600',
127
        '#B3446C',
128
        '#DCD300',
129
        '#882D17',
130
        '#8DB600',
131
        '#654522',
132
        '#E25822',
133
        '#2B3D26',
134
    ];
135
136
    /**
137
     * light colours
138
     *
139
     * @var array
140
     */
141
    private static $default_colour_options3 = [
0 ignored issues
show
introduced by
The private property $default_colour_options3 is not used, and could be removed.
Loading history...
142
        '#FFEBEE',
143
        '#FCE4EC',
144
        '#F3E5F5',
145
        '#EDE7F6',
146
        '#E8EAF6',
147
        '#E3F2FD',
148
        '#E1F5FE',
149
        '#E0F7FA',
150
        '#E0F2F1',
151
        '#E8F5E9',
152
        '#F1F8E9',
153
        '#F9FBE7',
154
        '#FFFDE7',
155
        '#FFF8E1',
156
        '#FFF3E0',
157
        '#FBE9E7',
158
        '#EFEBE9',
159
        '#FAFAFA',
160
    ];
161
162
    public function getEditForm($id = null, $fields = null)
163
    {
164
        $form = parent::getEditForm($id, $fields);
165
166
        // if ($form instanceof HTTPResponse) {
167
        //     return $form;
168
        // }
169
        // $form->Fields()->removeByName('LastVisited');
170
171
        $this->updateFormWithQuicklinks($form);
172
173
        return $form;
174
    }
175
176
    public function updateFormWithQuicklinks($form)
177
    {
178
        $shortcuts = $this->getLinksFromImplementor();
179
        // print_r($shortcuts);
180
        $html = '';
181
        $max = $this->Config()->get('max_shortcuts_per_group');
182
        if (count($shortcuts) > 0) {
183
            $html = '<div class="grid-wrapper">';
184
185
            usort(
186
                $shortcuts,
187
                function ($a, $b) {
188
                    $b['SortOrder'] ?? 0;
189
                    $a['SortOrder'] ?? 0;
190
                }
191
            );
192
193
            foreach ($shortcuts as $groupCode => $groupDetails) {
194
                $colour = '';
195
                if (! empty($groupDetails['Colour'])) {
196
                    $colour = 'style="background-color: ' . $groupDetails['Colour'] . '"';
197
                }
198
                $icon = '';
199
                if (! empty($groupDetails['IconClass'])) {
200
                    $icon = '<i class="' . $groupDetails['IconClass'] . '"></i> ';
201
                }
202
                $html .= '
203
                <div class="grid-cell" ' . $colour . '>
204
                    <div class="header">
205
                    <h1>' . $icon . '' . ($groupDetails['Title'] ?? $groupCode) . '</h1>
206
                    </div>
207
                    <div class="entries">';
208
                $items = $groupDetails['Items'] ?? [];
209
                if (! empty($entry['Link']) && class_exists($entry['Link'])) {
210
                    $obj = Injector::inst()->get($entry['Link']);
211
                    if ($obj instanceof DataObject) {
212
                        $entry['Link'] = DataObject::get_one($entry['Link'])->CMSEditLink();
213
                    } else {
214
                        $entry['Link'] = $obj->Link();
215
                    }
216
                }
217
                foreach ($items as $pos => $entry) {
218
                    $html .= $this->createInnerLink($entry, $pos, $items, $max);
219
                }
220
                $html .= '</div></div>';
221
            }
222
        }
223
        $kc = (array) $this->Config()->get('colour_options');
224
        if ($kc === []) {
225
            $kc = $this->Config()->get('default_colour_options');
226
        }
227
        $kcCount = count($kc);
228
        $colours = '';
229
        foreach ($kc as $key => $colour) {
230
            $colours .= ' .grid-wrapper .grid-cell:nth-child(' . $kcCount . 'n+' . ($key + 1) . ') div.header {background-color: ' . $colour . '; color: ' . $this->getFontColor($colour) . '!important;}';
231
        }
232
        $html .= '</div>';
233
        $html .= '<script>window.setTimeout(dashboardWelcomeQuickLinksSetupInputAndFilter, 500)</script>';
234
        $html .= '<style>' . $colours . '</style>';
235
        $form->Fields()->push(LiteralField::create('ShortCuts', $html));
236
    }
237
238
    protected function createInnerLink($entry, $pos, $items, $max)
239
    {
240
        $html = '';
241
        $entry['Class'] = $entry['Class'] ?? '';
242
        $entry['Class'] .= ($pos > $max) ? ' more-item' : '';
243
        $html .= $this->makeShortCut($entry)->Field();
244
        if ($pos > $max && count($items) == $pos + 1) {
245
            $html .= $this->makeShortCut(
246
                [
247
                    'Title' => DashboardWelcomeQuicklinks::get_base_phrase('more'),
248
                    'Link' => '#',
249
                    'OnClick' => 'dashboardWelcomeQuickLinksSetupInputAndFilterToggleMore(event); return false;',
250
                    'Class' => 'more-item-more',
251
                ]
252
            )->Field();
253
        }
254
        return $html;
255
    }
256
257
    protected function getLinksFromImplementor()
258
    {
259
        $array = [];
260
        $useDefaultDashboard = (bool) $this->config()->get('use_default_dashboard_provider');
261
        $classNames = ClassInfo::implementorsOf(DashboardWelcomeQuickLinksProvider::class);
262
        foreach ($classNames as $className) {
263
            if ($useDefaultDashboard === false && (string) $className === DefaultDashboardProvider::class) {
264
                continue;
265
            }
266
            $array += Injector::inst()->get($className)->provideDashboardWelcomeQuickLinks();
267
        }
268
        return $array;
269
    }
270
271
    protected function makeShortCut(array $entry, ?bool $isInsideLink = false): LiteralField|string
272
    {
273
        $title = (string) $entry['Title'];
274
        $link = (string) $entry['Link'];
275
        $onclick = (string) ($entry['OnClick'] ?? '');
276
        $script = (string) ($entry['Script'] ?? '');
277
        $class = (string) ($entry['Class'] ?? '');
278
        $iconClass = (string) ($entry['IconClass'] ?? '');
279
        $target = (string) ($entry['Target'] ?? '');
280
        $insideLink = (array) ($entry['InsideLink'] ?? []);
281
282
        $name = preg_replace('#[\W_]+#u', '', $title);
283
        $html = '';
284
        if ($onclick) {
285
            $onclick = ' onclick="' . $onclick . '"';
286
        }
287
        if ($script) {
288
            $script = '<script>' . $script . '</script>';
289
        }
290
        $icon = '';
291
        if ($iconClass !== null && $iconClass !== '' && $iconClass !== '0') {
292
            $icon = '<i class="' . $iconClass . '"></i> ';
293
        }
294
        if (! $target) {
295
            $target = '_self';
296
        }
297
        if($isInsideLink) {
298
            $tag = 'span';
299
        } else {
300
            $tag = 'h2';
301
        }
302
        if($class) {
303
            $class = ' class="'.$class.'"';
304
        }
305
        $insideLinkHTML = '';
306
        if(!empty($insideLink)) {
307
            $insideLink['Class'] = ($insideLink['Class'] ?? '').' inside-link';
308
            $insideLinkHTML = $this->makeShortCut($insideLink, true);
309
        }
310
        $target = ' target="' . $target . '"';
311
        if ($link !== '' && $link !== '0') {
312
            $html = '' . $script . '<'.$tag.'' . $class . '>' . $icon . '<a href="' . $link . '" ' . $target . ' ' . $onclick . '>' . $title . '</a>'.$insideLinkHTML .'</'.$tag.'>';
313
        } else {
314
            $html = '' . $script . '<'.$tag.'' . $class . '>' . $title . '' . $insideLinkHTML . '</'.$tag.'>
315
            ';
316
        }
317
        $html = preg_replace('/\s+/', ' ', $html);
318
        if($isInsideLink) {
319
            return $html;
320
        } else {
321
            return LiteralField::create($name, $html);
322
        }
323
    }
324
325
    /**
326
     * @return string
327
     */
328
    public function Title()
329
    {
330
        $app = $this->getApplicationName();
331
        $siteConfigTitle = SiteConfig::current_site_config()->Title;
332
        if ($siteConfigTitle) {
333
            $app = $siteConfigTitle . ' (' . $app . ')';
334
        }
335
        return ($section = $this->SectionTitle()) ? sprintf('%s for %s', $section, $app) : $app;
336
    }
337
338
    /**
339
     * @param bool $unlinked
340
     * @return ArrayList<ArrayData>
341
     */
342
    public function Breadcrumbs($unlinked = false)
343
    {
344
        return new ArrayList([
345
            new ArrayData([
346
                'Title' => $this->Title(),
347
                'Link' => ($unlinked) ? false : $this->Link(),
348
            ]),
349
        ]);
350
    }
351
352
    protected function getFontColor(string $backgroundColor): string
353
    {
354
        // Convert hex color to RGB
355
        $r = hexdec(substr($backgroundColor, 1, 2));
356
        $g = hexdec(substr($backgroundColor, 3, 2));
357
        $b = hexdec(substr($backgroundColor, 5, 2));
358
359
        // Calculate luminance
360
        $luminance = (0.299 * $r + 0.587 * $g + 0.114 * $b) / 255;
361
362
        // If luminance is greater than 0.5, use black font; otherwise, use white
363
        return $luminance > 0.5 ? '#222' : '#fff';
364
    }
365
}
366