├── .gitignore
├── composer.json
├── license.md
├── phpunit.xml
├── readme.md
└── src
├── LaravelSessionStore.php
├── Livewire
├── FlashContainer.php
├── FlashMessage.php
└── FlashOverlay.php
├── LivewireFlash.php
├── LivewireFlashNotifier.php
├── LivewireFlashServiceProvider.php
├── Message.php
├── OverlayMessage.php
├── SessionStore.php
├── functions.php
├── publish
└── livewire-flash.php
└── views
└── livewire
├── flash-container.blade.php
├── flash-message.blade.php
└── flash-overlay.blade.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mattlibera/livewire-flash",
3 | "description": "Flash notifications using Livewire",
4 | "license": "MIT",
5 | "authors": [
6 | {
7 | "name": "Matt Libera",
8 | "email": "me@mattlibera.com"
9 | }
10 | ],
11 | "require": {
12 | "php": ">=7.3.0",
13 | "illuminate/support": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
14 | "livewire/livewire": "^1.2|^2.12.7|^3.5.2"
15 | },
16 | "require-dev": {
17 | "mockery/mockery": "dev-master",
18 | "phpunit/phpunit": "^6.1|^9.5.10|^10.5"
19 | },
20 | "autoload": {
21 | "psr-4": {
22 | "MattLibera\\LivewireFlash\\": "src/"
23 | },
24 | "files": [
25 | "src/functions.php"
26 | ]
27 | },
28 | "minimum-stability": "stable",
29 | "extra": {
30 | "laravel": {
31 | "providers": [
32 | "MattLibera\\LivewireFlash\\LivewireFlashServiceProvider"
33 | ],
34 | "aliases": {
35 | "LivewireFlash": "MattLibera\\LivewireFlash\\LivewireFlash"
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/license.md:
--------------------------------------------------------------------------------
1 | Copyright 2020 Matt Libera (original work Jeffrey Way)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | ./tests/
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Livewire Flash
2 |
3 | This package provides flash message capability using Laravel Livewire. It is based very literally on `laracasts/flash` but has been extended to add the ability to flash a message to a the flash container (a Livewire component) without reloading the page.
4 |
5 | This package also retains much (though not all) of the same capability for "normal" flash messages, which are displayed on refresh by the same Livewire component.
6 |
7 | ## Installation
8 |
9 | Install via composer:
10 |
11 | ```bash
12 | composer require mattlibera/livewire-flash
13 | ```
14 |
15 | ## Requirements
16 |
17 | * Laravel >=7.0
18 | * Livewire ^1.2, ^2.12.7, or ^3.5.2
19 |
20 | > For new applications, consider using the TALL preset for Laravel: [https://github.com/laravel-frontend-presets/tall], or this package also works well with Laravel Jetstream: [https://jetstream.laravel.com/]
21 |
22 | ## Recommended add-ons
23 |
24 | Out of the box, the default alert component uses:
25 |
26 | * TailwindCSS (any version; see below for installation instructions)
27 | * FontAwesome
28 |
29 | However, it's fairly trivial to implement your own views / styles instead, by publishing the config and overriding defaults. See below for more on that.
30 |
31 | ### Tailwind setup (4.0+)
32 |
33 | If using modern Tailwind CSS, you should add a couple of paths to your `app.css` as `@source` directives:
34 |
35 | ```css
36 | @source "../../vendor/mattlibera/livewire-flash/src/publish/livewire-flash.php";
37 | @source "../../vendor/mattlibera/livewire-flash/src/views/livewire/*.blade.php";
38 | ```
39 | Of course, if you publish the views/config, you'll reference your own copies instead.
40 |
41 | ### Tailwind setup (> 4.0)
42 |
43 | If you are using legacy Tailwind CSS, you should amend the `content` section of your `tailwind.config.js` to include the appropriate files from this package:
44 | ```js
45 | /** @type {import('tailwindcss').Config} */
46 | module.exports = {
47 | content: [
48 | "./resources/**/*.blade.php",
49 | "./resources/**/*.js",
50 | "./resources/**/*.vue",
51 | "./vendor/mattlibera/livewire-flash/src/publish/livewire-flash.php",
52 | "./vendor/mattlibera/livewire-flash/src/views/livewire/*.blade.php",
53 | ],
54 | theme: {
55 | extend: {},
56 | },
57 | plugins: [],
58 | }
59 | ```
60 | Of course, if you publish the views/config, you'll reference your own copies instead.
61 |
62 | ## Usage
63 |
64 | ### Normal flash messages (on reload)
65 |
66 | Call the `flash()` helper from your code somewhere, before you redirect.
67 |
68 | ```php
69 | public function store()
70 | {
71 | flash('Success!');
72 |
73 | return redirect()->back();
74 | }
75 | ```
76 |
77 | ### Livewire flash message (before reload)
78 |
79 | From your Livewire component, flash your message using the normal syntax, but then call the `livewire()` helper method as the last method in the chain. You must pass in `$this` as the argument, as this package utilizes the `emit` helper that exists on all Livewire components. Example:
80 |
81 | ```php
82 | public function livewireAction()
83 | {
84 | flash('Your request was successful!')->success()->livewire($this);
85 | }
86 | ```
87 |
88 | ### Message types
89 |
90 | Message types are defined in the `livewire-flash.php` config file, which can be published (see below) if desired. By default, there are four supported message types: `info` (default if nothing else is specified), `success`, `warning`, and `error`.
91 |
92 | To set a message's type, either:
93 |
94 | 1. Pass it as the second argument to `flash()` - example: `flash('Your action succeeded', 'success')`, or
95 | 2. Chain it as a method name fluently after `flash()` - example: `flash('Your action succeeded')->success()`
96 |
97 | Both of those will change the message's display (colors and icon) to the configured styles.
98 |
99 | ### Overlay Message
100 |
101 | Overlay message is defined in the `livewire-flash.php` config file, which can be published (see below) if desired.
102 |
103 | To set an overlay message, chain the method name `overlay()` after `flash()`. When using overlay leave the `flash()` parameter empty. Enter your message as the first parameter and title as second parameter for `overlay()`. This can be used with or without the `livewire($this)` suffix:
104 |
105 | ```
106 | // renders on next page load
107 | flash()->overlay('This is my message', 'The Title');
108 | return redirect('somewhere');
109 |
110 | // renders immediately via Livewire
111 | flash()->overlay('This is my message', 'The Title')->livewire($this);
112 | ```
113 |
114 | Note that the out-of-the-box overlay component does support HTML code for the body and title, using the Blade unescaped `{!! !!}` tags.
115 |
116 | ### Customization
117 |
118 | To change the styles used by each message type, OR to add your own types, first publish the config file:
119 |
120 | ```bash
121 | php artisan vendor:publish --provider="MattLibera\LivewireFlash\LivewireFlashServiceProvider"
122 | ```
123 |
124 | Then, in the `styles` key you can change whatever you want:
125 |
126 | ```php
127 | 'styles' => [
128 | 'info' => [
129 | 'bg-color' => 'bg-blue-100', // could change to bg-purple-100, or something.
130 | 'border-color' => 'border-blue-400',
131 | 'icon-color' => 'text-blue-400',
132 | 'text-color' => 'text-blue-800',
133 | 'icon' => 'fas fa-info-circle', // could change to another FontAwesome icon
134 | ],
135 | ```
136 |
137 | Or you can add your own:
138 |
139 | ```php
140 | 'notice' => [
141 | 'bg-color' => 'bg-orange-100',
142 | 'border-color' => 'border-orange-400',
143 | 'icon-color' => 'text-orange-400',
144 | 'text-color' => 'text-orange-800',
145 | 'icon' => 'fas fa-flag',
146 | ],
147 | ```
148 |
149 | Whatever the case, just ensure that you call the alert by its config key: `flash('An important message')->notice()`
150 |
151 | To customize overlay styles, see the `overlay` key of the config file.
152 |
153 | ## Templates
154 |
155 | Out of the box, the Livewire Flash Container component is registered for you. All you have to do is include it in your template:
156 |
157 | ```html
158 |
159 | ```
160 |
161 | There are also some sample alert components (styled using TailwindCSS) included with this package. However, if you do not wish to use those...
162 |
163 | ### Customization
164 |
165 | You can change the views that the Livewire components use for rendering, and the styles applied to each message type.
166 |
167 | > If you are not using TailwindCSS and/or FontAwesome, you should definitely do this to call your own alert component/partial to fit whatever your stack is using.
168 |
169 | First, publish the config file:
170 |
171 | ```bash
172 | php artisan vendor:publish --provider="MattLibera\LivewireFlash\LivewireFlashServiceProvider"
173 | ```
174 |
175 | Then, edit the `views` area:
176 |
177 | ```php
178 | 'views' => [
179 | 'container' => 'livewire-flash::livewire.flash-container',
180 | 'message' => 'partials.my-bootstrap-flash',
181 | ],
182 | ```
183 |
184 | You can access the public message properties on `MattLibera\LivewireFlash\Message`, as well as `$styles` (which is injected via the Livewire component) in your template.
185 |
186 | ## Dismissible Messages
187 |
188 | By default, each message will be set to be dismissible (that is, have an X icon at the right that will close the alert). If you wish to prevent this, you can chain `->notDismissable()` (or `->dismissable(false)`) to your flash directive.
189 |
190 | You can add your own magic via AlpineJS or whatever else if you want to fade messages out automatically - right now each message is a Livewire component and uses Livewire logic to hide it when it is dismissed.
191 |
192 | _Note that the overlay does not support this directive._
193 |
194 | ## Multiple Flash Messages
195 |
196 | Multiple flash messages can be sent to the session:
197 |
198 | ```php
199 | // anywhere
200 | flash('Message 1');
201 | flash('Message 2')->warning();
202 |
203 | return redirect('somewhere');
204 | ```
205 |
206 | OR
207 |
208 | ```php
209 | // livewire component
210 | flash('Message 1')->livewire($this);
211 | flash('Message 2')->warning()->livewire($this);
212 | ```
213 |
214 | However, at the moment, because of the way Livewire handles the session, you *cannot* mix-and-match... that is, you cannot do:
215 |
216 | ```php
217 | // livewire component
218 | flash('Message 1'); // this one will get lost.
219 | flash('Message 2')->livewire($this); // this one will show on current page via Livewire
220 |
221 | ```
222 |
223 | # Contributing
224 |
225 | I am open to contributions to this package, and will do the best I can to maintain it over time. Pull requests are welcome, and in fact encouraged. Right now there are no specific guidelines for a PR.
226 |
227 | # Road Map
228 |
229 | Some considerations for future versions:
230 |
231 | - Fluent options for setting an icon or colors on the fly
232 | - Auto-dismissing option for flash messages
233 |
234 | # Credits and License
235 |
236 | Credit for the original package goes to Jeffrey Way and Laracasts. Additional thanks:
237 |
238 | * Caleb Porzio and his Livewire contributors for the awesome framework
239 | * Adam Wathan and the Tailwind crew
240 | * Taylor Otwell and co. for Laravel
241 |
242 | This is an MIT-licensed package. Please read license.md for the details.
243 |
--------------------------------------------------------------------------------
/src/LaravelSessionStore.php:
--------------------------------------------------------------------------------
1 | session = $session;
22 | }
23 |
24 | /**
25 | * Flash a message to the session.
26 | *
27 | * @param string $name
28 | * @param array $data
29 | */
30 | public function flash($name, $data)
31 | {
32 | $this->session->flash($name, $data);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Livewire/FlashContainer.php:
--------------------------------------------------------------------------------
1 | messages = session('flash_notification', collect())->toArray();
17 | session()->forget('flash_notification');
18 | }
19 |
20 | public function render()
21 | {
22 | return view(config('livewire-flash.views.container'));
23 | }
24 |
25 | public function flashMessageAdded($message)
26 | {
27 | $this->messages[] = $message;
28 | }
29 |
30 | public function dismissMessage($key)
31 | {
32 | unset($this->messages[$key]);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Livewire/FlashMessage.php:
--------------------------------------------------------------------------------
1 | message = $message;
20 | $this->styles = config('livewire-flash.styles.' . $this->message['level']);
21 | }
22 |
23 | public function render()
24 | {
25 | return view(config('livewire-flash.views.message'));
26 | }
27 |
28 | public function dismiss()
29 | {
30 | $this->shown = false;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Livewire/FlashOverlay.php:
--------------------------------------------------------------------------------
1 | message = $message;
20 | $this->styles = config('livewire-flash.styles.overlay');
21 | }
22 |
23 | public function render()
24 | {
25 | return view(config('livewire-flash.views.overlay'));
26 | }
27 |
28 | public function dismiss()
29 | {
30 | $this->shown = false;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/LivewireFlash.php:
--------------------------------------------------------------------------------
1 | session = $session;
34 | $this->messages = collect();
35 | }
36 |
37 | /**
38 | * Flash a general message.
39 | *
40 | * @param string|null $message
41 | * @param string|null $level
42 | * @return $this
43 | */
44 | public function message($message = null, $level = null)
45 | {
46 | // If no message was provided, we should update
47 | // the most recently added message.
48 | if (! $message) {
49 | return $this->updateLastMessage(compact('level'));
50 | }
51 |
52 | if (! $message instanceof Message) {
53 | $message = new Message(compact('message', 'level'));
54 | }
55 |
56 | $this->messages->push($message);
57 |
58 | return $this->flash();
59 | }
60 |
61 | /**
62 | * Modify the most recently added message.
63 | *
64 | * @param array $overrides
65 | * @return $this
66 | */
67 | protected function updateLastMessage($overrides = [])
68 | {
69 | $this->messages->last()->update($overrides);
70 |
71 | return $this;
72 | }
73 |
74 | /**
75 | * Flash an overlay modal.
76 | *
77 | * @param string|null $message
78 | * @param string $title
79 | * @return $this
80 | */
81 | public function overlay($message = null, $title = null)
82 | {
83 | if (! $message) {
84 | return $this->updateLastMessage(['title' => $title, 'overlay' => true]);
85 | }
86 |
87 | return $this->message(
88 | new OverlayMessage(compact('title', 'message'))
89 | );
90 | }
91 |
92 | /**
93 | * Add an "important" flash to the session.
94 | *
95 | * @return $this
96 | */
97 | public function important()
98 | {
99 | return $this->updateLastMessage(['important' => true]);
100 | }
101 |
102 | /**
103 | * Set the dismissability of the last flash message.
104 | *
105 | * @param bool $dismissable
106 | *
107 | * @return $this
108 | */
109 | public function dismissable(bool $dismissable = true)
110 | {
111 | return $this->updateLastMessage(['dismissable' => $dismissable]);
112 | }
113 |
114 | /**
115 | * Convenience method to set dismissable = false on a message
116 | *
117 | * @return void
118 | */
119 | public function notDismissable()
120 | {
121 | return $this->dismissable(false);
122 | }
123 |
124 | /**
125 | * Clear all registered messages.
126 | *
127 | * @return $this
128 | */
129 | public function clear()
130 | {
131 | $this->messages = collect();
132 |
133 | return $this;
134 | }
135 |
136 | /**
137 | * Flash all messages to the session.
138 | */
139 | protected function flash()
140 | {
141 | $this->session->flash('flash_notification', $this->messages);
142 |
143 | return $this;
144 | }
145 |
146 | /**
147 | * Pop the last message off the stack and emit it to the Livewire component
148 | *
149 | * @param Livewire\Component $livewire
150 | * @return \MattLibera\LivewireFlash\LivewireFlashNotifier
151 | */
152 | public function livewire(Component $livewire)
153 | {
154 | if (method_exists($livewire, 'dispatch')) {
155 | $livewire->dispatch('flashMessageAdded', $this->messages->pop());
156 | } else {
157 | $livewire->emit('flashMessageAdded', $this->messages->pop());
158 | }
159 |
160 | return $this;
161 | }
162 |
163 |
164 | /**
165 | * Magic __call: pass the method name called as the message type if it is configured
166 | *
167 | * @param mixed $method
168 | * @param mixed $arguments
169 | * @return \MattLibera\LivewireFlash\LivewireFlashNotifier
170 | */
171 | public function __call($method, $arguments)
172 | {
173 | $messageTypes = config('livewire-flash.styles');
174 | if (isset($messageTypes[$method])) {
175 | return $this->message(null, $method);
176 | }
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/src/LivewireFlashServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->bind(
25 | 'MattLibera\LivewireFlash\SessionStore',
26 | 'MattLibera\LivewireFlash\LaravelSessionStore'
27 | );
28 |
29 | $this->app->singleton('lwflash', function () {
30 | return $this->app->make('MattLibera\LivewireFlash\LivewireFlashNotifier');
31 | });
32 | }
33 |
34 | /**
35 | * Bootstrap the application events.
36 | *
37 | * @return void
38 | */
39 | public function boot()
40 | {
41 | $this->mergeConfigFrom(__DIR__. '/publish/livewire-flash.php', 'livewire-flash');
42 |
43 | $this->loadViewsFrom(__DIR__ . '/views', 'livewire-flash');
44 |
45 | $this->publishes([
46 | __DIR__ . '/publish' => config_path()
47 | ]);
48 |
49 | Livewire::component('flash-container', \MattLibera\LivewireFlash\Livewire\FlashContainer::class);
50 | Livewire::component('flash-message', \MattLibera\LivewireFlash\Livewire\FlashMessage::class);
51 | Livewire::component('flash-overlay', \MattLibera\LivewireFlash\Livewire\FlashOverlay::class);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Message.php:
--------------------------------------------------------------------------------
1 | update($attributes);
57 | }
58 |
59 | /**
60 | * Update the attributes.
61 | *
62 | * @param array $attributes
63 | * @return $this
64 | */
65 | public function update($attributes = [])
66 | {
67 | foreach ($attributes as $key => $attribute) {
68 | $this->$key = $attribute;
69 | }
70 | return $this;
71 | }
72 |
73 |
74 | /**
75 | * Whether the given offset exists.
76 | *
77 | * @param mixed $offset
78 | * @return bool
79 | */
80 | public function offsetExists($offset)
81 | {
82 | return isset($this->$offset);
83 | }
84 |
85 | /**
86 | * Fetch the offset.
87 | *
88 | * @param mixed $offset
89 | * @return mixed
90 | */
91 | public function offsetGet($offset)
92 | {
93 | return $this->$offset;
94 | }
95 |
96 | /**
97 | * Assign the offset.
98 | *
99 | * @param mixed $offset
100 | * @return void
101 | */
102 | public function offsetSet($offset, $value)
103 | {
104 | $this->$offset = $value;
105 | }
106 |
107 | /**
108 | * Unset the offset.
109 | *
110 | * @param mixed $offset
111 | * @return void
112 | */
113 | public function offsetUnset($offset)
114 | {
115 | //
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/OverlayMessage.php:
--------------------------------------------------------------------------------
1 | message($message, $level);
19 | }
20 |
21 | return $notifier;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/publish/livewire-flash.php:
--------------------------------------------------------------------------------
1 | [
5 | 'container' => 'livewire-flash::livewire.flash-container',
6 | 'message' => 'livewire-flash::livewire.flash-message',
7 | 'overlay' => 'livewire-flash::livewire.flash-overlay',
8 | ],
9 | 'styles' => [
10 | 'info' => [
11 | 'bg-color' => 'bg-blue-100',
12 | 'border-color' => 'border-blue-400',
13 | 'icon-color' => 'text-blue-400',
14 | 'text-color' => 'text-blue-800',
15 | 'icon' => 'fas fa-info-circle',
16 | ],
17 | 'success' => [
18 | 'bg-color' => 'bg-green-100',
19 | 'border-color' => 'border-green-400',
20 | 'icon-color' => 'text-green-400',
21 | 'text-color' => 'text-green-800',
22 | 'icon' => 'fas fa-check',
23 | ],
24 | 'warning' => [
25 | 'bg-color' => 'bg-yellow-100',
26 | 'border-color' => 'border-yellow-400',
27 | 'icon-color' => 'text-yellow-400',
28 | 'text-color' => 'text-yellow-800',
29 | 'icon' => 'fas fa-exclamation-circle',
30 | ],
31 | 'error' => [
32 | 'bg-color' => 'bg-red-100',
33 | 'border-color' => 'border-red-400',
34 | 'icon-color' => 'text-red-400',
35 | 'text-color' => 'text-red-800',
36 | 'icon' => 'fas fa-exclamation-triangle',
37 | ],
38 | 'overlay' => [
39 | 'overly-bg-color' => 'bg-gray-500',
40 | 'overlay-bg-opacity' => 'opacity-75',
41 |
42 | 'title-text-color' => 'text-gray-900',
43 |
44 | 'body-text-color' => 'text-gray-500',
45 |
46 | 'button-border-color' => 'border-transparent',
47 | 'button-bg-color' => 'bg-indigo-600',
48 | 'button-text-color' => 'text-white',
49 |
50 | 'button-hover-bg-color' => 'hover:bg-indigo-700',
51 | 'button-hover-text-color' => 'hover:text-white',
52 | 'button-focus-ring-color' => 'focus:ring-indigo-500',
53 |
54 | 'button-extra-classes' => '',
55 |
56 | 'button-text' => 'Close',
57 | ],
58 | ],
59 | ];
60 |
--------------------------------------------------------------------------------
/src/views/livewire/flash-container.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @foreach ($messages as $index => $message)
3 | @if ($message['overlay'])
4 |
5 | @else
6 |
7 | @endif
8 | @endforeach
9 |
10 |
--------------------------------------------------------------------------------
/src/views/livewire/flash-message.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @if($shown)
3 |
4 |
5 | @if ($styles['icon'] ?? false)
6 |
11 | @endif
12 |
13 | {!! $message['message'] !!}
14 |
15 | @if ($message['dismissable'] ?? false)
16 |
17 |
18 |
21 |
22 |
23 | @endif
24 |
25 |
26 | @endif
27 |
28 |
--------------------------------------------------------------------------------
/src/views/livewire/flash-overlay.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @if($shown)
3 |
4 |
5 |
15 |
18 |
19 |
20 |
21 |
31 |
32 |
33 |
38 |
39 |
40 |
41 | @if($message['title'])
42 |
43 | {!! $message['title'] !!}
44 |
45 | @endif
46 |
47 |
48 | {!! $message['message'] !!}
49 |
50 |
51 |
52 |
53 |
54 |
57 |
58 |
59 |
60 |
61 | @endif
62 |
63 |
--------------------------------------------------------------------------------