Passed
Push — master ( 3839e1...ef57d8 )
by Nicolaas
02:15
created

updateFormWithQuicklinks()   C

Complexity

Conditions 11
Paths 8

Size

Total Lines 154
Code Lines 84

Duplication

Lines 0
Ratio 0 %

Importance

Changes 12
Bugs 0 Features 0
Metric Value
cc 11
eloc 84
c 12
b 0
f 0
nc 8
nop 1
dl 0
loc 154
rs 6.2024

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Injector\Injector;
8
use SilverStripe\Forms\LiteralField;
9
use SilverStripe\ORM\ArrayList;
10
use SilverStripe\ORM\DataObject;
11
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...
12
use SilverStripe\View\ArrayData;
13
use Sunnysideup\DashboardWelcomeQuicklinks\Api\DefaultDashboardProvider;
14
use Sunnysideup\DashboardWelcomeQuicklinks\Interfaces\DashboardWelcomeQuickLinksProvider;
15
16
/**
17
 * Class \Sunnysideup\DashboardWelcomeQuicklinks\Admin\DashboardWelcomeQuicklinks
18
 *
19
 */
20
class DashboardWelcomeQuicklinks extends LeftAndMain
21
{
22
    private static $url_segment = 'go';
0 ignored issues
show
introduced by
The private property $url_segment is not used, and could be removed.
Loading history...
23
24
    private static $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...
25
26
    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...
27
28
    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...
29
30
    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...
31
32
    private static $colour_options = [];
0 ignored issues
show
introduced by
The private property $colour_options is not used, and could be removed.
Loading history...
33
34
    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...
35
        '#F2F3F4',
36
        '#222222',
37
        '#F3C300',
38
        '#875692',
39
        '#F38400',
40
        '#A1CAF1',
41
        '#BE0032',
42
        '#C2B280',
43
        '#848482',
44
        '#008856',
45
        '#E68FAC',
46
        '#0067A5',
47
        '#F99379',
48
        '#604E97',
49
        '#F6A600',
50
        '#B3446C',
51
        '#DCD300',
52
        '#882D17',
53
        '#8DB600',
54
        '#654522',
55
        '#E25822',
56
        '#2B3D26',
57
    ];
58
59
    public function getEditForm($id = null, $fields = null)
60
    {
61
        $form = parent::getEditForm($id, $fields);
62
63
        // if ($form instanceof HTTPResponse) {
64
        //     return $form;
65
        // }
66
        // $form->Fields()->removeByName('LastVisited');
67
68
        $this->updateFormWithQuicklinks($form);
69
70
        return $form;
71
    }
72
73
    public function updateFormWithQuicklinks($form)
74
    {
75
        $shortcuts = $this->getLinksFromImplementor();
76
        $html = '';
77
        if (count($shortcuts)) {
78
            $html = '<div class="grid-wrapper">';
79
80
            usort(
81
                $shortcuts,
82
                function ($a, $b) {
83
                    ($a['SortOrder'] ?? 0) <=> ($b['SortOrder'] ?? 0);
84
                }
85
            );
86
87
            foreach ($shortcuts as $groupCode => $groupDetails) {
88
                $colour = '';
89
                if (!empty($groupDetails['Colour'])) {
90
                    $colour = 'style="background-color: ' . $groupDetails['Colour'] . '"';
91
                }
92
                $icon = '';
93
                if (!empty($groupDetails['IconClass'])) {
94
                    $icon = '<i class="' . $groupDetails['IconClass'] . '"></i> ';
95
                }
96
                $html .= '
97
                <div class="grid-cell" ' . $colour . '>
98
                    <div class="header">
99
                    <h1>' . $icon . '' . ($groupDetails['Title'] ?? $groupCode) . '</h1>
100
                    </div>
101
                    <div class="entries">';
102
                $items = $groupDetails['Items'] ?? [];
103
                if (!empty($entry['Link']) && class_exists($entry['Link'])) {
104
                    $obj = Injector::inst()->get($entry['Link']);
105
                    if ($obj instanceof DataObject) {
106
                        $entry['Link'] = DataObject::get_one($entry['Link'])->CMSEditLink();
107
                    } else {
108
                        $entry['Link'] = $obj->Link();
109
                    }
110
                }
111
                foreach ($items as $entry) {
112
                    $html .= $this->makeShortCut(
113
                        $entry['Title'],
114
                        $entry['Link'],
115
                        $entry['OnClick'] ?? '',
116
                        $entry['Script'] ?? '',
117
                        $entry['Style'] ?? '',
118
                        $entry['IconClass'] ?? '',
119
                        $entry['Target'] ?? '',
120
                    )->Field();
121
                }
122
                $html .= '</div></div>';
123
            }
124
        }
125
        $kc = (array) $this->Config()->get('colour_options');
126
        if(empty($kc)) {
127
            $kc = $this->Config()->get('default_colour_options');
128
        }
129
        $kcCount = count($kc);
130
        $colours = '';
131
        foreach ($kc as $key => $colour) {
132
            $colours .= ' .grid-wrapper .grid-cell:nth-child(' . $kcCount . 'n+' . ($key + 1) . ') div.header {background-color: ' . $colour . '; color: '.$this->getFontColor($colour).'!important;}';
133
        }
134
        $html .= '</div>';
135
        $html .= <<<JS
136
        <script>
137
            // Function to add the input box and set up the filtering behavior
138
            function setupInputAndFilter() {
139
                // Locate the target span element
140
                const targetSpan = document.querySelector('.cms-content-header-info');
141
142
                // Create the input box
143
                const inputBox = document.createElement('input');
144
                inputBox.type = 'text';
145
                inputBox.placeholder = 'Type to filter...';
146
147
                // Append the input box to the target span
148
                targetSpan.appendChild(inputBox);
149
150
                // Function to filter grid cells based on input
151
                function filterGridCells() {
152
                    const inputValue = inputBox.value.toLowerCase();
153
                    const gridCells = document.querySelectorAll('div.grid-cell');
154
155
                    gridCells.forEach(cell => {
156
                        // Check if the text in the cell includes the input value
157
                        if (inputValue === '' || cell.textContent.toLowerCase().includes(inputValue)) {
158
                            cell.style.display = ''; // Show the cell
159
                        } else {
160
                            cell.style.display = 'none'; // Hide the cell
161
                        }
162
                    });
163
                }
164
165
                // Add event listener to the input box to filter as the user types
166
                inputBox.addEventListener('input', filterGridCells);
167
            }
168
            window.setTimeout(setupInputAndFilter, 500);
169
        </script>
170
171
JS;
172
173
        $html .= '<style>
174
175
        .grid-wrapper {
176
          display: grid;
177
          grid-template-columns: repeat( auto-fit, minmax(300px, 1fr) );;
178
          grid-gap: 20px;
179
        }
180
181
        .grid-wrapper .grid-cell {
182
          max-width: 500px;
183
          font-size: 150%;
184
          border-radius: 1rem;
185
          border: 1px solid #004e7f55;
186
          display: flex;
187
          flex-direction: column;
188
          overflow: hidden;
189
          box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
190
          transition: all 0.3s ease;
191
          opacity: 0.8;
192
          &:hover {
193
              transform: scale(1.05);
194
              box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
195
              opacity: 1;
196
          }
197
        }
198
        .grid-wrapper .grid-cell > div {
199
            padding: 20px;
200
            padding-bottom: 0;
201
        }
202
        .grid-wrapper .grid-cell > div.header {
203
            padding-bottom: 0;
204
            border-bottom: 1px solid #004e7f55;
205
        }
206
        .grid-wrapper .grid-cell > div.header h1 {
207
            font-weight: 700;
208
            font-size: 1.3rem!important;
209
        }
210
        .grid-wrapper .grid-cell > div.entries {
211
            background-color: #fff;
212
            height: 100%;
213
        }
214
        ' . $colours . '
215
        .grid-wrapper .grid-cell div.entries *,
216
        .grid-wrapper .grid-cell div.entries a:link,
217
        .grid-wrapper .grid-cell div.entries a:visited {
218
            color: #222;
219
        }
220
        .grid-wrapper .grid-cell div.entries a:link:hover,
221
        .grid-wrapper .grid-cell div.entries a:visited:hover {
222
            color: #0071c4;
223
            text-decoration: none;
224
        }
225
        </style>';
226
        $form->Fields()->push(LiteralField::create('ShortCuts', $html));
227
    }
228
229
    protected function getLinksFromImplementor()
230
    {
231
        $array = [];
232
        $useDefaultDashboard = $this->config()->get('use_default_dashboard_provider');
233
        $classNames = ClassInfo::implementorsOf(DashboardWelcomeQuickLinksProvider::class);
234
        foreach ($classNames as $className) {
235
            if((bool) $useDefaultDashboard === false && (string) $className === DefaultDashboardProvider::class) {
236
                continue;
237
            }
238
            $array += Injector::inst()->get($className)->provideDashboardWelcomeQuickLinks();
239
        }
240
        return $array;
241
    }
242
243
    protected function makeShortCut(string $title, string $link, ?string $onclick = '', ?string $script = '', ?string $style = '', ?string $iconClass = '', ?string $target = '')
244
    {
245
        $name = preg_replace('#[\W_]+#u', '', (string) $title);
246
        $html = '';
247
        if ($onclick) {
248
            $onclick = ' onclick="' . $onclick . '"';
249
        }
250
        if ($script) {
251
            $script = '<script>' . $script . '</script>';
252
        }
253
        $icon = '';
254
        if (!empty($iconClass)) {
255
            $icon = '<i class="' . $iconClass . '"></i> ';
256
        }
257
        if(!$target) {
258
            $target = '_self';
259
        }
260
        $target = ' target="'.$target.'"';
261
        if ($link) {
262
            $html = '
263
            ' . $script . '
264
            <h2 style="' . $style . '">
265
                ' . $icon . '<a href="' . $link . '" id="' . $name . '" ' . $target . ' ' . $onclick . '>' . $title . '</a>
266
            </h2>';
267
        } else {
268
            $html = '
269
            ' . $script . '
270
            <p>
271
                &raquo; ' . $title . '
272
            </p>
273
            ';
274
        }
275
        if ($style) {
276
            $html .= '<style>' . $style . '</style>';
277
        }
278
279
        return LiteralField::create(
280
            $name,
281
            $html
282
        );
283
    }
284
    /**
285
     * @return string
286
     */
287
    public function Title()
288
    {
289
        $app = $this->getApplicationName();
290
        $siteConfigTitle = SiteConfig::current_site_config()->Title;
291
        if($siteConfigTitle) {
292
            $app = $siteConfigTitle . ' ('.$app.')';
293
        }
294
        return ($section = $this->SectionTitle()) ? sprintf('%s for %s', $section, $app) : $app;
295
    }
296
    /**
297
     * @param bool $unlinked
298
     * @return ArrayList<ArrayData>
299
     */
300
    public function Breadcrumbs($unlinked = false)
301
    {
302
        $items = new ArrayList([
303
            new ArrayData([
304
                'Title' => $this->Title(),
305
                'Link' => ($unlinked) ? false : $this->Link()
306
            ])
307
        ]);
308
309
        return $items;
310
    }
311
    protected function getFontColor(string $backgroundColor): string
312
    {
313
        // Convert hex color to RGB
314
        $r = hexdec(substr($backgroundColor, 1, 2));
315
        $g = hexdec(substr($backgroundColor, 3, 2));
316
        $b = hexdec(substr($backgroundColor, 5, 2));
317
318
        // Calculate luminance
319
        $luminance = (0.299 * $r + 0.587 * $g + 0.114 * $b) / 255;
320
321
        // If luminance is greater than 0.5, use black font; otherwise, use white
322
        return $luminance > 0.5 ? '#222' : '#fff';
323
    }
324
325
}
326