diff --git a/composer.json b/composer.json index 24f46728..dd719028 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,15 @@ ], "require": { "php": ">=5.3", - "ext-json": "*" + "ext-json": "*", + "symfony/config": "^2.7|^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^2.7|^3.0|^4.0|^5.0", + "symfony/http-kernel": "^2.7|^3.0|^4.0|^5.0", + "symfony/yaml": "^2.7|^3.0|^4.0|^5.0", + "twig/twig": "^1.34|^2.0|^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.0|^6.0|^7.0|^8.0|^9.0" }, "autoload": { "psr-4": { diff --git a/src/Laravel/FlasherServiceProvider.php b/src/Laravel/FlasherServiceProvider.php index df1d0b98..8c0cd051 100644 --- a/src/Laravel/FlasherServiceProvider.php +++ b/src/Laravel/FlasherServiceProvider.php @@ -68,4 +68,12 @@ final class FlasherServiceProvider extends ServiceProvider { parent::loadTranslationsFrom($path, $namespace); } + + /** + * {@inheritdoc} + */ + public function loadViewsFrom($path, $namespace) + { + parent::loadViewsFrom($path, $namespace); + } } diff --git a/src/Laravel/Observer/FlasherModelObserver.php b/src/Laravel/Observer/FlasherModelObserver.php index 42340e83..589a885b 100644 --- a/src/Laravel/Observer/FlasherModelObserver.php +++ b/src/Laravel/Observer/FlasherModelObserver.php @@ -4,34 +4,43 @@ namespace Flasher\Laravel\Observer; use Flasher\Prime\Config\ConfigInterface; use Flasher\Prime\FlasherInterface; +use Illuminate\Contracts\Translation\Translator; use Illuminate\Database\Eloquent\Model; final class FlasherModelObserver { - /** - * @var FlasherInterface - */ - private $flasher; - /** * @var ConfigInterface */ private $config; /** - * @param FlasherInterface $flasher - * @param ConfigInterface $config + * @var FlasherInterface */ - public function __construct(FlasherInterface $flasher, ConfigInterface $config) + private $flasher; + + /** + * @var Translator + */ + private $translator; + + /** + * @param ConfigInterface $config + * @param FlasherInterface $flasher + * @param Translator $translator + */ + public function __construct(ConfigInterface $config, FlasherInterface $flasher, Translator $translator) { - $this->flasher = $flasher; $this->config = $config; + $this->flasher = $flasher; + $this->translator = $translator; } /** * Handle the Model "created" event. * - * @param Model $model + * @param Model $model + * * @return void */ public function created(Model $model) @@ -42,7 +51,8 @@ final class FlasherModelObserver /** * Handle the Model "updated" event. * - * @param Model $model + * @param Model $model + * * @return void */ public function updated(Model $model) @@ -53,7 +63,8 @@ final class FlasherModelObserver /** * Handle the Model "deleted" event. * - * @param Model $model + * @param Model $model + * * @return void */ public function deleted(Model $model) @@ -64,7 +75,8 @@ final class FlasherModelObserver /** * Handle the Model "restored" event. * - * @param Model $model + * @param Model $model + * * @return void */ public function restored(Model $model) @@ -75,7 +87,8 @@ final class FlasherModelObserver /** * Handle the Model "force deleted" event. * - * @param Model $model + * @param Model $model + * * @return void */ public function forceDeleted(Model $model) @@ -87,12 +100,21 @@ final class FlasherModelObserver * @param string $method * @param Model $model */ - private function addFlash(string $method, Model $model) + private function addFlash($method, Model $model) { - $message = $this->config->get(sprintf('flashable.%s.%s', get_class($model), $method)); + $exludes = $this->config->get('observer_events.exclude', array()); + if (in_array($method, $exludes)) { + return; + } - if(null === $message) { - $message = $this->config->get(sprintf('flashable.default.%s', $method)); + if (isset($exludes[$method]) && in_array(get_class($model), $exludes[$method])) { + return; + } + + if ($this->translator->has(sprintf('flasher::messages.flashable.%s.%s', get_class($model), $method))) { + $message = $this->translator->get(sprintf('flasher::messages.flashable.%s.%s', get_class($model), $method)); + } else { + $message = $this->translator->get(sprintf('flasher::messages.flashable.default.%s', $method)); $message = str_replace('{{ model }}', substr(strrchr(get_class($model), "\\"), 1), $message); } diff --git a/src/Laravel/Resources/config/config.php b/src/Laravel/Resources/config/config.php index 2999fcaa..47c70476 100644 --- a/src/Laravel/Resources/config/config.php +++ b/src/Laravel/Resources/config/config.php @@ -1,10 +1,10 @@ 'toastr', + 'default' => 'template', 'scripts' => array( - '/vendor/php-flasher/flasher/assets/js/flasher.js' + '/vendor/flasher/flasher.js', ), 'auto_create_from_session' => true, @@ -15,4 +15,30 @@ return array( 'warning' => array('warning', 'alarm'), 'info' => array('info', 'notice', 'alert'), ), + + 'observer_events' => array( + 'exclude' => array( + 'forceDeleted', + 'restored', + ), + ), + + 'adapters' => array( + 'template' => array( + 'default' => 'tailwindcss', + 'views' => array( + 'tailwindcss' => 'flasher::tailwindcss', + ), + 'scripts' => array( + '/vendor/flasher/flasher-template.js', + ), + 'styles' => array( + 'https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css', + ), + 'options' => array( + 'timeout' => 5000, + 'position' => 'top-right', + ), + ), + ), ); diff --git a/src/Laravel/Resources/public/flasher-template.js b/src/Laravel/Resources/public/flasher-template.js new file mode 100644 index 00000000..2a85cdd3 --- /dev/null +++ b/src/Laravel/Resources/public/flasher-template.js @@ -0,0 +1,137 @@ +PHPFlasher.addFactory('template', (function () { + 'use strict'; + + var exports = {}; + var options = { + timeout: 5000, + fps: 30, + position: 'top-right', + direction: 'top' + }; + + exports.render = function (envelope) { + var position = options.position; + + if (undefined !== envelope.options && undefined !== envelope.options.position) { + position = envelope.options.position; + } + + var container = document.getElementById('flasher-container-' + position); + if (null === container) { + container = document.createElement('div'); + container.id = "flasher-container-" + options.position; + container.style.position = "fixed"; + container.style.maxWidth = "304px"; + container.style.width = "100%"; + + switch (options.position) { + case "top-left": + container.style.top = 0; + container.style.left = "0.5em"; + break; + case "top-right": + container.style.top = 0; + container.style.right = "0.5em"; + break; + case "bottom-left": + container.style.bottom = 0; + container.style.left = "0.5em"; + break; + case "bottom-right": + default: + container.style.bottom = 0; + container.style.right = "0.5em"; + break; + } + document.getElementsByTagName('body')[0].appendChild(container); + } + + var template = stringToHTML(envelope.template); + template.style.transition = '0.8s'; + + switch (options.direction) { + case "top": + container.insertBefore(template, container.firstChild); + break; + case "bottom": + default: + container.appendChild(template); + break; + } + + var progressBar = template.querySelector('.flasher-progress'); + + var width = 0; + var lapse = 1000 / options.fps; + + var showProgress = function () { + width++; + var percent = (1 - lapse * width / options.timeout) * 100; + progressBar.style.width = percent + '%'; + + if (percent <= 0) { + template.style.opacity = 0; + clearInterval(progress); + + setTimeout(function () { + template.remove(); + }, 900); + } + } + + var progress = setInterval(showProgress, lapse); + + template.addEventListener('mouseover', function () { + clearInterval(progress); + }); + + template.addEventListener("mouseout", function () { + progress = setInterval(showProgress, lapse); + }); + }; + + exports.renderOptions = function (_setting) { + options = extend({}, options, _setting); + }; + + var stringToHTML = function (str) { + var support = (function () { + if (!window.DOMParser) return false; + var parser = new DOMParser(); + try { + parser.parseFromString('x', 'text/html'); + } catch (err) { + return false; + } + return true; + })(); + + if (support) { + var parser = new DOMParser(); + var doc = parser.parseFromString(str, 'text/html'); + return doc.body.firstChild; + } + + var dom = document.createElement('div'); + dom.innerHTML = str; + return dom.firstElementChild; + }; + + var extend = function (out) { + out = out || {}; + + for (var i = 1; i < arguments.length; i++) { + if (!arguments[i]) + continue; + + for (var key in arguments[i]) { + if (arguments[i].hasOwnProperty(key)) + out[key] = arguments[i][key]; + } + } + + return out; + }; + + return exports; +})()); diff --git a/src/Laravel/Resources/public/flasher.js b/src/Laravel/Resources/public/flasher.js index 4581795c..259c9661 100644 --- a/src/Laravel/Resources/public/flasher.js +++ b/src/Laravel/Resources/public/flasher.js @@ -8,7 +8,7 @@ var PHPFlasher = (function () { exports.addStyles(_options.styles, function () { exports.addScripts(_options.scripts, function () { exports.renderOptions(_options.options); - exports.renderNotifications(_options.notifications); + exports.renderEnvelopes(_options.envelopes); }); }); }; @@ -76,9 +76,9 @@ var PHPFlasher = (function () { }); }; - exports.renderNotifications = function (notifications) { - notifications.forEach(function (flash) { - factories[flash.handler].render(flash.notification); + exports.renderEnvelopes = function (envelopes) { + envelopes.forEach(function (envelope) { + factories[envelope.handler].render(envelope); }) }; diff --git a/src/Laravel/Resources/views/tailwindcss.blade.php b/src/Laravel/Resources/views/tailwindcss.blade.php new file mode 100644 index 00000000..a3c7681a --- /dev/null +++ b/src/Laravel/Resources/views/tailwindcss.blade.php @@ -0,0 +1,51 @@ +getType()) { + case 'success': + $textColor = 'text-green-600'; + $backgroundColor = 'bg-green-600'; + $progressBackgroundColor = 'bg-green-100'; + $borderColor = 'border-green-600'; + $icon = ''; + break; + case 'error': + $textColor = 'text-red-600'; + $backgroundColor = 'bg-red-600'; + $progressBackgroundColor = 'bg-red-100'; + $borderColor = 'border-red-600'; + $icon = ''; + break; + case 'warning': + $textColor = 'text-yellow-600'; + $backgroundColor = 'bg-yellow-600'; + $progressBackgroundColor = 'bg-yellow-100'; + $borderColor = 'border-yellow-600'; + $icon = ''; + break; + case 'info': + default: + $textColor = 'text-blue-600'; + $backgroundColor = 'bg-blue-600'; + $progressBackgroundColor = 'bg-blue-100'; + $borderColor = 'border-blue-600'; + $icon = ''; + break; + } +?> +
+
+
+ {!! $icon !!} +
+
+

+ {{ $envelope->getType() }} +

+

+ {{ $envelope->getMessage() }} +

+
+
+
+ +
+
diff --git a/src/Laravel/ServiceProvider/Providers/Laravel.php b/src/Laravel/ServiceProvider/Providers/Laravel.php index 5af3916a..7cb104c3 100644 --- a/src/Laravel/ServiceProvider/Providers/Laravel.php +++ b/src/Laravel/ServiceProvider/Providers/Laravel.php @@ -5,14 +5,18 @@ namespace Flasher\Laravel\ServiceProvider\Providers; use Flasher\Laravel\Config\Config; use Flasher\Laravel\FlasherServiceProvider; use Flasher\Laravel\Storage\Storage; +use Flasher\Laravel\Template\BladeEngine; use Flasher\Prime\EventDispatcher\EventDispatcher; use Flasher\Prime\EventDispatcher\EventListener\StampsListener; use Flasher\Prime\EventDispatcher\EventListener\FilterListener; use Flasher\Prime\EventDispatcher\EventListener\RemoveListener; +use Flasher\Prime\EventDispatcher\EventListener\TemplateListener; +use Flasher\Prime\Factory\NotificationFactory; use Flasher\Prime\Filter\Filter; use Flasher\Prime\Flasher; use Flasher\Prime\Renderer\Renderer; use Flasher\Prime\Storage\StorageManager; +use Flasher\Toastr\Prime\ToastrFactory; use Illuminate\Container\Container; use Illuminate\Foundation\Application; use Illuminate\Support\Facades\Blade; @@ -31,24 +35,16 @@ class Laravel implements ServiceProviderInterface return $this->app instanceof Application; } - public function publishConfig(FlasherServiceProvider $provider) - { - $source = realpath($raw = flasher_path(__DIR__.'/../../Resources/config/config.php')) ?: $raw; - - $provider->publishes(array($source => config_path('flasher.php')), 'config'); - - $provider->mergeConfigFrom($source, 'flasher'); - } - - public function publishAssets(FlasherServiceProvider $provider) - { - $provider->publishes(array(flasher_path(__DIR__.'/../../Resources/public') => public_path(flasher_path('vendor/php-flasher/flasher/assets/js'))), 'public'); - } - - public function publishTranslations(FlasherServiceProvider $provider) + public function publishes(FlasherServiceProvider $provider) { + $provider->mergeConfigFrom(flasher_path(__DIR__.'/../../Resources/config/config.php'), 'flasher'); $provider->loadTranslationsFrom(flasher_path(__DIR__.'/../../Resources/lang'), 'flasher'); - $provider->publishes(array(flasher_path(__DIR__.'/../../Resources/lang') => resource_path(flasher_path('lang/vendor/flasher')))); + $provider->loadViewsFrom(flasher_path(__DIR__.'/../../Resources/views'), 'flasher'); + + $provider->publishes(array(flasher_path(__DIR__.'/../../Resources/config/config.php') => config_path('flasher.php')), 'flasher-config'); + $provider->publishes(array(flasher_path(__DIR__.'/../../Resources/public') => public_path(flasher_path('vendor/flasher'))), 'flasher-public'); + $provider->publishes(array(flasher_path(__DIR__.'/../../Resources/lang') => resource_path(flasher_path('lang/vendor/flasher'))), 'flasher-lang'); + $provider->publishes(array(flasher_path(__DIR__.'/../../Resources/views') => resource_path(flasher_path('views/vendor/flasher'))), 'flasher-views'); } public function registerServices() @@ -63,7 +59,10 @@ class Laravel implements ServiceProviderInterface public function registerCommonServices() { $this->app->singleton('flasher', function (Application $app) { - return new Flasher($app['flasher.config']); + $flasher = new Flasher($app['flasher.config']); + $flasher->addFactory('template', $app['flasher.template']); + + return $flasher; }); $this->app->singleton('flasher.renderer', function (Application $app) { @@ -82,16 +81,25 @@ class Laravel implements ServiceProviderInterface return new Filter(); }); + $this->app->singleton('flasher.template_engine', function (Application $app) { + return new BladeEngine($app['view']); + }); + $this->app->singleton('flasher.event_dispatcher', function (Application $app) { $eventDispatcher = new EventDispatcher(); $eventDispatcher->addSubscriber(new FilterListener($app['flasher.filter'])); $eventDispatcher->addSubscriber(new RemoveListener()); $eventDispatcher->addSubscriber(new StampsListener()); + $eventDispatcher->addSubscriber(new TemplateListener($app['flasher.config'], $app['flasher.template_engine'])); return $eventDispatcher; }); + $this->app->singleton('flasher.notification_factory', function (Application $app) { + return new NotificationFactory($app['flasher.storage_manager']); + }); + $this->app->alias('flasher.config', 'Flasher\Laravel\Config\Config'); $this->app->alias('flasher', 'Flasher\Prime\Flasher'); $this->app->alias('flasher.renderer', 'Flasher\Prime\Renderer\Renderer'); @@ -99,6 +107,9 @@ class Laravel implements ServiceProviderInterface $this->app->alias('flasher.storage', 'Flasher\Laravel\Storage\Storage'); $this->app->alias('flasher.storage_manager', 'Flasher\Laravel\Storage\StorageManager'); $this->app->alias('flasher.filter', 'Flasher\Prime\Filter\Filter'); + $this->app->alias('flasher.template_engine', 'Flasher\Laravel\Template\BladeEngine'); + $this->app->alias('flasher.notification_factory', 'Flasher\Prime\Factory\NotificationFactory'); + $this->app->alias('Flasher\Prime\Factory\NotificationFactory', 'flasher.template'); $this->app->bind('Flasher\Prime\Config\ConfigInterface', 'flasher.config'); @@ -108,6 +119,8 @@ class Laravel implements ServiceProviderInterface $this->app->bind('Flasher\Prime\Filter\FilterInterface', 'flasher.filter'); $this->app->bind('Flasher\Prime\EventDispatcher\EventDispatcherInterface', 'flasher.event_dispatcher'); $this->app->bind('Flasher\Prime\Storage\StorageInterface', 'flasher.storage'); + $this->app->bind('Flasher\Prime\Template\EngineInterface', 'flasher.template_engine'); + $this->app->bind('Flasher\Prime\Factory\NotificationFactoryInterface', 'flasher.notification_factory'); } public function registerBladeDirectives() @@ -129,7 +142,7 @@ class Laravel implements ServiceProviderInterface $criteria = "array()"; } - return "render($criteria, 'html'); ?>"; + return "render($criteria, array('format' => 'html')); ?>"; }); } } diff --git a/src/Laravel/ServiceProvider/Providers/Laravel4.php b/src/Laravel/ServiceProvider/Providers/Laravel4.php index b1d9a99e..1cf6983e 100644 --- a/src/Laravel/ServiceProvider/Providers/Laravel4.php +++ b/src/Laravel/ServiceProvider/Providers/Laravel4.php @@ -15,19 +15,11 @@ final class Laravel4 extends Laravel return $this->app instanceof Application && 0 === strpos(Application::VERSION, '4.'); } - public function publishConfig(FlasherServiceProvider $provider) + public function publishes(FlasherServiceProvider $provider) { $provider->package('php-flasher/flasher-laravel', 'flasher', flasher_path(__DIR__.'/../../Resources')); } - public function publishAssets(FlasherServiceProvider $provider) - { - } - - public function publishTranslations(FlasherServiceProvider $provider) - { - } - public function registerServices() { $this->app->singleton('flasher.config', function (Application $app) { diff --git a/src/Laravel/ServiceProvider/Providers/Laravel50.php b/src/Laravel/ServiceProvider/Providers/Laravel50.php index ca7de456..538711c2 100644 --- a/src/Laravel/ServiceProvider/Providers/Laravel50.php +++ b/src/Laravel/ServiceProvider/Providers/Laravel50.php @@ -14,7 +14,7 @@ final class Laravel50 extends Laravel return $this->app instanceof Application && 0 === strpos(Application::VERSION, '5.0'); } - public function publishTranslations(FlasherServiceProvider $provider) + public function publishes(FlasherServiceProvider $provider) { $provider->loadTranslationsFrom(flasher_path(__DIR__.'/../../Resources/lang'), 'flasher'); $provider->publishes(array(flasher_path(__DIR__.'/../../Resources/lang') => base_path(flasher_path('resources/lang/vendor/flasher')))); diff --git a/src/Laravel/ServiceProvider/Providers/Laravel51.php b/src/Laravel/ServiceProvider/Providers/Laravel51.php index 712f3b58..f4cc9c88 100644 --- a/src/Laravel/ServiceProvider/Providers/Laravel51.php +++ b/src/Laravel/ServiceProvider/Providers/Laravel51.php @@ -12,7 +12,7 @@ final class Laravel51 extends Laravel return $this->app instanceof Application && 0 === strpos(Application::VERSION, '5.1'); } - public function publishTranslations(FlasherServiceProvider $provider) + public function publishes(FlasherServiceProvider $provider) { $provider->loadTranslationsFrom(flasher_path(__DIR__.'/../../Resources/lang'), 'flasher'); $provider->publishes(array(flasher_path(__DIR__.'/../../Resources/lang') => base_path(flasher_path('resources/lang/vendor/flasher')))); diff --git a/src/Laravel/ServiceProvider/Providers/Lumen.php b/src/Laravel/ServiceProvider/Providers/Lumen.php index 5ab828bd..6e15c8f1 100644 --- a/src/Laravel/ServiceProvider/Providers/Lumen.php +++ b/src/Laravel/ServiceProvider/Providers/Lumen.php @@ -12,7 +12,7 @@ final class Lumen extends Laravel return $this->app instanceof Application; } - public function publishConfig(FlasherServiceProvider $provider) + public function publishes(FlasherServiceProvider $provider) { $source = realpath($raw = flasher_path(__DIR__.'/../../../Resources/config/config.php')) ?: $raw; diff --git a/src/Laravel/ServiceProvider/Providers/ServiceProviderInterface.php b/src/Laravel/ServiceProvider/Providers/ServiceProviderInterface.php index 0a4302c1..f6213d72 100644 --- a/src/Laravel/ServiceProvider/Providers/ServiceProviderInterface.php +++ b/src/Laravel/ServiceProvider/Providers/ServiceProviderInterface.php @@ -8,11 +8,7 @@ interface ServiceProviderInterface { public function shouldBeUsed(); - public function publishConfig(FlasherServiceProvider $provider); - - public function publishAssets(FlasherServiceProvider $provider); - - public function publishTranslations(FlasherServiceProvider $provider); + public function publishes(FlasherServiceProvider $provider); public function registerServices(); diff --git a/src/Laravel/ServiceProvider/ServiceProviderManager.php b/src/Laravel/ServiceProvider/ServiceProviderManager.php index 506b30aa..199f0614 100644 --- a/src/Laravel/ServiceProvider/ServiceProviderManager.php +++ b/src/Laravel/ServiceProvider/ServiceProviderManager.php @@ -31,9 +31,7 @@ final class ServiceProviderManager { $provider = $this->resolveServiceProvider(); - $provider->publishConfig($this->notifyServiceProvider); - $provider->publishAssets($this->notifyServiceProvider); - $provider->publishTranslations($this->notifyServiceProvider); + $provider->publishes($this->notifyServiceProvider); $provider->registerBladeDirectives(); } diff --git a/src/Laravel/Template/BladeEngine.php b/src/Laravel/Template/BladeEngine.php new file mode 100644 index 00000000..8c4ec61d --- /dev/null +++ b/src/Laravel/Template/BladeEngine.php @@ -0,0 +1,29 @@ +engine = $engine; + } + + /** + * @inheritDoc + */ + public function render($name, array $context = array()) + { + return (string) $this->engine->make($name, $context); + } +} diff --git a/src/Noty/Laravel/Resources/public/flasher-noty.js b/src/Noty/Laravel/Resources/public/flasher-noty.js index f654f7d9..d6b20820 100644 --- a/src/Noty/Laravel/Resources/public/flasher-noty.js +++ b/src/Noty/Laravel/Resources/public/flasher-noty.js @@ -4,10 +4,11 @@ PHPFlasher.addFactory('noty', (function () { var exports = {}; exports.render = function (data) { + var notification = data.notification; var options = { - text: data.message, - type: data.type, - ...data.options + text: notification.message, + type: notification.type, + ...notification.options } new Noty(options).show(); diff --git a/src/Noty/Prime/NotyFactory.php b/src/Noty/Prime/NotyFactory.php index 60f9a337..7c931ebf 100644 --- a/src/Noty/Prime/NotyFactory.php +++ b/src/Noty/Prime/NotyFactory.php @@ -2,12 +2,12 @@ namespace Flasher\Noty\Prime; -use Flasher\Prime\Factory\AbstractFactory; +use Flasher\Prime\Factory\NotificationFactory; /** * @mixin NotyBuilder */ -final class NotyFactory extends AbstractFactory +final class NotyFactory extends NotificationFactory { /** * @inheritDoc diff --git a/src/Noty/Symfony/Resources/config/config.yaml b/src/Noty/Symfony/Resources/config/config.yaml index 094e84b9..ebbebcae 100644 --- a/src/Noty/Symfony/Resources/config/config.yaml +++ b/src/Noty/Symfony/Resources/config/config.yaml @@ -1,6 +1,6 @@ services: flasher.noty: - parent: 'flasher.abstract_factory' + parent: 'flasher.notification_factory' class: Flasher\Noty\Prime\NotyFactory tags: - { name: 'flasher.factory', alias: 'noty' } diff --git a/src/Noty/Symfony/Resources/public/flasher-noty.js b/src/Noty/Symfony/Resources/public/flasher-noty.js index f654f7d9..d6b20820 100644 --- a/src/Noty/Symfony/Resources/public/flasher-noty.js +++ b/src/Noty/Symfony/Resources/public/flasher-noty.js @@ -4,10 +4,11 @@ PHPFlasher.addFactory('noty', (function () { var exports = {}; exports.render = function (data) { + var notification = data.notification; var options = { - text: data.message, - type: data.type, - ...data.options + text: notification.message, + type: notification.type, + ...notification.options } new Noty(options).show(); diff --git a/src/Notyf/Laravel/Resources/public/flasher-notyf.js b/src/Notyf/Laravel/Resources/public/flasher-notyf.js index dd6fe205..5876c77f 100644 --- a/src/Notyf/Laravel/Resources/public/flasher-notyf.js +++ b/src/Notyf/Laravel/Resources/public/flasher-notyf.js @@ -4,7 +4,7 @@ PHPFlasher.addFactory('notyf', (function () { var exports = {}; exports.render = function (data) { - window.notyf.open(data); + window.notyf.open(data.notification); }; exports.renderOptions = function (options) { diff --git a/src/Notyf/Prime/NotyfFactory.php b/src/Notyf/Prime/NotyfFactory.php index 9e1a3860..e5499c3f 100644 --- a/src/Notyf/Prime/NotyfFactory.php +++ b/src/Notyf/Prime/NotyfFactory.php @@ -2,12 +2,12 @@ namespace Flasher\Notyf\Prime; -use Flasher\Prime\Factory\AbstractFactory; +use Flasher\Prime\Factory\NotificationFactory; /** * @mixin NotyfBuilder */ -final class NotyfFactory extends AbstractFactory +final class NotyfFactory extends NotificationFactory { /** * @inheritDoc diff --git a/src/Notyf/Symfony/Resources/config/config.yaml b/src/Notyf/Symfony/Resources/config/config.yaml index f4950e70..58b63c31 100644 --- a/src/Notyf/Symfony/Resources/config/config.yaml +++ b/src/Notyf/Symfony/Resources/config/config.yaml @@ -1,6 +1,6 @@ services: flasher.notyf: - parent: 'flasher.abstract_factory' + parent: 'flasher.notification_factory' class: Flasher\Notyf\Prime\NotyfFactory tags: - { name: 'flasher.factory', alias: 'notyf' } diff --git a/src/Notyf/Symfony/Resources/public/flasher-notyf.js b/src/Notyf/Symfony/Resources/public/flasher-notyf.js index dd6fe205..5876c77f 100644 --- a/src/Notyf/Symfony/Resources/public/flasher-notyf.js +++ b/src/Notyf/Symfony/Resources/public/flasher-notyf.js @@ -4,7 +4,7 @@ PHPFlasher.addFactory('notyf', (function () { var exports = {}; exports.render = function (data) { - window.notyf.open(data); + window.notyf.open(data.notification); }; exports.renderOptions = function (options) { diff --git a/src/Pnotify/Laravel/Resources/public/flasher-pnotify.js b/src/Pnotify/Laravel/Resources/public/flasher-pnotify.js index 1a8ca8d0..a03d66a4 100644 --- a/src/Pnotify/Laravel/Resources/public/flasher-pnotify.js +++ b/src/Pnotify/Laravel/Resources/public/flasher-pnotify.js @@ -4,10 +4,11 @@ PHPFlasher.addFactory('pnotify', (function () { var exports = {}; exports.render = function (data) { + var notification = data.notification; var options = { - text: data.message, - type: data.type, - ...data.options + text: notification.message, + type: notification.type, + ...notification.options } new PNotify(options); diff --git a/src/Pnotify/Prime/PnotifyFactory.php b/src/Pnotify/Prime/PnotifyFactory.php index 3a8fb34a..70c50dba 100644 --- a/src/Pnotify/Prime/PnotifyFactory.php +++ b/src/Pnotify/Prime/PnotifyFactory.php @@ -2,12 +2,12 @@ namespace Flasher\Pnotify\Prime; -use Flasher\Prime\Factory\AbstractFactory; +use Flasher\Prime\Factory\NotificationFactory; /** * @mixin PnotifyBuilder */ -final class PnotifyFactory extends AbstractFactory +final class PnotifyFactory extends NotificationFactory { /** * @inheritDoc diff --git a/src/Pnotify/Symfony/Resources/config/config.yaml b/src/Pnotify/Symfony/Resources/config/config.yaml index b5323526..f0db663f 100644 --- a/src/Pnotify/Symfony/Resources/config/config.yaml +++ b/src/Pnotify/Symfony/Resources/config/config.yaml @@ -1,6 +1,6 @@ services: flasher.pnotify: - parent: 'flasher.abstract_factory' + parent: 'flasher.notification_factory' class: Flasher\Pnotify\Prime\PnotifyFactory tags: - { name: 'flasher.factory', alias: 'pnotify' } diff --git a/src/Pnotify/Symfony/Resources/public/flasher-pnotify.js b/src/Pnotify/Symfony/Resources/public/flasher-pnotify.js index 1a8ca8d0..a03d66a4 100644 --- a/src/Pnotify/Symfony/Resources/public/flasher-pnotify.js +++ b/src/Pnotify/Symfony/Resources/public/flasher-pnotify.js @@ -4,10 +4,11 @@ PHPFlasher.addFactory('pnotify', (function () { var exports = {}; exports.render = function (data) { + var notification = data.notification; var options = { - text: data.message, - type: data.type, - ...data.options + text: notification.message, + type: notification.type, + ...notification.options } new PNotify(options); diff --git a/src/Prime/Envelope.php b/src/Prime/Envelope.php index f0be3dbf..4367959e 100644 --- a/src/Prime/Envelope.php +++ b/src/Prime/Envelope.php @@ -3,6 +3,7 @@ namespace Flasher\Prime; use Flasher\Prime\Notification\NotificationInterface; +use Flasher\Prime\Stamp\PresentableStampInterface; use Flasher\Prime\Stamp\StampInterface; final class Envelope implements NotificationInterface @@ -181,6 +182,16 @@ final class Envelope implements NotificationInterface */ public function toArray() { - return $this->notification->toArray(); + $array = array( + 'notification' => $this->notification->toArray(), + ); + + foreach ($this->all() as $stamp) { + if ($stamp instanceof PresentableStampInterface) { + $array = array_merge($array, $stamp->toArray()); + } + } + + return $array; } } diff --git a/src/Prime/EventDispatcher/Event/ResponseEvent.php b/src/Prime/EventDispatcher/Event/ResponseEvent.php new file mode 100644 index 00000000..aee83619 --- /dev/null +++ b/src/Prime/EventDispatcher/Event/ResponseEvent.php @@ -0,0 +1,37 @@ +envelopes = $envelopes; + } + + /** + * @return Envelope[] + */ + public function getEnvelopes() + { + return $this->envelopes; + } + + /** + * @param Envelope[] $envelopes + */ + public function setEnvelopes(array $envelopes) + { + $this->envelopes = $envelopes; + } +} diff --git a/src/Prime/EventDispatcher/EventListener/ResponseListener.php b/src/Prime/EventDispatcher/EventListener/ResponseListener.php new file mode 100644 index 00000000..95e58a59 --- /dev/null +++ b/src/Prime/EventDispatcher/EventListener/ResponseListener.php @@ -0,0 +1,44 @@ +filter = $filter; + } + + /** + * @param FilterEvent $event + */ + public function __invoke(FilterEvent $event) + { + $criteria = $event->getCriteria(); + $criteria['delay'] = 0; + $criteria['hops']['min'] = 1; + + $envelopes = $this->filter->filter($event->getEnvelopes(), $criteria); + + $event->setEnvelopes($envelopes); + } + + /** + * @inheritDoc + */ + public static function getSubscribedEvents() + { + return 'Flasher\Prime\EventDispatcher\Event\FilterEvent'; + } +} diff --git a/src/Prime/EventDispatcher/EventListener/TemplateListener.php b/src/Prime/EventDispatcher/EventListener/TemplateListener.php new file mode 100644 index 00000000..c3836455 --- /dev/null +++ b/src/Prime/EventDispatcher/EventListener/TemplateListener.php @@ -0,0 +1,72 @@ +config = $config; + $this->templateEngine = $templateEngine; + } + + public function __invoke(ResponseEvent $event) + { + $envelopes = array(); + + foreach ($event->getEnvelopes() as $envelope) { + $handler = $envelope->get('Flasher\Prime\Stamp\HandlerStamp')->getHandler(); + + if ('template' !== $handler) { + $envelopes[] = $envelope; + continue; + } + + $viewStamp = $envelope->get('Flasher\Prime\Stamp\TemplateStamp'); + $view = 'default'; + if (null !== $viewStamp) { + $view = $viewStamp->getView(); + } + + $template = $this->config->get('adapters.template.views.'.$view); + + if (null === $template) { + $default = $this->config->get('adapters.template.default'); + $template = $this->config->get('adapters.template.views.'.$default); + } + + $compiled = $this->templateEngine->render($template, array( + 'envelope' => $envelope, + )); + + $envelope->withStamp(new TemplateStamp($view, $compiled)); + $envelopes[] = $envelope; + } + + $event->setEnvelopes($envelopes); + } + + public static function getSubscribedEvents() + { + return 'Flasher\Prime\EventDispatcher\Event\ResponseEvent'; + } +} diff --git a/src/Prime/Factory/NotificationFactory.php b/src/Prime/Factory/NotificationFactory.php new file mode 100644 index 00000000..8fbf9745 --- /dev/null +++ b/src/Prime/Factory/NotificationFactory.php @@ -0,0 +1,52 @@ +storageManager = $storageManager; + } + + /** + * {@inheritdoc} + */ + public function createNotificationBuilder() + { + return new NotificationBuilder($this->getStorageManager(), new Notification(), 'template'); + } + + /** + * Dynamically call the default driver instance. + * + * @param string $method + * @param array $parameters + * + * @return mixed + */ + public function __call($method, array $parameters) + { + return call_user_func_array(array($this->createNotificationBuilder(), $method), $parameters); + } + + /** + * @return StorageManagerInterface + */ + public function getStorageManager() + { + return $this->storageManager; + } +} diff --git a/src/Prime/Factory/NotificationFactoryInterface.php b/src/Prime/Factory/NotificationFactoryInterface.php new file mode 100644 index 00000000..2100bca0 --- /dev/null +++ b/src/Prime/Factory/NotificationFactoryInterface.php @@ -0,0 +1,16 @@ +factories[$alias] = $factory; diff --git a/src/Prime/FlasherInterface.php b/src/Prime/FlasherInterface.php index a5a2a7e7..fb7780f9 100644 --- a/src/Prime/FlasherInterface.php +++ b/src/Prime/FlasherInterface.php @@ -2,7 +2,7 @@ namespace Flasher\Prime; -use Flasher\Prime\Factory\FactoryInterface; +use Flasher\Prime\Factory\NotificationFactoryInterface; use Flasher\Prime\Notification\NotificationBuilderInterface; /** @@ -15,7 +15,7 @@ interface FlasherInterface * * @param string|null $alias * - * @return FactoryInterface + * @return NotificationFactoryInterface * * @throws \InvalidArgumentException */ @@ -25,9 +25,9 @@ interface FlasherInterface * Register a custom driver creator. * * @param string $alias - * @param FactoryInterface $factory + * @param NotificationFactoryInterface $factory * * @return $this */ - public function addFactory($alias, FactoryInterface $factory); + public function addFactory($alias, NotificationFactoryInterface $factory); } diff --git a/src/Prime/Notification/NotificationBuilder.php b/src/Prime/Notification/NotificationBuilder.php index a2288480..415fa448 100644 --- a/src/Prime/Notification/NotificationBuilder.php +++ b/src/Prime/Notification/NotificationBuilder.php @@ -9,6 +9,7 @@ use Flasher\Prime\Stamp\HopsStamp; use Flasher\Prime\Stamp\PriorityStamp; use Flasher\Prime\Stamp\StampInterface; use Flasher\Prime\Storage\StorageManagerInterface; +use Flasher\Toastr\Prime\ToastrBuilder; class NotificationBuilder implements NotificationBuilderInterface { diff --git a/src/Prime/Renderer/Presenter/AbstractPresenter.php b/src/Prime/Renderer/Presenter/AbstractPresenter.php new file mode 100644 index 00000000..71ff83c1 --- /dev/null +++ b/src/Prime/Renderer/Presenter/AbstractPresenter.php @@ -0,0 +1,116 @@ +config = $config; + } + + /** + * @param Envelope[] $envelopes + * + * @return array[] + */ + protected function getEnvelopes(array $envelopes) + { + return array_map(function (Envelope $envelope) { + return $envelope->toArray(); + }, $envelopes); + } + + /** + * @param Envelope[] $envelopes + * + * @return string[] + */ + protected function getStyles(array $envelopes) + { + return $this->getAssets('styles', $envelopes); + } + + /** + * @param Envelope[] $envelopes + * + * @return string[] + */ + protected function getScripts(array $envelopes) + { + return $this->getAssets('scripts', $envelopes); + } + + /** + * @param Envelope[] $envelopes + * + * @return string[] + */ + protected function getOptions(array $envelopes) + { + $options = array(); + $handlers = array(); + + foreach ($envelopes as $envelope) { + $handler = $envelope->get('Flasher\Prime\Stamp\HandlerStamp')->getHandler(); + if (in_array($handler, $handlers)) { + continue; + } + + $handlers[] = $handler; + $options[$handler] = $this->config->get(sprintf('adapters.%s.options', $handler), array()); + } + + return array_filter($options); + } + + /** + * @param Envelope[] $envelopes + * + * @return array + */ + protected function toArray(array $envelopes = array()) + { + return array( + 'scripts' => $this->getScripts($envelopes), + 'styles' => $this->getStyles($envelopes), + 'options' => $this->getOptions($envelopes), + 'envelopes' => $this->getEnvelopes($envelopes), + ); + } + + /** + * @param string $keyword + * @param Envelope[] $envelopes + * + * @return string[] + */ + private function getAssets($keyword, $envelopes) + { + $files = $this->config->get($keyword, array()); + $handlers = array(); + + foreach ($envelopes as $envelope) { + $handler = $envelope->get('Flasher\Prime\Stamp\HandlerStamp')->getHandler(); + if (in_array($handler, $handlers)) { + continue; + } + + $handlers[] = $handler; + $files = array_merge($files, $this->config->get(sprintf('adapters.%s.%s', $handler, $keyword), array())); + } + + return array_values(array_filter(array_unique($files))); + } +} diff --git a/src/Prime/Renderer/Presenter/ArrayPresenter.php b/src/Prime/Renderer/Presenter/ArrayPresenter.php new file mode 100644 index 00000000..4113119d --- /dev/null +++ b/src/Prime/Renderer/Presenter/ArrayPresenter.php @@ -0,0 +1,14 @@ +toArray($envelopes); + } +} diff --git a/src/Prime/Renderer/Presenter/HtmlPresenter.php b/src/Prime/Renderer/Presenter/HtmlPresenter.php new file mode 100644 index 00000000..8d2276b3 --- /dev/null +++ b/src/Prime/Renderer/Presenter/HtmlPresenter.php @@ -0,0 +1,49 @@ +renderScripts($this->getScripts($envelopes), $context); + $response = json_encode($this->toArray($envelopes)); + + return << +if ("undefined" === typeof PHPFlasher) { + alert("[PHPFlasher] not found, please include the '/bundles/flasher/flasher.js' file"); +} else { + PHPFlasher.render({$response}); +} + +HTML; + } + + /** + * @param string[] $scripts + * @param array $context + * + * @return string + */ + public function renderScripts($scripts, array $context) + { + $html = ''; + + foreach ($scripts as $file) { + if (empty($context['content']) || false === strpos($context['content'], $file)) { + $html .= sprintf('', $file).PHP_EOL; + } + } + + return $html; + } +} diff --git a/src/Prime/Renderer/Presenter/PresenterInterface.php b/src/Prime/Renderer/Presenter/PresenterInterface.php new file mode 100644 index 00000000..70bdbfb8 --- /dev/null +++ b/src/Prime/Renderer/Presenter/PresenterInterface.php @@ -0,0 +1,16 @@ + + */ + private $presenters; + + public function __construct(ConfigInterface $config) + { + $this->addPresenter('array', new ArrayPresenter($config)); + $this->addPresenter('html', new HtmlPresenter($config)); + } + + /** + * @inheritDoc + */ + public function addPresenter($alias, PresenterInterface $response) + { + $this->presenters[$alias] = $response; + } + + /** + * @inheritDoc + */ + public function create($alias) + { + if (!isset($this->presenters[$alias])) { + throw new \InvalidArgumentException(sprintf('[%s] presenter not supported.', $alias)); + } + + return $this->presenters[$alias]; + } +} diff --git a/src/Prime/Renderer/Presenter/PresenterManagerInterface.php b/src/Prime/Renderer/Presenter/PresenterManagerInterface.php new file mode 100644 index 00000000..c4a8eea0 --- /dev/null +++ b/src/Prime/Renderer/Presenter/PresenterManagerInterface.php @@ -0,0 +1,19 @@ +storageManager = $storageManager; $this->eventDispatcher = $eventDispatcher; $this->config = $config; - $this->responseManager = $responseManager ?: new ResponseManager(); + $this->presenterManager = $presenterManager ?: new PresenterManager($config); } /** @@ -57,20 +58,14 @@ final class Renderer implements RendererInterface { $envelopes = $this->getEnvelopes($criteria); - if (empty($envelopes)) { - return array(); - } - - $response = array( - 'scripts' => $this->getScripts($envelopes), - 'styles' => $this->getStyles($envelopes), - 'options' => $this->getOptions($envelopes), - 'notifications' => $this->getNotifications($envelopes), - ); - $this->storageManager->remove($envelopes); - return $this->responseManager->create(isset($context['format']) ? $context['format'] : 'array')->render($response, $context); + $event = new ResponseEvent($envelopes); + $this->eventDispatcher->dispatch($event); + + $format = isset($context['format']) ? $context['format'] : 'array'; + + return $this->presenterManager->create($format)->render($event->getEnvelopes(), $context); } /** @@ -87,87 +82,4 @@ final class Renderer implements RendererInterface return $event->getEnvelopes(); } - - /** - * @param Envelope[] $envelopes - * - * @return string[] - */ - private function getStyles(array $envelopes) - { - return $this->getAssets('styles', $envelopes); - } - - /** - * @param Envelope[] $envelopes - * - * @return string[] - */ - private function getScripts(array $envelopes) - { - return $this->getAssets('scripts', $envelopes); - } - - /** - * @param Envelope[] $envelopes - * - * @return string[] - */ - private function getOptions(array $envelopes) - { - $options = array(); - $handlers = array(); - - foreach ($envelopes as $envelope) { - $handler = $envelope->get('Flasher\Prime\Stamp\HandlerStamp')->getHandler(); - if (in_array($handler, $handlers)) { - continue; - } - - $handlers[] = $handler; - $options[$handler] = $this->config->get(sprintf('adapters.%s.options', $handler), array()); - } - - return array_filter($options); - } - - /** - * @param Envelope[] $envelopes - * - * @return array[] - */ - private function getNotifications(array $envelopes) - { - return array_map(function (Envelope $envelope) { - return array( - 'handler' => $envelope->get('Flasher\Prime\Stamp\HandlerStamp')->getHandler(), - 'notification' => $envelope->toArray(), - ); - }, - $envelopes); - } - - /** - * @param string $keyword - * @param Envelope[] $envelopes - * - * @return string[] - */ - private function getAssets($keyword, $envelopes) - { - $files = $this->config->get($keyword, array()); - $handlers = array(); - - foreach ($envelopes as $envelope) { - $handler = $envelope->get('Flasher\Prime\Stamp\HandlerStamp')->getHandler(); - if (in_array($handler, $handlers)) { - continue; - } - - $handlers[] = $handler; - $files = array_merge($files, $this->config->get(sprintf('adapters.%s.%s', $handler, $keyword), array())); - } - - return array_values(array_filter(array_unique($files))); - } } diff --git a/src/Prime/Resources/views/tailwindcss.php b/src/Prime/Resources/views/tailwindcss.php new file mode 100644 index 00000000..e69de29b diff --git a/src/Prime/Stamp/CreatedAtStamp.php b/src/Prime/Stamp/CreatedAtStamp.php index ea11de0a..37953002 100644 --- a/src/Prime/Stamp/CreatedAtStamp.php +++ b/src/Prime/Stamp/CreatedAtStamp.php @@ -6,21 +6,28 @@ use DateTime; use DateTimeZone; use Exception; -final class CreatedAtStamp implements StampInterface, OrderableStampInterface +final class CreatedAtStamp implements StampInterface, OrderableStampInterface, PresentableStampInterface { /** * @var DateTime */ private $createdAt; + /** + * @var string + */ + private $format; + /** * @param DateTime|null $createdAt + * @param string|null $format * * @throws Exception */ - public function __construct(DateTime $createdAt = null) + public function __construct(DateTime $createdAt = null, $format = null) { $this->createdAt = $createdAt ?: new DateTime('now', new DateTimeZone('Africa/Casablanca')); + $this->format = $format ?: 'Y-m-d H:i:s'; } /** @@ -44,4 +51,14 @@ final class CreatedAtStamp implements StampInterface, OrderableStampInterface return $this->createdAt->getTimestamp() - $orderable->createdAt->getTimestamp(); } + + /** + * @inheritDoc + */ + public function toArray() + { + return array( + 'created_at' => $this->getCreatedAt()->format($this->format), + ); + } } diff --git a/src/Prime/Stamp/HandlerStamp.php b/src/Prime/Stamp/HandlerStamp.php index f9c2d667..de42bbe4 100644 --- a/src/Prime/Stamp/HandlerStamp.php +++ b/src/Prime/Stamp/HandlerStamp.php @@ -2,7 +2,7 @@ namespace Flasher\Prime\Stamp; -final class HandlerStamp implements StampInterface +final class HandlerStamp implements StampInterface, PresentableStampInterface { /** * @var string @@ -24,4 +24,14 @@ final class HandlerStamp implements StampInterface { return $this->handler; } + + /** + * @inheritDoc + */ + public function toArray() + { + return array( + 'handler' => $this->getHandler(), + ); + } } diff --git a/src/Prime/Stamp/PresentableStampInterface.php b/src/Prime/Stamp/PresentableStampInterface.php new file mode 100644 index 00000000..682a05b8 --- /dev/null +++ b/src/Prime/Stamp/PresentableStampInterface.php @@ -0,0 +1,11 @@ + + */ + public function toArray(); +} diff --git a/src/Prime/Stamp/PriorityStamp.php b/src/Prime/Stamp/PriorityStamp.php index b72894bb..cd5439dc 100644 --- a/src/Prime/Stamp/PriorityStamp.php +++ b/src/Prime/Stamp/PriorityStamp.php @@ -2,7 +2,7 @@ namespace Flasher\Prime\Stamp; -final class PriorityStamp implements StampInterface, OrderableStampInterface +final class PriorityStamp implements StampInterface, OrderableStampInterface, PresentableStampInterface { /** * @var int @@ -38,4 +38,14 @@ final class PriorityStamp implements StampInterface, OrderableStampInterface return $this->priority - $orderable->priority; } + + /** + * @inheritDoc + */ + public function toArray() + { + return array( + 'priority' => $this->getPriority(), + ); + } } diff --git a/src/Prime/Stamp/TemplateStamp.php b/src/Prime/Stamp/TemplateStamp.php new file mode 100644 index 00000000..3b52c420 --- /dev/null +++ b/src/Prime/Stamp/TemplateStamp.php @@ -0,0 +1,52 @@ +view = $view; + $this->template = $template; + } + + /** + * @return string + */ + public function getView() + { + return $this->view; + } + + /** + * @return string + */ + public function getTemplate() + { + return $this->template; + } + + /** + * @inheritDoc + */ + public function toArray() + { + return array( + 'template' => $this->getTemplate(), + ); + } +} diff --git a/src/Prime/Template/Engine.php b/src/Prime/Template/Engine.php new file mode 100644 index 00000000..e34397d0 --- /dev/null +++ b/src/Prime/Template/Engine.php @@ -0,0 +1,11 @@ +children() ->scalarNode('default') ->cannotBeEmpty() - ->defaultValue('toastr') ->end() ->arrayNode('scripts') ->prototype('scalar')->end() ->defaultValue(array( - '/bundles/flasher/flasher.js' + '/bundles/flasher/flasher.js', )) ->end() ->arrayNode('styles') diff --git a/src/Symfony/Resources/config/config.yaml b/src/Symfony/Resources/config/config.yaml index 4079d1d5..52d4fb72 100644 --- a/src/Symfony/Resources/config/config.yaml +++ b/src/Symfony/Resources/config/config.yaml @@ -12,11 +12,12 @@ services: arguments: - '@flasher.config' - flasher.abstract_factory: - class: Flasher\Prime\Factory\AbstractFactory - abstract: true + flasher.notification_factory: + class: Flasher\Prime\Factory\NotificationFactory arguments: - '@flasher.storage_manager' + tags: + - { name: 'flasher.factory', alias: 'template' } flasher.storage: class: Flasher\Symfony\Storage\Storage @@ -55,6 +56,15 @@ services: tags: - { name: 'flasher.event_subscriber' } + flasher.event_listener.template_listener: + class: Flasher\Prime\EventDispatcher\EventListener\TemplateListener + public: false + arguments: + - '@flasher.config' + - '@flasher.template_engine' + tags: + - { name: 'flasher.event_subscriber' } + flasher.twig.extension: class: Flasher\Symfony\Twig\FlasherTwigExtension arguments: @@ -78,6 +88,11 @@ services: tags: - { name: 'kernel.event_subscriber' } + flasher.template_engine: + class: Flasher\Symfony\Template\TwigEngine + arguments: + - '@twig' + Flasher\Prime\Config\Config: '@flasher.config' Flasher\Prime\Flasher: '@flasher' Flasher\Prime\Renderer\Renderer: '@flasher.renderer' @@ -85,6 +100,8 @@ services: Flasher\Symfony\Storage\Storage: '@flasher.storage' Flasher\Prime\Storage\StorageManager: '@flasher.storage_manager' Flasher\Prime\Filter\Filter: '@flasher.filter' + Flasher\Prime\Factory\NotificationFactory: '@flasher.notification_factory' + Flasher\Symfony\Template\TwigEngine: '@flasher.template_engine' Flasher\Prime\Config\ConfigInterface: '@flasher.config' Flasher\Prime\FlasherInterface: '@flasher' @@ -93,3 +110,5 @@ services: Flasher\Prime\Filter\FilterInterface: '@flasher.filter' Flasher\Prime\EventDispatcher\EventDispatcherInterface: '@flasher.event_dispatcher' Flasher\Prime\Storage\StorageInterface: '@flasher.storage' + Flasher\Prime\Factory\NotificationFactoryInterface: '@flasher.notification_factory' + Flasher\Prime\Template\EngineInterface: '@flasher.template_engine' diff --git a/src/Symfony/Resources/public/flasher-template.js b/src/Symfony/Resources/public/flasher-template.js new file mode 100644 index 00000000..2a85cdd3 --- /dev/null +++ b/src/Symfony/Resources/public/flasher-template.js @@ -0,0 +1,137 @@ +PHPFlasher.addFactory('template', (function () { + 'use strict'; + + var exports = {}; + var options = { + timeout: 5000, + fps: 30, + position: 'top-right', + direction: 'top' + }; + + exports.render = function (envelope) { + var position = options.position; + + if (undefined !== envelope.options && undefined !== envelope.options.position) { + position = envelope.options.position; + } + + var container = document.getElementById('flasher-container-' + position); + if (null === container) { + container = document.createElement('div'); + container.id = "flasher-container-" + options.position; + container.style.position = "fixed"; + container.style.maxWidth = "304px"; + container.style.width = "100%"; + + switch (options.position) { + case "top-left": + container.style.top = 0; + container.style.left = "0.5em"; + break; + case "top-right": + container.style.top = 0; + container.style.right = "0.5em"; + break; + case "bottom-left": + container.style.bottom = 0; + container.style.left = "0.5em"; + break; + case "bottom-right": + default: + container.style.bottom = 0; + container.style.right = "0.5em"; + break; + } + document.getElementsByTagName('body')[0].appendChild(container); + } + + var template = stringToHTML(envelope.template); + template.style.transition = '0.8s'; + + switch (options.direction) { + case "top": + container.insertBefore(template, container.firstChild); + break; + case "bottom": + default: + container.appendChild(template); + break; + } + + var progressBar = template.querySelector('.flasher-progress'); + + var width = 0; + var lapse = 1000 / options.fps; + + var showProgress = function () { + width++; + var percent = (1 - lapse * width / options.timeout) * 100; + progressBar.style.width = percent + '%'; + + if (percent <= 0) { + template.style.opacity = 0; + clearInterval(progress); + + setTimeout(function () { + template.remove(); + }, 900); + } + } + + var progress = setInterval(showProgress, lapse); + + template.addEventListener('mouseover', function () { + clearInterval(progress); + }); + + template.addEventListener("mouseout", function () { + progress = setInterval(showProgress, lapse); + }); + }; + + exports.renderOptions = function (_setting) { + options = extend({}, options, _setting); + }; + + var stringToHTML = function (str) { + var support = (function () { + if (!window.DOMParser) return false; + var parser = new DOMParser(); + try { + parser.parseFromString('x', 'text/html'); + } catch (err) { + return false; + } + return true; + })(); + + if (support) { + var parser = new DOMParser(); + var doc = parser.parseFromString(str, 'text/html'); + return doc.body.firstChild; + } + + var dom = document.createElement('div'); + dom.innerHTML = str; + return dom.firstElementChild; + }; + + var extend = function (out) { + out = out || {}; + + for (var i = 1; i < arguments.length; i++) { + if (!arguments[i]) + continue; + + for (var key in arguments[i]) { + if (arguments[i].hasOwnProperty(key)) + out[key] = arguments[i][key]; + } + } + + return out; + }; + + return exports; +})()); diff --git a/src/Symfony/Resources/public/flasher.js b/src/Symfony/Resources/public/flasher.js index 4581795c..259c9661 100644 --- a/src/Symfony/Resources/public/flasher.js +++ b/src/Symfony/Resources/public/flasher.js @@ -8,7 +8,7 @@ var PHPFlasher = (function () { exports.addStyles(_options.styles, function () { exports.addScripts(_options.scripts, function () { exports.renderOptions(_options.options); - exports.renderNotifications(_options.notifications); + exports.renderEnvelopes(_options.envelopes); }); }); }; @@ -76,9 +76,9 @@ var PHPFlasher = (function () { }); }; - exports.renderNotifications = function (notifications) { - notifications.forEach(function (flash) { - factories[flash.handler].render(flash.notification); + exports.renderEnvelopes = function (envelopes) { + envelopes.forEach(function (envelope) { + factories[envelope.handler].render(envelope); }) }; diff --git a/src/Symfony/Resources/views/tailwindcss.html.twig b/src/Symfony/Resources/views/tailwindcss.html.twig new file mode 100644 index 00000000..2c9ce051 --- /dev/null +++ b/src/Symfony/Resources/views/tailwindcss.html.twig @@ -0,0 +1,44 @@ +{% if 'success' == envelope.type %} + {% set text_color = 'text-green-600' %} + {% set background_color = 'bg-green-600' %} + {% set progress_background_color = 'bg-green-100' %} + {% set border_color = 'border-green-600' %} + {% set icon = '' %} +{% elseif 'error' == envelope.type %} + {% set text_color = 'text-red-600' %} + {% set background_color = 'bg-red-600' %} + {% set progress_background_color = 'bg-red-100' %} + {% set border_color = 'border-red-600' %} + {% set icon = '' %} +{% elseif 'warning' == envelope.type %} + {% set text_color = 'text-yellow-600' %} + {% set background_color = 'bg-yellow-600' %} + {% set progress_background_color = 'bg-yellow-100' %} + {% set border_color = 'border-yellow-600' %} + {% set icon = '' %} +{% else %} + {% set text_color = 'text-blue-600' %} + {% set background_color = 'bg-blue-600' %} + {% set progress_background_color = 'bg-blue-100' %} + {% set border_color = 'border-blue-600' %} + {% set icon = '' %} +{% endif %} + +
+
+
+ {{ icon | raw }} +
+
+

+ {{ envelope.type }} +

+

+ {{ envelope.message }} +

+
+
+
+ +
+
diff --git a/src/Symfony/Template/TwigEngine.php b/src/Symfony/Template/TwigEngine.php new file mode 100644 index 00000000..d20786f7 --- /dev/null +++ b/src/Symfony/Template/TwigEngine.php @@ -0,0 +1,30 @@ +engine = $engine; + } + + /** + * @inheritDoc + */ + public function render($name, array $context = array()) + { + return $this->engine->render($name, $context); + } +} diff --git a/src/Symfony/composer.json b/src/Symfony/composer.json index 08dc28e5..caed0bfe 100644 --- a/src/Symfony/composer.json +++ b/src/Symfony/composer.json @@ -39,9 +39,6 @@ "require-dev": { "phpunit/phpunit": "^4.8|^5.0|^6.0|^7.0|^8.0|^9.0" }, - "suggest": { - "twig/twig": "Twig support for Htmlpresenter" - }, "autoload": { "psr-4": { "Flasher\\Symfony\\": "" diff --git a/src/Toastr/Laravel/Resources/public/flasher-toastr.js b/src/Toastr/Laravel/Resources/public/flasher-toastr.js index 5f3d8f48..6d3fd4e2 100644 --- a/src/Toastr/Laravel/Resources/public/flasher-toastr.js +++ b/src/Toastr/Laravel/Resources/public/flasher-toastr.js @@ -4,7 +4,8 @@ PHPFlasher.addFactory('toastr', (function () { var exports = {}; exports.render = function (data) { - toastr[data.type](data.message, data.title, data.options); + var notification = data.notification; + toastr[notification.type](notification.message, notification.title, notification.options); }; exports.renderOptions = function (options) { diff --git a/src/Toastr/Prime/ToastrFactory.php b/src/Toastr/Prime/ToastrFactory.php index 9cdbb93f..0a2d8788 100644 --- a/src/Toastr/Prime/ToastrFactory.php +++ b/src/Toastr/Prime/ToastrFactory.php @@ -2,12 +2,12 @@ namespace Flasher\Toastr\Prime; -use Flasher\Prime\Factory\AbstractFactory; +use Flasher\Prime\Factory\NotificationFactory; /** * @mixin ToastrBuilder */ -final class ToastrFactory extends AbstractFactory +final class ToastrFactory extends NotificationFactory { /** * {@inheritdoc} diff --git a/src/Toastr/Symfony/Resources/config/config.yaml b/src/Toastr/Symfony/Resources/config/config.yaml index 7f18015c..619a168d 100644 --- a/src/Toastr/Symfony/Resources/config/config.yaml +++ b/src/Toastr/Symfony/Resources/config/config.yaml @@ -1,6 +1,6 @@ services: flasher.toastr: - parent: 'flasher.abstract_factory' + parent: 'flasher.notification_factory' class: Flasher\Toastr\Prime\ToastrFactory tags: - { name: 'flasher.factory', alias: 'toastr' } diff --git a/src/Toastr/Symfony/Resources/public/flasher-toastr.js b/src/Toastr/Symfony/Resources/public/flasher-toastr.js index 5f3d8f48..6d3fd4e2 100644 --- a/src/Toastr/Symfony/Resources/public/flasher-toastr.js +++ b/src/Toastr/Symfony/Resources/public/flasher-toastr.js @@ -4,7 +4,8 @@ PHPFlasher.addFactory('toastr', (function () { var exports = {}; exports.render = function (data) { - toastr[data.type](data.message, data.title, data.options); + var notification = data.notification; + toastr[notification.type](notification.message, notification.title, notification.options); }; exports.renderOptions = function (options) {