├── .editorconfig
├── .github
└── workflows
│ └── tests.yml
├── .gitignore
├── .styleci.yml
├── LICENSE.md
├── README.md
├── SECURITY.md
├── composer.json
├── phpunit.xml
├── src
├── Config
│ └── menu.php
├── Facade.php
├── Menu.php
├── MenuBuilder.php
├── MenuItem.php
├── Presenters
│ ├── Admin
│ │ ├── Adminlte.php
│ │ ├── Argon.php
│ │ ├── MetronicHorizontal.php
│ │ └── Tailwind.php
│ ├── Bootstrap3
│ │ ├── Nav.php
│ │ ├── NavPills.php
│ │ ├── NavTab.php
│ │ ├── Navbar.php
│ │ ├── NavbarRight.php
│ │ └── Sidebar.php
│ ├── Foundation
│ │ └── Zurb.php
│ ├── Presenter.php
│ └── PresenterInterface.php
├── Provider.php
├── Resources
│ └── views
│ │ └── bootstrap3
│ │ ├── child
│ │ ├── dropdown.blade.php
│ │ └── item.blade.php
│ │ ├── default.blade.php
│ │ ├── item
│ │ ├── dropdown.blade.php
│ │ └── item.blade.php
│ │ ├── menu.blade.php
│ │ ├── nav-pills-justified.blade.php
│ │ ├── nav-pills-stacked.blade.php
│ │ ├── nav-pills.blade.php
│ │ ├── nav-tabs-justified.blade.php
│ │ ├── nav-tabs.blade.php
│ │ ├── navbar-left.blade.php
│ │ ├── navbar-right.blade.php
│ │ └── style.blade.php
└── helpers.php
└── tests
├── MenuBuilderTest.php
├── MenuItemTest.php
├── MenuTest.php
└── TestCase.php
/.editorconfig:
--------------------------------------------------------------------------------
1 | ; This file is for unifying the coding style for different editors and IDEs.
2 | ; More information at https://editorconfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | charset = utf-8
8 | indent_size = 4
9 | indent_style = space
10 | end_of_line = lf
11 | insert_final_newline = true
12 | trim_trailing_whitespace = true
13 |
14 | [*.md]
15 | trim_trailing_whitespace = false
16 |
17 | [*.yml]
18 | indent_size = 2
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | tests:
7 | name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.stability }}
8 |
9 | runs-on: ubuntu-latest
10 |
11 | strategy:
12 | matrix:
13 | php: ['8.0', '8.1', '8.2']
14 | laravel: [9.*, 10.*]
15 | stability: [prefer-lowest, prefer-stable]
16 | include:
17 | - laravel: 9.*
18 | testbench: 7.*
19 | - laravel: 10.*
20 | testbench: 8.*
21 | exclude:
22 | - laravel: 10.*
23 | php: 8.0
24 |
25 | steps:
26 | - name: Checkout code
27 | uses: actions/checkout@v2
28 |
29 | - name: Setup PHP
30 | uses: shivammathur/setup-php@v2
31 | with:
32 | php-version: ${{ matrix.php }}
33 | extensions: bcmath, ctype, dom, fileinfo, intl, gd, json, mbstring, pdo, pdo_sqlite, openssl, sqlite, xml, zip
34 | coverage: none
35 |
36 | - name: Install dependencies
37 | run: |
38 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
39 | composer update --${{ matrix.stability }} --prefer-dist --no-interaction
40 |
41 | - name: Execute tests
42 | run: vendor/bin/phpunit
43 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /.history
3 | /.vscode
4 | /build
5 | /vendor
6 | composer.phar
7 | composer.lock
8 | .DS_Store
9 | .phpunit.result.cache
10 |
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: psr2
2 |
3 | enabled:
4 | - concat_with_spaces
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Pingpong Labs
4 |
5 | Copyright (c) 2016 Nicolas Widart
6 |
7 | Copyright (c) 2019 Akaunting
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in all
17 | copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Menu and sidebar management package for Laravel
2 |
3 | 
4 | 
5 | [](https://styleci.io/repos/180763610)
6 | [](LICENSE.md)
7 |
8 | This package intends to create and manage menus and sidebars for your Laravel app. It ships with ready-to-go presenters and you can create your own ones.
9 |
10 | ## Getting Started
11 |
12 | ### 1. Install
13 |
14 | Run the following command:
15 |
16 | ```bash
17 | composer require akaunting/laravel-menu
18 | ```
19 |
20 | ### 2. Register
21 |
22 | Service provider and facade will be registered automatically. If you want to register them manually in `config/app.php`:
23 |
24 | ```php
25 | Akaunting\Menu\Facade::class,
26 | Akaunting\Menu\Provider::class,
27 | ```
28 |
29 | ### 3. Publish
30 |
31 | Publish config file.
32 |
33 | ```bash
34 | php artisan vendor:publish --tag=menu
35 | ```
36 |
37 | ### 4. Configure
38 |
39 | You can change the configuration from `config/menu.php` file
40 |
41 | ## Usage
42 |
43 | Check out the [wiki](../../wiki) about the usage and further documentation.
44 |
45 | ## Changelog
46 |
47 | Please see [Releases](../../releases) for more information what has changed recently.
48 |
49 | ## Contributing
50 |
51 | Pull requests are more than welcome. You must follow the PSR coding standards.
52 |
53 | ## Security
54 |
55 | Please review [our security policy](https://github.com/akaunting/laravel-menu/security/policy) on how to report security vulnerabilities.
56 |
57 | ## Credits
58 |
59 | - [Denis Duliçi](https://github.com/denisdulici)
60 | - [All Contributors](../../contributors)
61 |
62 | ## License
63 |
64 | The MIT License (MIT). Please see [LICENSE](LICENSE.md) for more information.
65 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | **PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).**
4 |
5 | ## Reporting a Vulnerability
6 |
7 | If you discover any security related issues, please email security@akaunting.com instead of using the issue tracker.
8 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "akaunting/laravel-menu",
3 | "description": "Menu and sidebar management package for Laravel",
4 | "keywords": [
5 | "laravel",
6 | "menu",
7 | "navigation",
8 | "sidebar",
9 | "bootstrap"
10 | ],
11 | "license": "MIT",
12 | "authors": [
13 | {
14 | "name": "Denis Duliçi",
15 | "email": "info@akaunting.com",
16 | "homepage": "https://akaunting.com",
17 | "role": "Developer"
18 | }
19 | ],
20 | "require": {
21 | "php": "^8.0",
22 | "illuminate/config": "^9.0|^10.0",
23 | "illuminate/support": "^9.0|^10.0",
24 | "illuminate/view": "^9.0|^10.0",
25 | "laravelcollective/html": "^6.3"
26 | },
27 | "require-dev": {
28 | "friendsofphp/php-cs-fixer": "^3.12",
29 | "mockery/mockery": "^1.5",
30 | "orchestra/testbench": "^7.4|^8.0",
31 | "phpunit/phpunit": "^9.5"
32 | },
33 | "autoload": {
34 | "psr-4": {
35 | "Akaunting\\Menu\\": "src"
36 | },
37 | "files": [
38 | "src/helpers.php"
39 | ]
40 | },
41 | "autoload-dev": {
42 | "psr-4": {
43 | "Akaunting\\Menu\\Tests\\": "tests"
44 | }
45 | },
46 | "extra": {
47 | "laravel": {
48 | "providers": [
49 | "Akaunting\\Menu\\Provider"
50 | ],
51 | "aliases": {
52 | "Menu": "Akaunting\\Menu\\Facade"
53 | }
54 | }
55 | },
56 | "minimum-stability": "dev",
57 | "prefer-stable": true
58 | }
59 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | tests
15 |
16 |
17 |
18 |
19 | ./src
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/Config/menu.php:
--------------------------------------------------------------------------------
1 | [
6 | // Boostrap 3
7 | 'bs3-navbar' => \Akaunting\Menu\Presenters\Bootstrap3\Navbar::class,
8 | 'bs3-navbar-right' => \Akaunting\Menu\Presenters\Bootstrap3\NavbarRight::class,
9 | 'bs3-nav-pills' => \Akaunting\Menu\Presenters\Bootstrap3\NavPills::class,
10 | 'bs3-nav-tab' => \Akaunting\Menu\Presenters\Bootstrap3\NavTab::class,
11 | 'bs3-sidebar' => \Akaunting\Menu\Presenters\Bootstrap3\Sidebar::class,
12 | 'bs3-navmenu' => \Akaunting\Menu\Presenters\Bootstrap3\Nav::class,
13 |
14 | // Zurb
15 | 'zurb' => \Akaunting\Menu\Presenters\Foundation\Zurb::class,
16 |
17 | // Admin
18 | 'adminlte' => \Akaunting\Menu\Presenters\Admin\Adminlte::class,
19 | 'argon' => \Akaunting\Menu\Presenters\Admin\Argon::class,
20 | 'metronic-horizontal' => \Akaunting\Menu\Presenters\Admin\MetronicHorizontal::class,
21 | 'tailwind' => \Akaunting\Menu\Presenters\Admin\Tailwind::class,
22 | ],
23 |
24 | 'home_urls' => [
25 | '/',
26 | ],
27 |
28 | 'ordering' => false,
29 |
30 | ];
31 |
--------------------------------------------------------------------------------
/src/Facade.php:
--------------------------------------------------------------------------------
1 | views = $views;
22 | $this->config = $config;
23 | }
24 |
25 | /**
26 | * Make new menu.
27 | */
28 | public function make(string $name, Closure $callback): mixed
29 | {
30 | return $this->create($name, $callback);
31 | }
32 |
33 | /**
34 | * Create new menu.
35 | */
36 | public function create(string $name, Closure $resolver): mixed
37 | {
38 | $builder = new MenuBuilder($name, $this->config);
39 |
40 | $builder->setViewFactory($this->views);
41 |
42 | $this->menu[$name] = $builder;
43 |
44 | return $resolver($builder);
45 | }
46 |
47 | /**
48 | * Check if the menu exists.
49 | */
50 | public function has(string $name): bool
51 | {
52 | return array_key_exists($name, $this->menu);
53 | }
54 |
55 | /**
56 | * Get instance of the given menu if exists.
57 | */
58 | public function instance(string $name): ?MenuBuilder
59 | {
60 | return $this->has($name) ? $this->menu[$name] : null;
61 | }
62 |
63 | /**
64 | * Modify a specific menu.
65 | */
66 | public function modify(string $name, Closure $callback): void
67 | {
68 | $menu = collect($this->menu)->filter(function ($menu) use ($name) {
69 | return $menu->getName() == $name;
70 | })->first();
71 |
72 | $callback($menu);
73 | }
74 |
75 | /**
76 | * Render the menu tag by given name.
77 | */
78 | public function get(string $name, ?string $presenter = null, array $bindings = []): ?string
79 | {
80 | return $this->has($name) ?
81 | $this->menu[$name]->setBindings($bindings)->render($presenter) : null;
82 | }
83 |
84 | /**
85 | * Render the menu tag by given name.
86 | */
87 | public function render(string $name, ?string $presenter = null, array $bindings = []): ?string
88 | {
89 | return $this->get($name, $presenter, $bindings);
90 | }
91 |
92 | /**
93 | * Get a stylesheet for enable multilevel menu.
94 | */
95 | public function style(): mixed
96 | {
97 | return $this->views->make('menu::bootstrap3.style')->render();
98 | }
99 |
100 | /**
101 | * Get all menus.
102 | */
103 | public function all(): array
104 | {
105 | return $this->menu;
106 | }
107 |
108 | /**
109 | * Count menus.
110 | */
111 | public function count(): int
112 | {
113 | return count($this->menu);
114 | }
115 |
116 | /**
117 | * Empty the current menus.
118 | */
119 | public function destroy(): void
120 | {
121 | $this->menu = [];
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/MenuBuilder.php:
--------------------------------------------------------------------------------
1 | menu = $menu;
95 | $this->config = $config;
96 | }
97 |
98 | /**
99 | * Get menu name.
100 | *
101 | * @return string
102 | */
103 | public function getName()
104 | {
105 | return $this->menu;
106 | }
107 |
108 | /**
109 | * Find menu item by title.
110 | *
111 | * @param string $title
112 | * @param callable|null $callback
113 | * @return mixed
114 | */
115 | public function whereTitle($title, callable $callback = null)
116 | {
117 | $item = $this->findBy('title', $title);
118 |
119 | if (is_callable($callback)) {
120 | return call_user_func($callback, $item);
121 | }
122 |
123 | return $item;
124 | }
125 |
126 | /**
127 | * Find menu item by key and value.
128 | *
129 | * @param string $key
130 | * @param string $value
131 | * @return \Akaunting\Menu\MenuItem
132 | */
133 | public function findBy($key, $value)
134 | {
135 | return collect($this->items)->filter(function ($item) use ($key, $value) {
136 | return $item->{$key} == $value;
137 | })->first();
138 | }
139 |
140 | /**
141 | * Remove menu item by title.
142 | *
143 | * @param string $title
144 | * @return void
145 | */
146 | public function removeByTitle($title)
147 | {
148 | $this->removeBy('title', $title);
149 | }
150 |
151 | /**
152 | * Remove menu item by key and value.
153 | *
154 | * @param string $key
155 | * @param string $value
156 | * @return void
157 | */
158 | public function removeBy($key, $value)
159 | {
160 | $this->items = collect($this->items)->reject(function ($item) use ($key, $value) {
161 | return $item->{$key} == $value;
162 | })->values()->all();
163 | }
164 |
165 | /**
166 | * Set view factory instance.
167 | *
168 | * @param ViewFactory $views
169 | *
170 | * @return $this
171 | */
172 | public function setViewFactory(ViewFactory $views)
173 | {
174 | $this->views = $views;
175 |
176 | return $this;
177 | }
178 |
179 | /**
180 | * Set view.
181 | *
182 | * @param string $view
183 | *
184 | * @return $this
185 | */
186 | public function setView($view)
187 | {
188 | $this->view = $view;
189 |
190 | return $this;
191 | }
192 |
193 | /**
194 | * Set Prefix URL.
195 | *
196 | * @param string $prefixUrl
197 | *
198 | * @return $this
199 | */
200 | public function setPrefixUrl($prefixUrl)
201 | {
202 | $this->prefixUrl = $prefixUrl;
203 |
204 | return $this;
205 | }
206 |
207 | /**
208 | * Set Prefix URL.
209 | *
210 | * @param string $fragmentUrl
211 | *
212 | * @return $this
213 | */
214 | public function setFragmentUrl($fragmentUrl)
215 | {
216 | $this->fragmentUrl = $fragmentUrl;
217 |
218 | return $this;
219 | }
220 |
221 | /**
222 | * Set styles.
223 | *
224 | * @param array $styles
225 | */
226 | public function setStyles(array $styles)
227 | {
228 | $this->styles = $styles;
229 | }
230 |
231 | /**
232 | * Set new presenter class.
233 | *
234 | * @param string $presenter
235 | */
236 | public function setPresenter($presenter)
237 | {
238 | $this->presenter = $presenter;
239 | }
240 |
241 | /**
242 | * Get presenter instance.
243 | *
244 | * @return \Akaunting\Menu\Presenters\PresenterInterface
245 | */
246 | public function getPresenter()
247 | {
248 | return new $this->presenter();
249 | }
250 |
251 | /**
252 | * Set new presenter class by given style name.
253 | *
254 | * @param string $name
255 | *
256 | * @return self
257 | */
258 | public function style($name)
259 | {
260 | if ($this->hasStyle($name)) {
261 | $this->setPresenter($this->getStyle($name));
262 | }
263 |
264 | return $this;
265 | }
266 |
267 | /**
268 | * Determine if the given name in the presenter style.
269 | *
270 | * @param $name
271 | *
272 | * @return bool
273 | */
274 | public function hasStyle($name)
275 | {
276 | return array_key_exists($name, $this->getStyles());
277 | }
278 |
279 | /**
280 | * Get style aliases.
281 | *
282 | * @return mixed
283 | */
284 | public function getStyles()
285 | {
286 | return $this->styles ?: $this->config->get('menu.styles');
287 | }
288 |
289 | /**
290 | * Get the presenter class name by given alias name.
291 | *
292 | * @param $name
293 | *
294 | * @return mixed
295 | */
296 | public function getStyle($name)
297 | {
298 | $style = $this->getStyles();
299 |
300 | return $style[$name];
301 | }
302 |
303 | /**
304 | * Set new presenter class from given alias name.
305 | *
306 | * @param $name
307 | */
308 | public function setPresenterFromStyle($name)
309 | {
310 | $this->setPresenter($this->getStyle($name));
311 | }
312 |
313 | /**
314 | * Set the resolved item bindings
315 | *
316 | * @param array $bindings
317 | * @return $this
318 | */
319 | public function setBindings(array $bindings)
320 | {
321 | $this->bindings = $bindings;
322 |
323 | return $this;
324 | }
325 |
326 | /**
327 | * Resolves a key from the bindings array.
328 | *
329 | * @param string|array $key
330 | * @return mixed
331 | */
332 | public function resolve($key)
333 | {
334 | if (is_array($key)) {
335 | foreach ($key as $k => $v) {
336 | $key[$k] = $this->resolve($v);
337 | }
338 | } elseif (is_string($key)) {
339 | $matches = [];
340 |
341 | preg_match_all('/{[\s]*?([^\s]+)[\s]*?}/i', $key, $matches, PREG_SET_ORDER);
342 |
343 | foreach ($matches as $match) {
344 | if (array_key_exists($match[1], $this->bindings)) {
345 | $key = preg_replace('/' . $match[0] . '/', $this->bindings[$match[1]], $key, 1);
346 | }
347 | }
348 | }
349 |
350 | return $key;
351 | }
352 |
353 | /**
354 | * Resolves an array of menu items properties.
355 | *
356 | * @param array &$items
357 | * @return void
358 | */
359 | protected function resolveItems(array &$items)
360 | {
361 | $resolver = function ($property) {
362 | return $this->resolve($property) ?: $property;
363 | };
364 |
365 | $totalItems = count($items);
366 | for ($i = 0; $i < $totalItems; $i++) {
367 | $items[$i]->fill(array_map($resolver, $items[$i]->getProperties()));
368 | }
369 | }
370 |
371 | /**
372 | * Add new child menu.
373 | *
374 | * @param array $attributes
375 | *
376 | * @return \Akaunting\Menu\MenuItem
377 | */
378 | public function add(array $attributes = [])
379 | {
380 | $item = MenuItem::make($attributes);
381 |
382 | $this->items[] = $item;
383 |
384 | return $item;
385 | }
386 |
387 | /**
388 | * Create new menu with dropdown.
389 | *
390 | * @param $title
391 | * @param callable $callback
392 | * @param array $attributes
393 | * @param string|null $fragment
394 | *
395 | * @return $this
396 | */
397 | public function dropdown($title, \Closure $callback, $order = null, array $attributes = [], $fragment = null)
398 | {
399 | $fragment = $fragment ?: $this->fragmentUrl;
400 |
401 | $properties = compact('title', 'order', 'attributes', 'fragment');
402 |
403 | if (func_num_args() == 3) {
404 | $arguments = func_get_args();
405 |
406 | $title = Arr::get($arguments, 0);
407 | $attributes = Arr::get($arguments, 2);
408 |
409 | $properties = compact('title', 'attributes');
410 | }
411 |
412 | $item = MenuItem::make($properties);
413 |
414 | call_user_func($callback, $item);
415 |
416 | $this->items[] = $item;
417 |
418 | return $item;
419 | }
420 |
421 | /**
422 | * Register new menu item using registered route.
423 | *
424 | * @param $route
425 | * @param $title
426 | * @param array $parameters
427 | * @param array $attributes
428 | * @param string|null $fragment
429 | *
430 | * @return static
431 | */
432 | public function route($route, $title, $parameters = [], $order = null, $attributes = [], $fragment = null)
433 | {
434 | if (func_num_args() == 4) {
435 | $arguments = func_get_args();
436 |
437 | return $this->add([
438 | 'route' => [Arr::get($arguments, 0), Arr::get($arguments, 2)],
439 | 'title' => Arr::get($arguments, 1),
440 | 'attributes' => Arr::get($arguments, 3),
441 | ]);
442 | }
443 |
444 | $route = [$route, $parameters];
445 |
446 | $fragment = $fragment ?: $this->fragmentUrl;
447 |
448 | $item = MenuItem::make(compact('route', 'title', 'parameters', 'attributes', 'order', 'fragment'));
449 |
450 | $this->items[] = $item;
451 |
452 | return $item;
453 | }
454 |
455 | /**
456 | * Format URL.
457 | *
458 | * @param string $url
459 | *
460 | * @return string
461 | */
462 | protected function formatUrl($url)
463 | {
464 | $url = !is_null($this->prefixUrl) ? $this->prefixUrl . $url : $url;
465 | $url = !is_null($this->fragmentUrl) ? $url . '#' . $this->fragmentUrl : $url;
466 |
467 | return $url == '/' ? '/' : ltrim(rtrim($url, '/'), '/');
468 | }
469 |
470 | /**
471 | * Register new menu item using url.
472 | *
473 | * @param $url
474 | * @param $title
475 | * @param array $attributes
476 | * @param string|null $fragment
477 | *
478 | * @return static
479 | */
480 | public function url($url, $title, $order = 0, $attributes = [], $fragment = null)
481 | {
482 | if (func_num_args() == 3) {
483 | $arguments = func_get_args();
484 |
485 | return $this->add([
486 | 'url' => $this->formatUrl(Arr::get($arguments, 0)),
487 | 'title' => Arr::get($arguments, 1),
488 | 'attributes' => Arr::get($arguments, 2),
489 | ]);
490 | }
491 |
492 | $url = $this->formatUrl($url);
493 |
494 | $fragment = $fragment ?: $this->fragmentUrl;
495 |
496 | $item = MenuItem::make(compact('url', 'title', 'order', 'attributes', 'fragment'));
497 |
498 | $this->items[] = $item;
499 |
500 | return $item;
501 | }
502 |
503 | /**
504 | * Add new divider item.
505 | *
506 | * @param int $order
507 | * @return \Akaunting\Menu\MenuItem
508 | */
509 | public function addDivider($order = null)
510 | {
511 | $this->items[] = new MenuItem([
512 | 'name' => 'divider',
513 | 'order' => $order,
514 | ]);
515 |
516 | return $this;
517 | }
518 |
519 | /**
520 | * Add new header item.
521 | *
522 | * @return \Akaunting\Menu\MenuItem
523 | */
524 | public function addHeader($title, $order = null)
525 | {
526 | $this->items[] = new MenuItem([
527 | 'name' => 'header',
528 | 'title' => $title,
529 | 'order' => $order,
530 | ]);
531 |
532 | return $this;
533 | }
534 |
535 | /**
536 | * Alias for "addHeader" method.
537 | *
538 | * @param string $title
539 | *
540 | * @return $this
541 | */
542 | public function header($title)
543 | {
544 | return $this->addHeader($title);
545 | }
546 |
547 | /**
548 | * Alias for "addDivider" method.
549 | *
550 | * @return $this
551 | */
552 | public function divider()
553 | {
554 | return $this->addDivider();
555 | }
556 |
557 | /**
558 | * Get items count.
559 | *
560 | * @return int
561 | */
562 | public function count(): int
563 | {
564 | return count($this->items);
565 | }
566 |
567 | /**
568 | * Empty the current menu items.
569 | */
570 | public function destroy()
571 | {
572 | $this->items = [];
573 |
574 | return $this;
575 | }
576 |
577 | /**
578 | * Render the menu to HTML tag.
579 | *
580 | * @param string $presenter
581 | *
582 | * @return string
583 | */
584 | public function render($presenter = null)
585 | {
586 | $this->resolveItems($this->items);
587 |
588 | if (!is_null($this->view)) {
589 | return $this->renderView($presenter);
590 | }
591 |
592 | if ($this->hasStyle($presenter)) {
593 | $this->setPresenterFromStyle($presenter);
594 | }
595 |
596 | if (!is_null($presenter) && !$this->hasStyle($presenter)) {
597 | $this->setPresenter($presenter);
598 | }
599 |
600 | return $this->renderMenu();
601 | }
602 |
603 | /**
604 | * Render menu via view presenter.
605 | *
606 | * @return \Illuminate\View\View
607 | */
608 | public function renderView($presenter = null)
609 | {
610 | return $this->views->make($presenter ?: $this->view, [
611 | 'items' => $this->getOrderedItems(),
612 | ]);
613 | }
614 |
615 | /**
616 | * Get original items.
617 | *
618 | * @return array
619 | */
620 | public function getItems()
621 | {
622 | return $this->items;
623 | }
624 |
625 | /**
626 | * Get menu items as laravel collection instance.
627 | *
628 | * @return \Illuminate\Support\Collection
629 | */
630 | public function toCollection()
631 | {
632 | return collect($this->items);
633 | }
634 |
635 | /**
636 | * Get menu items as array.
637 | *
638 | * @return array
639 | */
640 | public function toArray()
641 | {
642 | return $this->toCollection()->toArray();
643 | }
644 |
645 | /**
646 | * Enable menu ordering.
647 | *
648 | * @return self
649 | */
650 | public function enableOrdering()
651 | {
652 | $this->ordering = true;
653 |
654 | return $this;
655 | }
656 |
657 | /**
658 | * Disable menu ordering.
659 | *
660 | * @return self
661 | */
662 | public function disableOrdering()
663 | {
664 | $this->ordering = false;
665 |
666 | return $this;
667 | }
668 |
669 | /**
670 | * Get menu items and order it by 'order' key.
671 | *
672 | * @return array
673 | */
674 | public function getOrderedItems()
675 | {
676 | if (config('menu.ordering') || $this->ordering) {
677 | return $this->toCollection()->sortBy(function ($item) {
678 | return $item->order;
679 | })->all();
680 | }
681 |
682 | return $this->items;
683 | }
684 |
685 | /**
686 | * Render the menu.
687 | *
688 | * @return string
689 | */
690 | protected function renderMenu()
691 | {
692 | $presenter = $this->getPresenter();
693 | $menu = $presenter->getOpenTagWrapper();
694 |
695 | foreach ($this->getOrderedItems() as $item) {
696 | if ($item->hidden()) {
697 | continue;
698 | }
699 |
700 | if ($item->hasSubMenu()) {
701 | $menu .= $presenter->getMenuWithDropDownWrapper($item);
702 | } elseif ($item->isHeader()) {
703 | $menu .= $presenter->getHeaderWrapper($item);
704 | } elseif ($item->isDivider()) {
705 | $menu .= $presenter->getDividerWrapper();
706 | } else {
707 | $menu .= $presenter->getMenuWithoutDropdownWrapper($item);
708 | }
709 | }
710 |
711 | $menu .= $presenter->getCloseTagWrapper();
712 |
713 | return $menu;
714 | }
715 | }
716 |
--------------------------------------------------------------------------------
/src/MenuItem.php:
--------------------------------------------------------------------------------
1 | properties = $properties;
112 | $this->fill($properties);
113 | }
114 |
115 | /**
116 | * Set the icon property when the icon is defined in the link attributes.
117 | *
118 | * @param array $properties
119 | *
120 | * @return array
121 | */
122 | protected static function setIconAttribute(array $properties)
123 | {
124 | $icon = Arr::get($properties, 'attributes.icon');
125 | if (!is_null($icon)) {
126 | $properties['icon'] = $icon;
127 |
128 | Arr::forget($properties, 'attributes.icon');
129 |
130 | return $properties;
131 | }
132 |
133 | return $properties;
134 | }
135 |
136 | /**
137 | * Get random name.
138 | *
139 | * @param array $attributes
140 | *
141 | * @return string
142 | */
143 | protected static function getRandomName(array $attributes)
144 | {
145 | return substr(md5(Arr::get($attributes, 'title', Str::random(6))), 0, 5);
146 | }
147 |
148 | /**
149 | * Create new static instance.
150 | *
151 | * @param array $properties
152 | *
153 | * @return static
154 | */
155 | public static function make(array $properties)
156 | {
157 | $properties = self::setIconAttribute($properties);
158 |
159 | return new static($properties);
160 | }
161 |
162 | /**
163 | * Fill the attributes.
164 | *
165 | * @param array $attributes
166 | */
167 | public function fill($attributes)
168 | {
169 | foreach ($attributes as $key => $value) {
170 | if (in_array($key, $this->fillable)) {
171 | $this->{$key} = $value;
172 | }
173 | }
174 | }
175 |
176 | /**
177 | * Create new menu child item using array.
178 | *
179 | * @param $attributes
180 | *
181 | * @return $this
182 | */
183 | public function child($attributes)
184 | {
185 | $this->childs[] = static::make($attributes);
186 |
187 | return $this;
188 | }
189 |
190 | /**
191 | * Register new child menu with dropdown.
192 | *
193 | * @param $title
194 | * @param callable $callback
195 | * @param int $order
196 | * @param array $attributes
197 | * @param string|null $fragment
198 | *
199 | * @return $this
200 | */
201 | public function dropdown($title, \Closure $callback, $order = 0, array $attributes = [], $fragment = null)
202 | {
203 | $properties = compact('title', 'order', 'attributes', 'fragment');
204 |
205 | if (func_num_args() === 3) {
206 | $arguments = func_get_args();
207 |
208 | $title = Arr::get($arguments, 0);
209 | $attributes = Arr::get($arguments, 2);
210 |
211 | $properties = compact('title', 'attributes');
212 | }
213 |
214 | $child = static::make($properties);
215 |
216 | call_user_func($callback, $child);
217 |
218 | $this->childs[] = $child;
219 |
220 | return $child;
221 | }
222 |
223 | /**
224 | * Create new menu item and set the action to route.
225 | *
226 | * @param $route
227 | * @param $title
228 | * @param array $parameters
229 | * @param array $attributes
230 | * @param string|null $fragment
231 | *
232 | * @return MenuItem
233 | */
234 | public function route($route, $title, $parameters = [], $order = 0, $attributes = [], $fragment = null)
235 | {
236 | if (func_num_args() === 4) {
237 | $arguments = func_get_args();
238 |
239 | return $this->add([
240 | 'route' => [Arr::get($arguments, 0), Arr::get($arguments, 2)],
241 | 'title' => Arr::get($arguments, 1),
242 | 'attributes' => Arr::get($arguments, 3),
243 | ]);
244 | }
245 |
246 | $route = [$route, $parameters];
247 |
248 | return $this->add(compact('route', 'title', 'order', 'attributes', 'fragment'));
249 | }
250 |
251 | /**
252 | * Create new menu item and set the action to url.
253 | *
254 | * @param $url
255 | * @param $title
256 | * @param array $attributes
257 | * @param string|null $fragment
258 | *
259 | * @return MenuItem
260 | */
261 | public function url($url, $title, $order = 0, $attributes = [], $fragment = null)
262 | {
263 | if (func_num_args() === 3) {
264 | $arguments = func_get_args();
265 |
266 | return $this->add([
267 | 'url' => Arr::get($arguments, 0),
268 | 'title' => Arr::get($arguments, 1),
269 | 'attributes' => Arr::get($arguments, 2),
270 | ]);
271 | }
272 |
273 | return $this->add(compact('url', 'title', 'order', 'attributes', 'fragment'));
274 | }
275 |
276 | /**
277 | * Add new child item.
278 | *
279 | * @param array $properties
280 | *
281 | * @return $this
282 | */
283 | public function add(array $properties)
284 | {
285 | $item = static::make($properties);
286 |
287 | $this->childs[] = $item;
288 |
289 | return $item;
290 | }
291 |
292 | /**
293 | * Add new divider.
294 | *
295 | * @param int $order
296 | *
297 | * @return self
298 | */
299 | public function addDivider($order = null)
300 | {
301 | $item = static::make(['name' => 'divider', 'order' => $order]);
302 |
303 | $this->childs[] = $item;
304 |
305 | return $item;
306 | }
307 |
308 | /**
309 | * Alias method instead "addDivider".
310 | *
311 | * @param int $order
312 | *
313 | * @return MenuItem
314 | */
315 | public function divider($order = null)
316 | {
317 | return $this->addDivider($order);
318 | }
319 |
320 | /**
321 | * Add dropdown header.
322 | *
323 | * @param $title
324 | *
325 | * @return $this
326 | */
327 | public function addHeader($title)
328 | {
329 | $item = static::make([
330 | 'name' => 'header',
331 | 'title' => $title,
332 | ]);
333 |
334 | $this->childs[] = $item;
335 |
336 | return $item;
337 | }
338 |
339 | /**
340 | * Same with "addHeader" method.
341 | *
342 | * @param $title
343 | *
344 | * @return $this
345 | */
346 | public function header($title)
347 | {
348 | return $this->addHeader($title);
349 | }
350 |
351 | /**
352 | * Get childs.
353 | *
354 | * @return array
355 | */
356 | public function getChilds()
357 | {
358 | if (config('menu.ordering')) {
359 | return collect($this->childs)->sortBy('order')->all();
360 | }
361 |
362 | return $this->childs;
363 | }
364 |
365 | /**
366 | * Get url.
367 | *
368 | * @return string
369 | */
370 | public function getUrl()
371 | {
372 | if ($this->route !== null) {
373 | $url = route($this->route[0], $this->route[1]);
374 |
375 | return !is_null($this->fragment) ? $url . '#' . $this->fragment : $url;
376 | }
377 |
378 | if (empty($this->url)) {
379 | return url("/#");
380 | }
381 |
382 | return url($this->url);
383 | }
384 |
385 | /**
386 | * Get request url.
387 | *
388 | * @return string
389 | */
390 | public function getRequest()
391 | {
392 | return ltrim(str_replace(url('/'), '', $this->getUrl()), '/');
393 | }
394 |
395 | /**
396 | * Get icon.
397 | *
398 | * @param null|string $default
399 | *
400 | * @return string
401 | */
402 | public function getIcon($default = null)
403 | {
404 | if ($this->icon !== null && $this->icon !== '') {
405 | return '';
406 | }
407 | if ($default === null) {
408 | return $default;
409 | }
410 |
411 | return '';
412 | }
413 |
414 | /**
415 | * Get properties.
416 | *
417 | * @return array
418 | */
419 | public function getProperties()
420 | {
421 | return $this->properties;
422 | }
423 |
424 | /**
425 | * Get HTML attribute data.
426 | *
427 | * @return mixed
428 | */
429 | public function getAttributes()
430 | {
431 | $attributes = $this->attributes ? $this->attributes : [];
432 |
433 | Arr::forget($attributes, ['active', 'icon', 'search_keywords']);
434 |
435 | return HTML::attributes($attributes);
436 | }
437 |
438 | /**
439 | * Check is the current item divider.
440 | *
441 | * @return bool
442 | */
443 | public function isDivider()
444 | {
445 | return $this->is('divider');
446 | }
447 |
448 | /**
449 | * Check is the current item divider.
450 | *
451 | * @return bool
452 | */
453 | public function isHeader()
454 | {
455 | return $this->is('header');
456 | }
457 |
458 | /**
459 | * Check is the current item divider.
460 | *
461 | * @param $name
462 | *
463 | * @return bool
464 | */
465 | public function is($name)
466 | {
467 | return $this->name == $name;
468 | }
469 |
470 | /**
471 | * Check is the current item has sub menu .
472 | *
473 | * @return bool
474 | */
475 | public function hasSubMenu()
476 | {
477 | return !empty($this->childs);
478 | }
479 |
480 | /**
481 | * Same with hasSubMenu.
482 | *
483 | * @return bool
484 | */
485 | public function hasChilds()
486 | {
487 | return $this->hasSubMenu();
488 | }
489 |
490 | /**
491 | * Check the active state for current menu.
492 | *
493 | * @return mixed
494 | */
495 | public function hasActiveOnChild()
496 | {
497 | if ($this->inactive()) {
498 | return false;
499 | }
500 |
501 | return $this->hasChilds() ? $this->getActiveStateFromChilds() : false;
502 | }
503 |
504 | /**
505 | * Get active state from child menu items.
506 | *
507 | * @return bool
508 | */
509 | public function getActiveStateFromChilds()
510 | {
511 | foreach ($this->getChilds() as $child) {
512 | if ($child->inactive()) {
513 | continue;
514 | }
515 |
516 | if ($child->hasChilds()) {
517 | if ($child->getActiveStateFromChilds()) {
518 | return true;
519 | }
520 | } elseif ($child->isActive()) {
521 | return true;
522 | } elseif ($child->hasRoute() && $child->getActiveStateFromRoute()) {
523 | return true;
524 | } elseif ($child->getActiveStateFromUrl()) {
525 | return true;
526 | }
527 | }
528 |
529 | return false;
530 | }
531 |
532 | /**
533 | * Get inactive state.
534 | *
535 | * @return bool
536 | */
537 | public function inactive()
538 | {
539 | $inactive = $this->getInactiveAttribute();
540 |
541 | if (is_bool($inactive)) {
542 | return $inactive;
543 | }
544 |
545 | if ($inactive instanceof \Closure) {
546 | return call_user_func($inactive);
547 | }
548 |
549 | return false;
550 | }
551 |
552 | /**
553 | * Get active attribute.
554 | *
555 | * @return string
556 | */
557 | public function getActiveAttribute()
558 | {
559 | return Arr::get($this->attributes, 'active');
560 | }
561 |
562 | /**
563 | * Get inactive attribute.
564 | *
565 | * @return string
566 | */
567 | public function getInactiveAttribute()
568 | {
569 | return Arr::get($this->attributes, 'inactive');
570 | }
571 |
572 | /**
573 | * Get active state for current item.
574 | *
575 | * @return mixed
576 | */
577 | public function isActive()
578 | {
579 | if ($this->inactive()) {
580 | return false;
581 | }
582 |
583 | $active = $this->getActiveAttribute();
584 |
585 | if (is_bool($active)) {
586 | return $active;
587 | }
588 |
589 | if ($active instanceof \Closure) {
590 | return call_user_func($active);
591 | }
592 |
593 | if ($this->hasRoute()) {
594 | return $this->getActiveStateFromRoute();
595 | }
596 |
597 | return $this->getActiveStateFromUrl();
598 | }
599 |
600 | /**
601 | * Determine the current item using route.
602 | *
603 | * @return bool
604 | */
605 | protected function hasRoute()
606 | {
607 | return !empty($this->route);
608 | }
609 |
610 | /**
611 | * Get active status using route.
612 | *
613 | * @return bool
614 | */
615 | protected function getActiveStateFromRoute()
616 | {
617 | $url = str_replace(url('/') . '/', '', $this->getUrl());
618 | $url = str_replace('#' . (string) $this->fragment, '', $url);
619 |
620 | return $this->checkActiveState($url);
621 | }
622 |
623 | /**
624 | * Get active status using request url.
625 | *
626 | * @return bool
627 | */
628 | protected function getActiveStateFromUrl()
629 | {
630 | $url = str_replace('#' . (string) $this->fragment, '', (string) $this->url);
631 |
632 | return $this->checkActiveState($url);
633 | }
634 |
635 | /**
636 | * Check the active state.
637 | *
638 | * @return bool
639 | */
640 | protected function checkActiveState($url)
641 | {
642 | if (empty($url) || in_array($url, config('menu.home_urls', ['/']))) {
643 | return Request::is($url);
644 | } else {
645 | return Request::is($url, $url . '/*');
646 | }
647 | }
648 |
649 | /**
650 | * Set order value.
651 | *
652 | * @param int $order
653 | * @return self
654 | */
655 | public function order($order)
656 | {
657 | $this->order = $order;
658 |
659 | return $this;
660 | }
661 |
662 | /**
663 | * Set hide condition for current menu item.
664 | *
665 | * @param Closure
666 | * @return boolean
667 | */
668 | public function hideWhen(Closure $callback)
669 | {
670 | $this->hideWhen = $callback;
671 |
672 | return $this;
673 | }
674 |
675 | /**
676 | * Determine whether the menu item is hidden.
677 | *
678 | * @return boolean
679 | */
680 | public function hidden()
681 | {
682 | if (is_null($this->hideWhen)) {
683 | return false;
684 | }
685 |
686 | return call_user_func($this->hideWhen) == true;
687 | }
688 |
689 | /**
690 | * Get the instance as an array.
691 | *
692 | * @return array
693 | */
694 | public function toArray()
695 | {
696 | return $this->getProperties();
697 | }
698 |
699 | /**
700 | * Get property.
701 | *
702 | * @param string $key
703 | *
704 | * @return string|null
705 | */
706 | public function __get($key)
707 | {
708 | return isset($this->$key) ? $this->$key : null;
709 | }
710 | }
711 |
--------------------------------------------------------------------------------
/src/Presenters/Admin/Adminlte.php:
--------------------------------------------------------------------------------
1 | ' . PHP_EOL;
15 | }
16 |
17 | /**
18 | * {@inheritdoc }.
19 | */
20 | public function getCloseTagWrapper()
21 | {
22 | return PHP_EOL . '' . PHP_EOL;
23 | }
24 |
25 | /**
26 | * {@inheritdoc }.
27 | */
28 | public function getMenuWithoutDropdownWrapper($item)
29 | {
30 | return '
getActiveState($item) . '>getAttributes() . '>' . $item->getIcon() . ' ' . $item->title . '' . PHP_EOL;
31 | }
32 |
33 | /**
34 | * {@inheritdoc }.
35 | */
36 | public function getActiveState($item, $state = ' class="active"')
37 | {
38 | return $item->isActive() ? $state : null;
39 | }
40 |
41 | /**
42 | * Get active state on child items.
43 | *
44 | * @param $item
45 | * @param string $state
46 | *
47 | * @return null|string
48 | */
49 | public function getActiveStateOnChild($item, $state = 'active')
50 | {
51 | return $item->hasActiveOnChild() ? $state : null;
52 | }
53 |
54 | /**
55 | * {@inheritdoc }.
56 | */
57 | public function getDividerWrapper()
58 | {
59 | return '';
60 | }
61 |
62 | /**
63 | * {@inheritdoc }.
64 | */
65 | public function getHeaderWrapper($item)
66 | {
67 | return '';
68 | }
69 |
70 | /**
71 | * {@inheritdoc }.
72 | */
73 | public function getMenuWithDropDownWrapper($item)
74 | {
75 | return '
76 |
77 | ' . $item->getIcon() . ' ' . $item->title . '
78 |
79 |
80 |
81 |
82 |
85 | '
86 | . PHP_EOL;
87 | }
88 |
89 | /**
90 | * Get multilevel menu wrapper.
91 | *
92 | * @param \Akaunting\Menu\MenuItem $item
93 | *
94 | * @return string`
95 | */
96 | public function getMultiLevelDropdownWrapper($item)
97 | {
98 | return '
99 |
100 | ' . $item->getIcon() . ' ' . $item->title . '
101 |
102 |
103 |
104 |
105 |
108 | '
109 | . PHP_EOL;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/Presenters/Admin/Argon.php:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
' . PHP_EOL;
20 | }
21 |
22 | /**
23 | * {@inheritdoc }.
24 | */
25 | public function getCloseTagWrapper()
26 | {
27 | return PHP_EOL . '
28 |
29 | ' . PHP_EOL;
30 | }
31 |
32 | /**
33 | * {@inheritdoc }.
34 | */
35 | public function getMenuWithoutDropdownWrapper($item)
36 | {
37 | $html = '';
38 | $html .= ' getAttributes() . '>';
39 | $html .= $item->getIcon();
40 | $html .= ' ' . $item->title . '';
41 | $html .= ' ';
42 | $html .= '' . PHP_EOL;
43 |
44 | return $html;
45 | }
46 |
47 | /**
48 | * {@inheritdoc }.
49 | */
50 | public function getActiveState($item, $state = ' active')
51 | {
52 | return $item->isActive() ? $state : '';
53 | }
54 |
55 | /**
56 | * Get active state on child items.
57 | *
58 | * @param $item
59 | * @param string $state
60 | *
61 | * @return null|string
62 | */
63 | public function getActiveStateOnChild($item, $state = ' active show')
64 | {
65 | return $item->hasActiveOnChild() ? $state : null;
66 | }
67 |
68 | /**
69 | * Get active state on child items.
70 | *
71 | * @param $item
72 | * @param string $state
73 | *
74 | * @return null|string
75 | */
76 | public function getShowStateOnChild($item, $state = ' show')
77 | {
78 | return $item->hasActiveOnChild() ? $state : null;
79 | }
80 |
81 | /**
82 | * {@inheritdoc }.
83 | */
84 | public function getDividerWrapper()
85 | {
86 | return '
';
87 | }
88 |
89 | /**
90 | * {@inheritdoc }.
91 | */
92 | public function getHeaderWrapper($item)
93 | {
94 | return '' . $item->title . '
';
95 | }
96 |
97 | /**
98 | * {@inheritdoc }.
99 | */
100 | public function getMenuWithDropDownWrapper($item)
101 | {
102 | $id = Str::slug($item->title);
103 |
104 | return '
105 |
106 | ' . $item->getIcon() . '
107 | ' . $item->title . '
108 |
109 |
110 |
111 | ' . $this->getChildMenuItems($item) . '
112 |
113 |
114 | '
115 | . PHP_EOL;
116 | }
117 |
118 | /**
119 | * Get multilevel menu wrapper.
120 | *
121 | * @param \Akaunting\Menu\MenuItem $item
122 | *
123 | * @return string`
124 | */
125 | public function getMultiLevelDropdownWrapper($item)
126 | {
127 | $id = Str::slug($item->title);
128 |
129 | return '
130 |
131 | ' . $item->getIcon() . '
132 | ' . $item->title . '
133 |
134 |
135 |
136 | ' . $this->getChildMenuItems($item) . '
137 |
138 |
139 | '
140 | . PHP_EOL;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/Presenters/Admin/MetronicHorizontal.php:
--------------------------------------------------------------------------------
1 | ' . PHP_EOL;
21 | }
22 |
23 | /**
24 | * {@inheritdoc }
25 | */
26 | public function getCloseTagWrapper()
27 | {
28 | return PHP_EOL . '' . PHP_EOL;
29 | }
30 |
31 | /**
32 | * {@inheritdoc }
33 | */
34 | public function getMenuWithoutDropdownWrapper($item)
35 | {
36 | return 'getActiveState($item) . '>' . $item->getIcon() . '';
37 | }
38 |
39 | /**
40 | * {@inheritdoc }
41 | */
42 | public function getActiveState($item)
43 | {
44 | return \Request::is($item->getRequest()) ? ' class="m-menu__item m-menu__item--rel active"' : 'class="m-menu__item m-menu__item--rel"';
45 | }
46 |
47 | /**
48 | * {@inheritdoc }
49 | */
50 | public function getDividerWrapper()
51 | {
52 | return '';
53 | }
54 |
55 | /**
56 | * {@inheritdoc }
57 | */
58 | public function getMenuWithDropDownWrapper($item)
59 | {
60 | if ($item->title == '...') {
61 | return '' . PHP_EOL;
74 | } else {
75 | return '' . PHP_EOL;
91 | }
92 | }
93 |
94 | public function getMultiLevelDropdownWrapper($item)
95 | {
96 | return '' . PHP_EOL;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/Presenters/Admin/Tailwind.php:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
' . PHP_EOL;
20 | }
21 |
22 | /**
23 | * {@inheritdoc }.
24 | */
25 | public function getCloseTagWrapper()
26 | {
27 | return PHP_EOL . '
28 |
29 | ' . PHP_EOL;
30 | }
31 |
32 | /**
33 | * {@inheritdoc }.
34 | */
35 | public function getMenuWithoutDropdownWrapper($item)
36 | {
37 | return '
38 | getAttributes() . '>
39 | ' . $this->getIcon($item) . '
40 | ' . $item->title . '
41 |
42 |
43 | '
44 | . PHP_EOL;
45 | }
46 |
47 | /**
48 | * {@inheritdoc }.
49 | */
50 | public function getActiveState($item, $state = 'active-menu')
51 | {
52 | return $item->isActive() ? $state : '';
53 | }
54 |
55 | /**
56 | * Get active state on child items.
57 | *
58 | * @param $item
59 | * @param string $state
60 | *
61 | * @return null|string
62 | */
63 | public function getActiveStateOnChild($item, $state = 'open')
64 | {
65 | return $item->hasActiveOnChild() ? $state : '';
66 | }
67 |
68 | /**
69 | * Get active state on child items.
70 | *
71 | * @param $item
72 | * @param string $state
73 | *
74 | * @return null|string
75 | */
76 | public function getShowStateOnChild($item, $state = 'open')
77 | {
78 | return $item->hasActiveOnChild() ? $state : ' ';
79 | }
80 |
81 | /**
82 | * {@inheritdoc }.
83 | */
84 | public function getDividerWrapper()
85 | {
86 | return '
';
87 | }
88 |
89 | /**
90 | * {@inheritdoc }.
91 | */
92 | public function getHeaderWrapper($item)
93 | {
94 | return '' . $item->title . '
';
95 | }
96 |
97 | /**
98 | * {@inheritdoc }.
99 | */
100 | public function getMenuWithDropDownWrapper($item)
101 | {
102 | $id = Str::slug($item->title);
103 |
104 | return '
105 | getActiveStateOnChild($item) . '>
106 |
107 |
108 | ' . $this->getIcon($item) . '
109 | ' . $item->title . '
110 | ' . $this->getChevron($item) . '
111 |
112 |
113 |
118 | '
119 | . PHP_EOL;
120 | }
121 |
122 | /**
123 | * Get multilevel menu wrapper.
124 | *
125 | * @param \Akaunting\Menu\MenuItem $item
126 | *
127 | * @return string`
128 | */
129 | public function getMultiLevelDropdownWrapper($item)
130 | {
131 | $id = Str::slug($item->title);
132 |
133 | return 'getActiveStateOnChild($item) . '>
134 |
135 |
136 | ' . $this->getIcon($item) . '
137 | ' . $item->title . '
138 |
139 | ' . $this->getChevron($item) . '
140 |
141 |
142 |
147 | '
148 | . PHP_EOL;
149 | }
150 |
151 | public function iconState($item, $state = '')
152 | {
153 | return $item->isActive() ? $state : '-outlined';
154 | }
155 |
156 | public function iconChildState($item, $state = '')
157 | {
158 | return $item->hasActiveOnChild() ? $state : '-outlined';
159 | }
160 |
161 | public function getClass($item)
162 | {
163 | $class = 'flex items-center text-purple';
164 |
165 | $attributes = $item->attributes;
166 |
167 | if (!empty($attributes['class'])) {
168 | $class .= ' ' . $attributes['class'];
169 | }
170 |
171 | return $class;
172 | }
173 |
174 | public function getIcon($item)
175 | {
176 | if (empty($item->icon)) {
177 | return '';
178 | }
179 |
180 | $state = empty($item->getChilds()) ? $this->iconState($item) : $this->iconChildState($item);
181 |
182 | return '
183 | ' . $item->icon . '
184 |
' . PHP_EOL;
185 | }
186 |
187 | public function getChevron($item)
188 | {
189 | $state = $this->chevronState($item);
190 |
191 | return 'expand' . $state . '' . PHP_EOL;
192 | }
193 |
194 | public function chevronState($item, $state = '_less')
195 | {
196 | return $item->hasActiveOnChild() ? $state : '_more';
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/src/Presenters/Bootstrap3/Nav.php:
--------------------------------------------------------------------------------
1 | ' . PHP_EOL;
13 | }
14 |
15 | /**
16 | * {@inheritdoc }.
17 | */
18 | public function getMenuWithDropDownWrapper($item)
19 | {
20 | return '
21 |
22 | ' . $item->getIcon() . ' ' . $item->title . '
23 |
24 |
25 |
28 | '
29 | . PHP_EOL;
30 | }
31 |
32 | /**
33 | * Get multilevel menu wrapper.
34 | *
35 | * @param \Akaunting\Menu\MenuItem $item
36 | *
37 | * @return string`
38 | */
39 | public function getMultiLevelDropdownWrapper($item)
40 | {
41 | return '
42 |
43 | ' . $item->getIcon() . ' ' . $item->title . '
44 |
45 |
46 |
49 | '
50 | . PHP_EOL;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Presenters/Bootstrap3/NavPills.php:
--------------------------------------------------------------------------------
1 | ' . PHP_EOL;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Presenters/Bootstrap3/NavTab.php:
--------------------------------------------------------------------------------
1 | ' . PHP_EOL;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Presenters/Bootstrap3/Navbar.php:
--------------------------------------------------------------------------------
1 | ' . PHP_EOL;
15 | }
16 |
17 | /**
18 | * {@inheritdoc }.
19 | */
20 | public function getCloseTagWrapper()
21 | {
22 | return PHP_EOL . '' . PHP_EOL;
23 | }
24 |
25 | /**
26 | * {@inheritdoc }.
27 | */
28 | public function getMenuWithoutDropdownWrapper($item)
29 | {
30 | return 'getActiveState($item) . '>getAttributes() . '>' . $item->getIcon() . ' ' . $item->title . '' . PHP_EOL;
31 | }
32 |
33 | /**
34 | * {@inheritdoc }.
35 | */
36 | public function getActiveState($item, $state = ' class="active"')
37 | {
38 | return $item->isActive() ? $state : null;
39 | }
40 |
41 | /**
42 | * Get active state on child items.
43 | *
44 | * @param $item
45 | * @param string $state
46 | *
47 | * @return null|string
48 | */
49 | public function getActiveStateOnChild($item, $state = 'active')
50 | {
51 | return $item->hasActiveOnChild() ? $state : null;
52 | }
53 |
54 | /**
55 | * {@inheritdoc }.
56 | */
57 | public function getDividerWrapper()
58 | {
59 | return '';
60 | }
61 |
62 | /**
63 | * {@inheritdoc }.
64 | */
65 | public function getHeaderWrapper($item)
66 | {
67 | return '';
68 | }
69 |
70 | /**
71 | * {@inheritdoc }.
72 | */
73 | public function getMenuWithDropDownWrapper($item)
74 | {
75 | return '
76 |
77 | ' . $item->getIcon() . ' ' . $item->title . '
78 |
79 |
80 |
83 | '
84 | . PHP_EOL;
85 | }
86 |
87 | /**
88 | * Get multilevel menu wrapper.
89 | *
90 | * @param \Akaunting\Menu\MenuItem $item
91 | *
92 | * @return string`
93 | */
94 | public function getMultiLevelDropdownWrapper($item)
95 | {
96 | return '
97 |
98 | ' . $item->getIcon() . ' ' . $item->title . '
99 |
100 |
101 |
104 | '
105 | . PHP_EOL;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/Presenters/Bootstrap3/NavbarRight.php:
--------------------------------------------------------------------------------
1 | ' . PHP_EOL;
13 | }
14 |
15 | /**
16 | * {@inheritdoc }.
17 | */
18 | public function getMenuWithDropDownWrapper($item)
19 | {
20 | return '
21 |
22 | ' . $item->getIcon() . ' ' . $item->title . '
23 |
24 |
25 |
28 | '
29 | . PHP_EOL;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Presenters/Bootstrap3/Sidebar.php:
--------------------------------------------------------------------------------
1 | ';
18 | }
19 |
20 | /**
21 | * Get close tag wrapper.
22 | *
23 | * @return string
24 | */
25 | public function getCloseTagWrapper()
26 | {
27 | return '';
28 | }
29 |
30 | /**
31 | * Get menu tag without dropdown wrapper.
32 | *
33 | * @param \Akaunting\Menu\MenuItem $item
34 | *
35 | * @return string
36 | */
37 | public function getMenuWithoutDropdownWrapper($item)
38 | {
39 | return 'getActiveState($item) . '>
40 | getAttributes() . '>'
41 | . $item->getIcon() . ' ' . $item->title . '' . PHP_EOL;
42 | }
43 |
44 | /**
45 | * {@inheritdoc }.
46 | */
47 | public function getActiveState($item, $state = ' class="active"')
48 | {
49 | return $item->isActive() ? $state : null;
50 | }
51 |
52 | /**
53 | * Get active state on child items.
54 | *
55 | * @param $item
56 | * @param string $state
57 | *
58 | * @return null|string
59 | */
60 | public function getActiveStateOnChild($item, $state = 'active')
61 | {
62 | return $item->hasActiveOnChild() ? $state : null;
63 | }
64 |
65 | /**
66 | * {@inheritdoc }.
67 | */
68 | public function getDividerWrapper()
69 | {
70 | return '';
71 | }
72 |
73 | /**
74 | * {@inheritdoc }.
75 | */
76 | public function getHeaderWrapper($item)
77 | {
78 | return '';
79 | }
80 |
81 | /**
82 | * {@inheritdoc }.
83 | */
84 | public function getMenuWithDropDownWrapper($item)
85 | {
86 | $id = Str::random();
87 |
88 | return '
89 |
90 |
91 | ' . $item->getIcon() . ' ' . $item->title . '
92 |
93 |
94 |
95 |
96 | ' . $this->getChildMenuItems($item) . '
97 |
98 |
99 |
100 |
101 | ' . PHP_EOL;
102 | }
103 |
104 | /**
105 | * Get multilevel menu wrapper.
106 | *
107 | * @param \Akaunting\Menu\MenuItem $item
108 | *
109 | * @return string`
110 | */
111 | public function getMultiLevelDropdownWrapper($item)
112 | {
113 | return $this->getMenuWithDropDownWrapper($item);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/Presenters/Foundation/Zurb.php:
--------------------------------------------------------------------------------
1 |
15 | ' . PHP_EOL;
24 | }
25 |
26 | /**
27 | * {@inheritdoc }
28 | */
29 | public function getMenuWithoutDropdownWrapper($item)
30 | {
31 | return 'getActiveState($item) . '>' . $item->title . '';
32 | }
33 |
34 | /**
35 | * {@inheritdoc }
36 | */
37 | public function getActiveState($item)
38 | {
39 | return \Request::is($item->getRequest()) ? ' class="is-active"' : null;
40 | }
41 |
42 | /**
43 | * {@inheritdoc }
44 | */
45 | public function getDividerWrapper()
46 | {
47 | return '';
48 | }
49 |
50 | /**
51 | * {@inheritdoc }
52 | */
53 | public function getMenuWithDropDownWrapper($item)
54 | {
55 | return '
56 | ' . $item->title . '
57 |
60 | ' . PHP_EOL;
61 | }
62 |
63 |
64 | /**
65 | * {@inheritdoc }
66 | */
67 | public function getMultiLevelDropdownWrapper($item)
68 | {
69 | return '
70 | ' . $item->title . '
71 |
74 | ' . PHP_EOL;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/Presenters/Presenter.php:
--------------------------------------------------------------------------------
1 | getChilds() as $child) {
91 | if ($child->hidden()) {
92 | continue;
93 | }
94 |
95 | if ($child->hasSubMenu()) {
96 | $results .= $this->getMultiLevelDropdownWrapper($child);
97 | } elseif ($child->isHeader()) {
98 | $results .= $this->getHeaderWrapper($child);
99 | } elseif ($child->isDivider()) {
100 | $results .= $this->getDividerWrapper();
101 | } else {
102 | $results .= $this->getMenuWithoutDropdownWrapper($child);
103 | }
104 | }
105 |
106 | return $results;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/Presenters/PresenterInterface.php:
--------------------------------------------------------------------------------
1 | publishes([
18 | __DIR__ . '/Config/menu.php' => config_path('menu.php'),
19 | __DIR__ . '/Resources/views' => base_path('resources/views/vendor/akaunting/menu'),
20 | ], 'menu');
21 |
22 | $this->app->singleton('menu', function ($app) {
23 | return new Menu($app['view'], $app['config']);
24 | });
25 |
26 | if (file_exists($file = app_path('Support/menus.php'))) {
27 | require_once($file);
28 | }
29 | }
30 |
31 | /**
32 | * Register the application services.
33 | *
34 | * @return void
35 | */
36 | public function register()
37 | {
38 | $this->registerHtmlPackage();
39 |
40 | $this->mergeConfigFrom(__DIR__ . '/Config/menu.php', 'menu');
41 |
42 | $this->loadViewsFrom(__DIR__ . '/Resources/views', 'menu');
43 | }
44 |
45 | /**
46 | * Register "iluminate/html" package.
47 | */
48 | private function registerHtmlPackage()
49 | {
50 | $this->app->register('Collective\Html\HtmlServiceProvider');
51 |
52 | $aliases = [
53 | 'HTML' => 'Collective\Html\HtmlFacade',
54 | 'Form' => 'Collective\Html\FormFacade',
55 | ];
56 |
57 | AliasLoader::getInstance($aliases)->register();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/child/dropdown.blade.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/child/item.blade.php:
--------------------------------------------------------------------------------
1 | @if ($item->isDivider())
2 |
3 | @elseif ($item->isHeader())
4 |
5 | @else
6 |
7 |
8 | {{ $item->title }}
9 |
10 |
11 | @endif
12 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/default.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @include('menu::bootstrap3.menu')
3 |
4 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/item/dropdown.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ $item->title }}
4 |
5 |
6 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/item/item.blade.php:
--------------------------------------------------------------------------------
1 | @if ($item->isDivider())
2 |
3 | @elseif ($item->isHeader())
4 |
5 | @else
6 |
7 | getAttributes() !!}>
8 | {!! $item->getIcon() !!}
9 | {{ $item->title }}
10 |
11 |
12 | @endif
13 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/menu.blade.php:
--------------------------------------------------------------------------------
1 | @foreach ($items as $item)
2 | @if ($item->hasChilds())
3 | @include('menu::bootstrap3.item.dropdown', compact('item'))
4 | @else
5 | @include('menu::bootstrap3.item.item', compact('item'))
6 | @endif
7 | @endforeach
8 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/nav-pills-justified.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @include('menu::bootstrap3.menu')
3 |
4 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/nav-pills-stacked.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @include('menu::bootstrap3.menu')
3 |
4 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/nav-pills.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @include('menu::bootstrap3.menu')
3 |
4 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/nav-tabs-justified.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @include('menu::bootstrap3.menu')
3 |
4 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/nav-tabs.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @include('menu::bootstrap3.menu')
3 |
4 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/navbar-left.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @include('menu::bootstrap3.menu')
3 |
4 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/navbar-right.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @include('menu::bootstrap3.menu')
3 |
4 |
--------------------------------------------------------------------------------
/src/Resources/views/bootstrap3/style.blade.php:
--------------------------------------------------------------------------------
1 |
50 |
--------------------------------------------------------------------------------
/src/helpers.php:
--------------------------------------------------------------------------------
1 | get($name);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tests/MenuBuilderTest.php:
--------------------------------------------------------------------------------
1 | url('hello', 'world'));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tests/MenuItemTest.php:
--------------------------------------------------------------------------------
1 | menu = app(Menu::class);
21 | }
22 |
23 | /** @test */
24 | public function it_can_make_an_empty_menu_item()
25 | {
26 | $menuItem = MenuItem::make([]);
27 |
28 | $this->assertInstanceOf(MenuItem::class, $menuItem);
29 | }
30 |
31 | /** @test */
32 | public function it_can_set_properties_on_menu_item()
33 | {
34 | $properties = [
35 | 'url' => 'my.url',
36 | 'route' => 'my.route',
37 | 'title' => 'My Menu item',
38 | 'name' => 'my-menu-item',
39 | 'icon' => 'fa fa-user',
40 | 'parent' => 1,
41 | 'attributes' => [],
42 | 'active' => false,
43 | 'order' => 1,
44 | ];
45 |
46 | $menuItem = MenuItem::make($properties);
47 |
48 | $this->assertEquals($properties, $menuItem->getProperties());
49 | }
50 |
51 | /** @test */
52 | public function it_can_fill_a_menu_item_with_allowed_properties()
53 | {
54 | $properties = [
55 | 'url' => 'my.url',
56 | 'route' => 'my.route',
57 | 'title' => 'My Menu item',
58 | 'name' => 'my-menu-item',
59 | 'icon' => 'fa fa-user',
60 | 'parent' => 1,
61 | 'attributes' => [],
62 | 'active' => false,
63 | 'order' => 1,
64 | ];
65 |
66 | $menuItem = MenuItem::make($properties);
67 |
68 | $this->assertEquals('my.url', $menuItem->url);
69 | $this->assertEquals('my.route', $menuItem->route);
70 | $this->assertEquals('My Menu item', $menuItem->title);
71 | $this->assertEquals('my-menu-item', $menuItem->name);
72 | $this->assertEquals('fa fa-user', $menuItem->icon);
73 | $this->assertSame(1, $menuItem->parent);
74 | $this->assertSame([], $menuItem->attributes);
75 | $this->assertFalse($menuItem->active);
76 | $this->assertSame(1, $menuItem->order);
77 | }
78 |
79 | /** @test */
80 | public function it_can_set_icon_via_attributes()
81 | {
82 | $menuItem = MenuItem::make(['attributes' => ['icon' => 'fa fa-user']]);
83 |
84 | $this->assertEquals('fa fa-user', $menuItem->icon);
85 | }
86 |
87 | /** @test */
88 | public function it_can_add_a_child_menu_item()
89 | {
90 | $menuItem = MenuItem::make(['title' => 'Parent Item']);
91 | $menuItem->child(['title' => 'Child Item']);
92 |
93 | $this->assertCount(1, $menuItem->getChilds());
94 | }
95 |
96 | /** @test */
97 | public function it_can_get_ordered_children()
98 | {
99 | $this->app['config']->set('menu.ordering', true);
100 | $menuItem = MenuItem::make(['title' => 'Parent Item']);
101 | $menuItem->child(['title' => 'Child Item', 'order' => 10]);
102 | $menuItem->child(['title' => 'First Child Item', 'order' => 1]);
103 |
104 | $children = $menuItem->getChilds();
105 | $this->assertEquals('First Child Item', $children[1]->title);
106 | $this->assertEquals('Child Item', $children[0]->title);
107 | }
108 |
109 | /** @test */
110 | public function it_can_create_a_dropdown_menu_item()
111 | {
112 | $menuItem = MenuItem::make(['title' => 'Parent Item']);
113 | $menuItem->dropdown('Dropdown item', function (MenuItem $sub) {
114 | $sub->url('settings/account', 'Account');
115 | $sub->url('settings/password', 'Password');
116 | });
117 | $this->assertCount(1, $menuItem->getChilds());
118 | $this->assertCount(2, $menuItem->getChilds()[0]->getChilds());
119 | }
120 |
121 | /** @test */
122 | public function it_can_make_a_simple_route_menu_item()
123 | {
124 | $menuItem = MenuItem::make(['title' => 'Parent Item']);
125 | $menuItem->dropdown('Dropdown item', function (MenuItem $sub) {
126 | $sub->route('settings.account', 'Account', ['user_id' => 1]);
127 | });
128 | $children = $menuItem->getChilds()[0]->getChilds();
129 |
130 | $this->assertCount(1, $children);
131 | $childMenuItem = Arr::first($children);
132 | $this->assertEquals('settings.account', $childMenuItem->route[0]);
133 | $this->assertEquals(['user_id' => 1], $childMenuItem->route[1]);
134 | }
135 |
136 | /** @test */
137 | public function it_can_make_a_route_menu_item()
138 | {
139 | $menuItem = MenuItem::make(['title' => 'Parent Item']);
140 | $menuItem->dropdown('Dropdown item', function (MenuItem $sub) {
141 | $sub->route('settings.account', 'Account', ['user_id' => 1], 1, ['my-attr' => 'value']);
142 | });
143 | $children = $menuItem->getChilds()[0]->getChilds();
144 |
145 | $this->assertCount(1, $children);
146 | $childMenuItem = Arr::first($children);
147 | $this->assertEquals('settings.account', $childMenuItem->route[0]);
148 | $this->assertEquals(['user_id' => 1], $childMenuItem->route[1]);
149 | $this->assertSame(1, $childMenuItem->order);
150 | $this->assertEquals(['my-attr' => 'value'], $childMenuItem->attributes);
151 | }
152 |
153 | /** @test */
154 | public function it_can_make_a_simple_url_menu_item()
155 | {
156 | $menuItem = MenuItem::make(['title' => 'Parent Item']);
157 | $menuItem->dropdown('Dropdown item', function (MenuItem $sub) {
158 | $sub->url('settings/account', 'Account');
159 | });
160 | $children = $menuItem->getChilds()[0]->getChilds();
161 |
162 | $this->assertCount(1, $children);
163 | $childMenuItem = Arr::first($children);
164 | $this->assertEquals('settings/account', $childMenuItem->url);
165 | $this->assertEquals('Account', $childMenuItem->title);
166 | }
167 |
168 | /** @test */
169 | public function it_can_make_a_url_menu_item()
170 | {
171 | $menuItem = MenuItem::make(['title' => 'Parent Item']);
172 | $menuItem->dropdown('Dropdown item', function (MenuItem $sub) {
173 | $sub->url('settings/account', 'Account', 1, ['my-attr' => 'value']);
174 | });
175 | $children = $menuItem->getChilds()[0]->getChilds();
176 |
177 | $this->assertCount(1, $children);
178 | $childMenuItem = Arr::first($children);
179 | $this->assertEquals('settings/account', $childMenuItem->url);
180 | $this->assertEquals('Account', $childMenuItem->title);
181 | $this->assertSame(1, $childMenuItem->order);
182 | $this->assertEquals(['my-attr' => 'value'], $childMenuItem->attributes);
183 | }
184 |
185 | /** @test */
186 | public function it_can_add_a_menu_item_divider()
187 | {
188 | $menuItem = MenuItem::make(['title' => 'Parent Item']);
189 | $menuItem->dropdown('Dropdown item', function (MenuItem $sub) {
190 | $sub->url('settings/account', 'Account');
191 | $sub->divider();
192 | });
193 |
194 | $children = $menuItem->getChilds()[0]->getChilds();
195 |
196 | $this->assertCount(2, $children);
197 | $dividerMenuItem = $children[1];
198 | $this->assertEquals('divider', $dividerMenuItem->name);
199 | $this->assertTrue($dividerMenuItem->isDivider());
200 | }
201 |
202 | /** @test */
203 | public function it_can_add_a_header_menu_item()
204 | {
205 | $menuItem = MenuItem::make(['title' => 'Parent Item']);
206 | $menuItem->dropdown('Dropdown item', function (MenuItem $sub) {
207 | $sub->header('User Stuff');
208 | $sub->url('settings/account', 'Account');
209 | });
210 |
211 | $children = $menuItem->getChilds()[0]->getChilds();
212 |
213 | $this->assertCount(2, $children);
214 | $headerItem = $children[0];
215 | $this->assertEquals('header', $headerItem->name);
216 | $this->assertEquals('User Stuff', $headerItem->title);
217 | $this->assertTrue($headerItem->isHeader());
218 | }
219 |
220 | /** @test */
221 | public function it_can_get_the_correct_url_for_url_type()
222 | {
223 | $menuItem = MenuItem::make(['url' => 'settings/account', 'title' => 'Parent Item']);
224 |
225 | $this->assertEquals('http://localhost/settings/account', $menuItem->getUrl());
226 | }
227 |
228 | /** @test */
229 | public function it_can_get_the_correct_url_for_route_type()
230 | {
231 | $this->app['router']->get('settings/account', ['as' => 'settings.account']);
232 | $menuItem = MenuItem::make(['title' => 'Parent Item']);
233 | $menuItem->dropdown('Dropdown item', function (MenuItem $sub) {
234 | $sub->route('settings.account', 'Account');
235 | });
236 | $children = $menuItem->getChilds()[0]->getChilds();
237 | $childMenuItem = Arr::first($children);
238 |
239 | $this->assertEquals('http://localhost/settings/account', $childMenuItem->getUrl());
240 | }
241 |
242 | /** @test */
243 | public function it_can_get_request_uri()
244 | {
245 | $menuItem = MenuItem::make(['url' => 'settings/account', 'title' => 'Parent Item']);
246 |
247 | $this->assertEquals('settings/account', $menuItem->getRequest());
248 | }
249 |
250 | /** @test */
251 | public function it_can_get_the_icon_html_attribute()
252 | {
253 | $menuItem = MenuItem::make(['url' => 'settings/account', 'title' => 'Parent Item', 'icon' => 'fa fa-user']);
254 |
255 | $this->assertEquals('', $menuItem->getIcon());
256 | }
257 |
258 | /** @test */
259 | public function it_returns_no_icon_if_none_exist()
260 | {
261 | $menuItem = MenuItem::make(['url' => 'settings/account', 'title' => 'Parent Item']);
262 |
263 | $this->assertNull($menuItem->getIcon());
264 | }
265 |
266 | /** @test */
267 | public function it_returns_default_icon_if_none_exist()
268 | {
269 | $menuItem = MenuItem::make(['url' => 'settings/account', 'title' => 'Parent Item']);
270 |
271 | $this->assertEquals('', $menuItem->getIcon('fa fa-user'));
272 | }
273 |
274 | /** @test */
275 | public function it_can_get_item_properties()
276 | {
277 | $menuItem = MenuItem::make(['url' => 'settings/account', 'title' => 'Parent Item']);
278 |
279 | $this->assertEquals(['url' => 'settings/account', 'title' => 'Parent Item'], $menuItem->getProperties());
280 | }
281 |
282 | /** @test */
283 | public function it_can_get_item_html_attributes()
284 | {
285 | $menuItem = MenuItem::make(['url' => 'settings/account', 'title' => 'Parent Item', 'attributes' => ['my-attr' => 'value']]);
286 |
287 | $this->assertEquals(' my-attr="value"', $menuItem->getAttributes());
288 | }
289 |
290 | /** @test */
291 | public function it_can_check_for_a_submenu()
292 | {
293 | $menuItem = MenuItem::make(['title' => 'Parent Item']);
294 | $menuItem->dropdown('Dropdown item', function (MenuItem $sub) {
295 | $sub->header('User Stuff');
296 | $sub->url('settings/account', 'Account');
297 | });
298 |
299 | $this->assertTrue($menuItem->hasSubMenu());
300 | $this->assertTrue($menuItem->hasChilds());
301 | }
302 |
303 | public function it_can_check_active_state_on_item()
304 | {
305 | }
306 | }
307 |
--------------------------------------------------------------------------------
/tests/MenuTest.php:
--------------------------------------------------------------------------------
1 | menu = app(Menu::class);
20 | }
21 |
22 | /** @test */
23 | public function it_generates_an_empty_menu()
24 | {
25 | $this->menu->create('test', function (MenuBuilder $menu) {
26 | });
27 |
28 | $expected = <<
31 |
32 |
33 |
34 | TEXT;
35 |
36 | self::assertEquals($expected, $this->menu->get('test'));
37 | }
38 |
39 | /** @test */
40 | public function it_makes_is_an_alias_for_create()
41 | {
42 | $this->menu->make('test', function (MenuBuilder $menu) {
43 | });
44 |
45 | $expected = <<
48 |
49 |
50 |
51 | TEXT;
52 |
53 | self::assertEquals($expected, $this->menu->get('test'));
54 | }
55 |
56 | /** @test */
57 | public function it_render_is_an_alias_of_get()
58 | {
59 | $this->menu->make('test', function (MenuBuilder $menu) {
60 | });
61 |
62 | $expected = <<
65 |
66 |
67 |
68 | TEXT;
69 |
70 | self::assertEquals($expected, $this->menu->render('test'));
71 | }
72 |
73 | /** @test */
74 | public function it_can_get_the_instance_of_a_menu()
75 | {
76 | $this->menu->create('test', function (MenuBuilder $menu) {
77 | });
78 |
79 | $this->assertInstanceOf(MenuBuilder::class, $this->menu->instance('test'));
80 | }
81 |
82 | /** @test */
83 | public function it_can_modify_a_menu_instance()
84 | {
85 | $this->menu->create('test', function (MenuBuilder $menu) {
86 | });
87 |
88 | $this->menu->modify('test', function (MenuBuilder $builder) {
89 | $builder->url('hello', 'world');
90 | });
91 |
92 | $this->assertCount(1, $this->menu->instance('test'));
93 | }
94 |
95 | /** @test */
96 | public function it_gets_a_partial_for_dropdown_styles()
97 | {
98 | $this->menu->create('test', function (MenuBuilder $menu) {
99 | });
100 |
101 | $this->assertStringContainsString('.dropdown-submenu', $this->menu->style());
102 | }
103 |
104 | /** @test */
105 | public function it_can_get_all_menus()
106 | {
107 | $this->menu->create('main', function (MenuBuilder $menu) {
108 | });
109 | $this->menu->create('footer', function (MenuBuilder $menu) {
110 | });
111 |
112 | $this->assertCount(2, $this->menu->all());
113 | }
114 |
115 | /** @test */
116 | public function it_can_count_menus()
117 | {
118 | $this->menu->create('main', function (MenuBuilder $menu) {
119 | });
120 | $this->menu->create('footer', function (MenuBuilder $menu) {
121 | });
122 |
123 | $this->assertEquals(2, $this->menu->count());
124 | }
125 |
126 | /** @test */
127 | public function it_can_destroy_all_menus()
128 | {
129 | $this->menu->create('main', function (MenuBuilder $menu) {
130 | });
131 | $this->menu->create('footer', function (MenuBuilder $menu) {
132 | });
133 |
134 | $this->assertCount(2, $this->menu->all());
135 | $this->menu->destroy();
136 | $this->assertCount(0, $this->menu->all());
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | set('menu', [
32 | 'styles' => [
33 | 'bs3-navbar' => \Akaunting\Menu\Presenters\Bootstrap3\Navbar::class,
34 | 'bs3-navbar-right' => \Akaunting\Menu\Presenters\Bootstrap3\NavbarRight::class,
35 | 'bs3-nav-pills' => \Akaunting\Menu\Presenters\Bootstrap3\NavPills::class,
36 | 'bs3-nav-tab' => \Akaunting\Menu\Presenters\Bootstrap3\NavTab::class,
37 | 'bs3-sidebar' => \Akaunting\Menu\Presenters\Bootstrap3\Sidebar::class,
38 | 'bs3-navmenu' => \Akaunting\Menu\Presenters\Bootstrap3\Nav::class,
39 | ],
40 |
41 | 'ordering' => false,
42 | ]);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------