├── LICENSE.md ├── README.md ├── composer.json ├── config └── blade-javascript.php ├── resources └── views │ └── index.blade.php └── src ├── BladeJavaScriptServiceProvider.php ├── Exceptions └── Untransformable.php ├── Renderer.php └── Transformers ├── ArrayTransformer.php ├── BooleanTransformer.php ├── NullTransformer.php ├── NumericTransformer.php ├── ObjectTransformer.php ├── StringTransformer.php └── Transformer.php /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Spatie bvba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Blade directive to export variables to JavaScript 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/laravel-blade-javascript.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-blade-javascript) 4 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 5 | [![run-tests](https://github.com/spatie/laravel-blade-javascript/actions/workflows/run-tests.yml/badge.svg)](https://github.com/spatie/laravel-blade-javascript/actions/workflows/run-tests.yml) 6 | ![Check & fix styling](https://github.com/spatie/laravel-blade-javascript/workflows/Check%20&%20fix%20styling/badge.svg) 7 | [![Total Downloads](https://img.shields.io/packagist/dt/spatie/laravel-blade-javascript.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-blade-javascript) 8 | 9 | This package contains a Blade directive to export values to JavaScript. 10 | 11 | Here's an example of how it can be used: 12 | 13 | ```php 14 | @javascript('key', 'value') 15 | ``` 16 | 17 | The rendered view will output: 18 | ```html 19 | 20 | ``` 21 | 22 | So in your browser you now have access to a key variable: 23 | ```js 24 | console.log(key); //outputs "value" 25 | ``` 26 | 27 | Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource). 28 | 29 | ## Support us 30 | 31 | [](https://spatie.be/github-ad-click/laravel-blade-javascript) 32 | 33 | We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). 34 | 35 | We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). 36 | 37 | ## Installation 38 | 39 | You can install the package via composer: 40 | 41 | ``` bash 42 | composer require spatie/laravel-blade-javascript 43 | ``` 44 | 45 | The package will automatically register itself. 46 | 47 | Optionally the config file can be published with 48 | 49 | ```bash 50 | php artisan vendor:publish --provider="Spatie\BladeJavaScript\BladeJavaScriptServiceProvider" --tag="config" 51 | ``` 52 | 53 | This is the contents of the published config file: 54 | 55 | ```php 56 | return [ 57 | 58 | /** 59 | * All passed values will be present in this JavaScript namespace. Set this to an empty string 60 | * to use the window object. 61 | */ 62 | 'namespace' => '', 63 | ]; 64 | ``` 65 | 66 | If you want to customize the generated ` 85 | ``` 86 | 87 | You can also use a single argument: 88 | ```php 89 | @javascript(['key' => 'value']) 90 | ``` 91 | 92 | This will also output: 93 | ```html 94 | 95 | ``` 96 | 97 | When setting the namespace to eg `js` in the config file this will be the output: 98 | 99 | ```html 100 | 101 | ``` 102 | 103 | ## Changelog 104 | 105 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 106 | 107 | ## Testing 108 | 109 | ``` bash 110 | composer test 111 | ``` 112 | 113 | ## Contributing 114 | 115 | Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. 116 | 117 | ## Security 118 | 119 | If you've found a bug regarding security please mail [security@spatie.be](mailto:security@spatie.be) instead of using the issue tracker. 120 | 121 | ## Credits 122 | 123 | - [Freek Van der Herten](https://github.com/freekmurze) 124 | - [Sebastian De Deyne](https://github.com/seb) 125 | - [All Contributors](../../contributors) 126 | 127 | This repository contains some code from the [laracasts/PHP-Vars-To-Js-Transformer](https://github.com/laracasts/PHP-Vars-To-Js-Transformer) package written by [Jeffrey Way](https://github.com/JeffreyWay). 128 | 129 | ## License 130 | 131 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 132 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spatie/laravel-blade-javascript", 3 | "description": "A Blade directive to export variables to JavaScript", 4 | "keywords": [ 5 | "spatie", 6 | "laravel", 7 | "blade", 8 | "javascript", 9 | "directive", 10 | "laravel-blade-javascript" 11 | ], 12 | "homepage": "https://github.com/spatie/laravel-blade-javascript", 13 | "license": "MIT", 14 | "authors": [ 15 | { 16 | "name": "Freek Van der Herten", 17 | "email": "freek@spatie.be", 18 | "homepage": "https://spatie.be", 19 | "role": "Developer" 20 | }, 21 | { 22 | "name": "Sebastian De Deyne", 23 | "email": "sebastian@spatie.be", 24 | "homepage": "https://spatie.be", 25 | "role": "Developer" 26 | } 27 | ], 28 | "require": { 29 | "php": "^8.0", 30 | "illuminate/contracts": "^8.0|^9.0|^10.0|^11.0|^12.0", 31 | "illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0" 32 | }, 33 | "require-dev": { 34 | "phpunit/phpunit": "^9.5|^10.5|^11.5", 35 | "orchestra/testbench": "^6.0|^7.0|^8.0|^9.0|^10.0", 36 | "pestphp/pest": "^1.22|^2.28|^3.0" 37 | }, 38 | "autoload": { 39 | "psr-4": { 40 | "Spatie\\BladeJavaScript\\": "src" 41 | } 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "Spatie\\BladeJavaScript\\Tests\\": "tests" 46 | } 47 | }, 48 | "scripts": { 49 | "test": "vendor/bin/pest" 50 | }, 51 | "extra": { 52 | "laravel": { 53 | "providers": [ 54 | "Spatie\\BladeJavaScript\\BladeJavaScriptServiceProvider" 55 | ] 56 | } 57 | }, 58 | "minimum-stability": "dev", 59 | "prefer-stable": true, 60 | "config": { 61 | "allow-plugins": { 62 | "pestphp/pest-plugin": true 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /config/blade-javascript.php: -------------------------------------------------------------------------------- 1 | '', 10 | ]; 11 | -------------------------------------------------------------------------------- /resources/views/index.blade.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/BladeJavaScriptServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 12 | __DIR__.'/../config/blade-javascript.php' => config_path('blade-javascript.php'), 13 | ], 'config'); 14 | 15 | $this->publishes([ 16 | __DIR__.'/../resources/views' => base_path('resources/views/vendor/bladeJavaScript'), 17 | ], 'views'); 18 | 19 | $this->loadViewsFrom(__DIR__.'/../resources/views', 'bladeJavaScript'); 20 | 21 | $this->app['blade.compiler']->directive('javascript', function ($expression) { 22 | $expression = $this->makeBackwardsCompatible($expression); 23 | 24 | return "render{$expression}; ?>"; 25 | }); 26 | } 27 | 28 | public function makeBackwardsCompatible($expression) 29 | { 30 | return "({$expression})"; 31 | } 32 | 33 | public function register() 34 | { 35 | $this->mergeConfigFrom( 36 | __DIR__.'/../config/blade-javascript.php', 37 | 'blade-javascript' 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Exceptions/Untransformable.php: -------------------------------------------------------------------------------- 1 | namespace = $config->get('blade-javascript.namespace', 'window'); 33 | } 34 | 35 | /** 36 | * @param array ...$arguments 37 | * 38 | * @return string 39 | * 40 | * @throws \Throwable 41 | */ 42 | public function render(...$arguments): string 43 | { 44 | $variables = $this->normalizeArguments($arguments); 45 | 46 | return view('bladeJavaScript::index', [ 47 | 'javaScript' => $this->buildJavaScriptSyntax($variables), 48 | ])->render(); 49 | } 50 | 51 | /** 52 | * @param $arguments 53 | * 54 | * @return mixed 55 | */ 56 | protected function normalizeArguments(array $arguments) 57 | { 58 | if (count($arguments) === 2) { 59 | return [$arguments[0] => $arguments[1]]; 60 | } 61 | 62 | if ($arguments[0] instanceof Arrayable) { 63 | return $arguments[0]->toArray(); 64 | } 65 | 66 | if (! is_array($arguments[0])) { 67 | $arguments[0] = [$arguments[0]]; 68 | } 69 | 70 | return $arguments[0]; 71 | } 72 | 73 | public function buildJavaScriptSyntax(array $variables): string 74 | { 75 | return collect($variables) 76 | ->map(function ($value, $key) { 77 | return $this->buildVariableInitialization($key, $value); 78 | }) 79 | ->reduce(function ($javaScriptSyntax, $variableInitialization) { 80 | return $javaScriptSyntax.$variableInitialization; 81 | }, $this->buildNamespaceDeclaration()); 82 | } 83 | 84 | protected function buildNamespaceDeclaration(): string 85 | { 86 | if (empty($this->namespace)) { 87 | return ''; 88 | } 89 | 90 | return "window['{$this->namespace}'] = window['{$this->namespace}'] || {};"; 91 | } 92 | 93 | /** 94 | * @param string $key 95 | * @param mixed $value 96 | * 97 | * @return string 98 | */ 99 | protected function buildVariableInitialization(string $key, $value) 100 | { 101 | $variableName = $this->namespace ? "window['{$this->namespace}']['{$key}']" : "window['{$key}']"; 102 | 103 | return "{$variableName} = {$this->optimizeValueForJavaScript($value)};"; 104 | } 105 | 106 | /** 107 | * @param mixed $value 108 | * 109 | * @return string 110 | * 111 | * @throws \Spatie\BladeJavaScript\Exceptions\Untransformable 112 | */ 113 | protected function optimizeValueForJavaScript($value): string 114 | { 115 | return $this->getTransformer($value)->transform($value); 116 | } 117 | 118 | public function getAllTransformers(): Collection 119 | { 120 | return collect($this->transformers)->map(function (string $className): Transformer { 121 | return new $className(); 122 | }); 123 | } 124 | 125 | /** 126 | * @param mixed $value 127 | * 128 | * @return \Spatie\BladeJavaScript\Transformers\Transformer 129 | * 130 | * @throws \Spatie\BladeJavaScript\Exceptions\Untransformable 131 | */ 132 | public function getTransformer($value): Transformer 133 | { 134 | foreach ($this->getAllTransformers() as $transformer) { 135 | if ($transformer->canTransform($value)) { 136 | return $transformer; 137 | } 138 | } 139 | 140 | throw Untransformable::noTransformerFound($value); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/Transformers/ArrayTransformer.php: -------------------------------------------------------------------------------- 1 | toJson(); 32 | } 33 | 34 | if ($value instanceof JsonSerializable || $value instanceof StdClass) { 35 | return json_encode($value); 36 | } 37 | 38 | if (! method_exists($value, '__toString')) { 39 | throw Untransformable::cannotTransformObject($value); 40 | } 41 | 42 | return "'{$value}'"; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Transformers/StringTransformer.php: -------------------------------------------------------------------------------- 1 | escape($value)}'"; 25 | } 26 | 27 | protected function escape(string $value): string 28 | { 29 | return str_replace(['\\', "'", "\r", "\n", '<', '>'], ['\\\\', "\'", '\\r', '\\n', '\<', '\>'], $value); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Transformers/Transformer.php: -------------------------------------------------------------------------------- 1 |