├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── dist ├── assets │ ├── editor.css │ ├── editor.js │ └── editor.js.LICENSE.txt ├── fonts │ ├── main-fonts.eot │ ├── main-fonts.svg │ ├── main-fonts.ttf │ └── main-fonts.woff └── svg │ ├── icon-a.svg │ ├── icon-b.svg │ ├── icon-c.svg │ └── icon-d.svg ├── mix-manifest.json ├── package-lock.json ├── package.json ├── src ├── App │ ├── Contracts │ │ └── Editable.php │ ├── Editor │ │ ├── AssetManager.php │ │ ├── Canvas.php │ │ ├── Config.php │ │ ├── PluginManager.php │ │ ├── StorageManager.php │ │ └── StyleManager.php │ ├── Http │ │ └── Controllers │ │ │ ├── AssetController.php │ │ │ └── EditorController.php │ ├── Repositories │ │ └── AssetRepository.php │ └── Traits │ │ ├── EditableTrait.php │ │ └── EditorTrait.php ├── GrapesjsServiceProvider.php ├── config.php ├── resources │ ├── js │ │ ├── gjs.js │ │ ├── index.js │ │ └── plugins │ │ │ ├── back-button │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── background-image │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── index.scss │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── code-editor │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── custom-font-family │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── custom-types │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── device-buttons │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── extra-buttons │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── image-editor │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ ├── svg │ │ │ │ ├── icon-a.svg │ │ │ │ ├── icon-b.svg │ │ │ │ ├── icon-c.svg │ │ │ │ └── icon-d.svg │ │ │ └── tsconfig.json │ │ │ ├── linkable-image │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── loader │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── notifications │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── plugins-loader │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── save-button │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ ├── style-editor │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── index.scss │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ └── index.js │ │ │ └── tsconfig.json │ │ │ └── templates │ │ │ ├── .gitignore │ │ │ ├── .npmignore │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ └── index.js │ │ │ └── tsconfig.json │ ├── scss │ │ └── gjs.scss │ └── views │ │ ├── edittor.blade.php │ │ ├── gjs-blocks │ │ └── example.blade.php │ │ └── templates │ │ └── example.blade.php └── routes │ └── laravel-grapesjs.php └── webpack.mix.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | /vendor/ 3 | /node_modules/ 4 | .DS_Store 5 | .composer.lock 6 | composer.lock 7 | .phpunit.result.cache 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 jd-dotlogics 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Grapesjs Editor 2 | This package provide an esay way to integrate [GrapesJS](https://grapesjs.com/) into your laravel proejct. 3 | 4 | ## Installation 5 | 6 | >`composer require jd-dotlogics/laravel-grapesjs` 7 | 8 | 9 | ## Publish files & migrate 10 | 11 | >`php artisan vendor:publish --tag="laravel-grapesjs"` 12 | 13 | >`php artisan migrate` 14 | 15 | ## Getting started 16 | 17 | 1. Add 'gjs_data' column to the model's database table (e.g Page), for which you are going to use the editor. 18 | 19 | 2. Implement Editable Interface and use the EditableTrait trait for the Model class 20 | ```php 21 | use Illuminate\Database\Eloquent\Model; 22 | use Dotlogics\Grapesjs\App\Traits\EditableTrait; 23 | use Dotlogics\Grapesjs\App\Contracts\Editable; 24 | 25 | class Page extends Model implements Editable 26 | { 27 | use EditableTrait; 28 | 29 | ... 30 | } 31 | ``` 32 | 33 | 3. Next Create a Route for editor 34 | ```php 35 | Route::get('pages/{page}/editor', 'PageController@editor'); 36 | 37 | ``` 38 | 39 | 4. In your controller, use the EditorTrait and add the editor method 40 | ```php 41 | show_gjs_editor($request, $page); 59 | } 60 | 61 | ... 62 | } 63 | 64 | 65 | ``` 66 | 67 | 5. Open this route /pages/:page_id/editor (where the :page_id is the id of your model) 68 | 69 | ## Placeholders 70 | Placeholders are like short-code in wordpress. The synax of placeholder is 71 | >`[[This-Is-Placeholder]]` 72 | 73 | Create a file named "this-is-placeholder.blade.php" in "/resources/views/vendor/laravel-grapesjs/placeholders" directory. 74 | 75 | The the placeholder will be replaced by the content of the relative blade file "this-is-placeholder.blade.php" 76 | 77 | 78 | ## Templates 79 | You can create global templates (or blocks) in the "/resources/views/vendor/laravel-grapesjs/templates" directory. And the templates/blocks will be availabe in the block section of edittor. You can also create model specific templates/blocks by defining getTemplatesPath/getGjsBlocksPath in model 80 | ```php 81 | public function getTemplatesPath(){ return 'pages_templates'; } 82 | ``` 83 | 84 | This will look for templates under "laravel-grapesj::pages_templates" directory. 85 | 86 | You can also return null from these methods to hide templates/blocks for any model. 87 | 88 | 89 | 90 | ## Display output 91 | The "Editable" model (e.g. Page) will have two public properties, css and html. In your blade file you can use these properties to display the content. 92 | 93 | ```blade 94 | 97 | 98 | {!! $page->html !!} 99 | 100 | ``` 101 | 102 | Thank you for using. 103 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jd-dotlogics/laravel-grapesjs", 3 | "description": "A package to easily integrate GrapesJS into your laravel proejct.", 4 | "type": "library", 5 | "require": { 6 | "php": "^7.4|^8.0", 7 | "illuminate/support": ">=5.6.0" 8 | }, 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Dotlogics", 13 | "email": "hello@dotlogics.com" 14 | } 15 | ], 16 | "autoload": { 17 | "psr-4": { 18 | "Dotlogics\\Grapesjs\\": "src" 19 | } 20 | }, 21 | "extra": { 22 | "laravel": { 23 | "providers": [ 24 | "Dotlogics\\Grapesjs\\GrapesjsServiceProvider" 25 | ] 26 | } 27 | }, 28 | "minimum-stability": "dev" 29 | } 30 | -------------------------------------------------------------------------------- /dist/assets/editor.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * Underscore.string 3 | * (c) 2010 Esa-Matti Suuronen 4 | * Underscore.string is freely distributable under the terms of the MIT license. 5 | * Documentation: https://github.com/epeli/underscore.string 6 | * Some code is borrowed from MooTools and Alexandru Marasteanu. 7 | * Version '3.3.4' 8 | * @preserve 9 | */ 10 | 11 | /*! 12 | * Sizzle CSS Selector Engine v2.3.6 13 | * https://sizzlejs.com/ 14 | * 15 | * Copyright JS Foundation and other contributors 16 | * Released under the MIT license 17 | * https://js.foundation/ 18 | * 19 | * Date: 2021-02-16 20 | */ 21 | 22 | /*! 23 | * jQuery JavaScript Library v3.6.0 24 | * https://jquery.com/ 25 | * 26 | * Includes Sizzle.js 27 | * https://sizzlejs.com/ 28 | * 29 | * Copyright OpenJS Foundation and other contributors 30 | * Released under the MIT license 31 | * https://jquery.org/license 32 | * 33 | * Date: 2021-03-02T17:08Z 34 | */ 35 | 36 | /*! grapesjs - 0.18.4 */ 37 | 38 | /*! grapesjs-blocks-bootstrap4 - 0.2.3 */ 39 | -------------------------------------------------------------------------------- /dist/fonts/main-fonts.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjawad096/laravel-grapesjs/2c4136621454b368c30464636701ef85a04d990f/dist/fonts/main-fonts.eot -------------------------------------------------------------------------------- /dist/fonts/main-fonts.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjawad096/laravel-grapesjs/2c4136621454b368c30464636701ef85a04d990f/dist/fonts/main-fonts.ttf -------------------------------------------------------------------------------- /dist/fonts/main-fonts.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjawad096/laravel-grapesjs/2c4136621454b368c30464636701ef85a04d990f/dist/fonts/main-fonts.woff -------------------------------------------------------------------------------- /mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/dist/assets/editor.js": "/dist/assets/editor.js", 3 | "/dist/assets/editor.css": "/dist/assets/editor.css", 4 | "/dist/fonts/main-fonts.eot": "/dist/fonts/main-fonts.eot", 5 | "/dist/fonts/main-fonts.svg": "/dist/fonts/main-fonts.svg", 6 | "/dist/fonts/main-fonts.ttf": "/dist/fonts/main-fonts.ttf", 7 | "/dist/fonts/main-fonts.woff": "/dist/fonts/main-fonts.woff", 8 | "/dist/svg/icon-a.svg": "/dist/svg/icon-a.svg", 9 | "/dist/svg/icon-b.svg": "/dist/svg/icon-b.svg", 10 | "/dist/svg/icon-c.svg": "/dist/svg/icon-c.svg", 11 | "/dist/svg/icon-d.svg": "/dist/svg/icon-d.svg" 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "mix", 6 | "watch": "mix watch", 7 | "watch-poll": "mix watch -- --watch-options-poll=1000", 8 | "hot": "mix watch --hot", 9 | "prod": "npm run production", 10 | "production": "mix --production" 11 | }, 12 | "devDependencies": { 13 | "axios": "^0.21", 14 | "grapesjs": "^0.18.4", 15 | "grapesjs-blocks-basic": "^0.1.8", 16 | "grapesjs-blocks-bootstrap4": "^0.2.3", 17 | "grapesjs-tui-image-editor": "^0.1.3", 18 | "laravel-mix": "^6.0.6", 19 | "lodash": "^4.17.19", 20 | "postcss": "^8.1.14", 21 | "sass": "^1.32.12", 22 | "sass-loader": "^11.0.1", 23 | "toastr": "^2.1.4" 24 | }, 25 | "dependencies": {} 26 | } 27 | -------------------------------------------------------------------------------- /src/App/Contracts/Editable.php: -------------------------------------------------------------------------------- 1 | headers['X-CSRF-TOKEN'] = csrf_token(); 24 | $this->upload = $assetRepository->getUploadUrl(); 25 | $this->uploadName = 'file'; 26 | 27 | $this->assets = $assetRepository->getAllMediaLinks(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/App/Editor/Canvas.php: -------------------------------------------------------------------------------- 1 | initStylesAndScripts(); 13 | 14 | if(!empty($styles)){ 15 | $this->mergeStyles($styles); 16 | } 17 | 18 | if(!empty($scripts)){ 19 | $this->mergeScripts($scripts); 20 | } 21 | } 22 | 23 | protected function mapScriptsUrls($urls) 24 | { 25 | $urls = collect($urls)->filter()->values()->toArray(); 26 | 27 | return array_map('url', $urls); 28 | } 29 | 30 | protected function initStylesAndScripts() 31 | { 32 | collect(['styles', 'scripts']) 33 | ->each(function($type){ 34 | $this->{$type} = $this->mapScriptsUrls(config("laravel-grapesjs.canvas.{$type}", [])); 35 | }); 36 | } 37 | 38 | public function mergeStyles($styles) 39 | { 40 | $this->styles = array_merge($this->styles, $this->mapScriptsUrls($styles)); 41 | 42 | return $this; 43 | } 44 | 45 | public function mergeScripts($scripts) 46 | { 47 | $this->scripts = array_merge($this->scripts, $this->mapScriptsUrls($scripts)); 48 | 49 | return $this; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/App/Editor/Config.php: -------------------------------------------------------------------------------- 1 | exposeApi = config('laravel-grapesjs.expose_api', false); 34 | $this->forceClass = config('laravel-grapesjs.force_class', false); 35 | } 36 | 37 | public function initialize(Editable $editable) 38 | { 39 | $pluginManager = app(PluginManager::class, ['templates_url' => $editable->templates_url]); 40 | $assetManager = app(AssetManager::class); 41 | $storageManager = app(StorageManager::class, ['save_url' => $editable->store_url]); 42 | $styleManager = app(StyleManager::class); 43 | 44 | $canvas = app(Canvas::class, ['styles' => $editable->style_sheet_links, 'scripts' => $editable->script_links]); 45 | 46 | $this->pluginManager = $pluginManager; 47 | $this->assetManager = $assetManager; 48 | $this->canvas = $canvas; 49 | $this->storageManager = $storageManager; 50 | $this->styleManager = $styleManager; 51 | 52 | $this->components = $editable->components; 53 | $this->style = $editable->styles; 54 | 55 | $this->initStylesAndScripts(); 56 | 57 | // dd($this->toArray()); 58 | return $this; 59 | } 60 | 61 | protected function initStylesAndScripts() 62 | { 63 | collect(['styles', 'scripts']) 64 | ->each(function($type){ 65 | $items = config("laravel-grapesjs.{$type}", []); 66 | $items = collect($items)->filter()->values()->toArray(); 67 | 68 | $this->{$type} = array_map('url', $items); 69 | }); 70 | } 71 | 72 | public function getStyles() 73 | { 74 | $extraStyles = $this->pluginManager ? $this->pluginManager->getPluginStyles() : []; 75 | 76 | return [...$extraStyles, ...$this->styles]; 77 | } 78 | 79 | public function getScripts() 80 | { 81 | $extraScripts = $this->pluginManager ? $this->pluginManager->getPluginScripts() : []; 82 | 83 | return [...$extraScripts, ...$this->scripts]; 84 | } 85 | 86 | public function toJson() 87 | { 88 | return json_encode($this); 89 | } 90 | 91 | public function __toString() 92 | { 93 | return $this->toJson(); 94 | } 95 | 96 | public function toArray() 97 | { 98 | return json_decode($this->toJson(), true); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/App/Editor/PluginManager.php: -------------------------------------------------------------------------------- 1 | basicBlocks = config('laravel-grapesjs.plugins.default.basic_blocks', false); 37 | $this->bootstrap4Blocks = config('laravel-grapesjs.plugins.default.bootstrap4_blocks', false); 38 | $this->codeEditor = config('laravel-grapesjs.plugins.default.code_editor', false); 39 | $this->imageEditor = config('laravel-grapesjs.plugins.default.image_editor', false); 40 | $this->customFonts = config('laravel-grapesjs.plugins.default.custom_fonts', []); 41 | $this->templates = config('laravel-grapesjs.plugins.default.templates', false); 42 | 43 | if($this->basicBlocks){ 44 | $this->basicBlocks = []; 45 | } 46 | 47 | if($this->bootstrap4Blocks){ 48 | $this->bootstrap4Blocks = []; 49 | } 50 | 51 | if($this->codeEditor){ 52 | $this->codeEditor = []; 53 | } 54 | 55 | if($this->imageEditor){ 56 | $this->imageEditor = [ 57 | 'dist_path' => asset('vendor/laravel-grapesjs'), 58 | 'proxy_url' => route('laravel-grapesjs.asset.proxy'), 59 | 'proxy_url_input' => 'file', 60 | ]; 61 | } 62 | 63 | if($this->templates){ 64 | $this->templates = [ 65 | 'url' => $templates_url, 66 | ]; 67 | } 68 | 69 | $this->pluginsLoader = $this->getPluginsLoaderOptions(); 70 | } 71 | 72 | public function getPluginsLoaderOptions() 73 | { 74 | $config = config('laravel-grapesjs.plugins.custom', []); 75 | 76 | if(!is_array($config)){ 77 | $config = []; 78 | } 79 | 80 | return collect($config) 81 | ->map(function($value, $key){ 82 | $options = []; 83 | $styles = []; 84 | $scripts = []; 85 | $enabled = true; 86 | 87 | if(is_string($key)){ 88 | $name = $key; 89 | 90 | if(is_string($value)){ 91 | $scripts = $value; 92 | }else{ 93 | $options = $value; 94 | } 95 | }else if(is_string($value)){ 96 | $name = $value; 97 | }else if(!is_array($value)){ 98 | return null; 99 | }else{ 100 | $name = $value['name'] ?? null; 101 | $options = $value['options'] ?? []; 102 | $enabled = (bool)($value['enabled'] ?? true); 103 | $styles = $value['styles'] ?? []; 104 | $scripts = $value['scripts'] ?? []; 105 | 106 | if(!empty($value['styles'])){ 107 | } 108 | 109 | if(!empty($value['scripts'])){ 110 | } 111 | } 112 | 113 | $styles = array_map('url', (array)$styles); 114 | $scripts = array_map('url', (array)$scripts); 115 | 116 | return compact('name', 'options', 'enabled', 'styles', 'scripts'); 117 | }) 118 | ->filter() 119 | ->unique('name') 120 | ->where('enabled', true) 121 | ->values() 122 | ->toArray(); 123 | } 124 | 125 | protected function getPluginStyleScript($type = 'scripts') 126 | { 127 | return collect($this->pluginsLoader)->pluck($type)->flatten()->toArray(); 128 | } 129 | 130 | public function getPluginStyles() 131 | { 132 | return $this->getPluginStyleScript('styles'); 133 | } 134 | 135 | public function getPluginScripts() 136 | { 137 | return $this->getPluginStyleScript(); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/App/Editor/StorageManager.php: -------------------------------------------------------------------------------- 1 | headers['X-CSRF-TOKEN'] = csrf_token(); 20 | 21 | $this->autosave = config('laravel-grapesjs.storage_manager.autosave', true); 22 | $this->stepsBeforeSave = config('laravel-grapesjs.storage_manager.steps_before_save', 10); 23 | 24 | if(!empty($save_url)){ 25 | $this->type = 'remote'; 26 | $this->urlStore = $save_url; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/App/Editor/StyleManager.php: -------------------------------------------------------------------------------- 1 | sectors = []; 11 | } 12 | 13 | } 14 | } -------------------------------------------------------------------------------- /src/App/Http/Controllers/AssetController.php: -------------------------------------------------------------------------------- 1 | json( 17 | $assetRepository->getAllMediaLinks() 18 | ); 19 | } 20 | 21 | /** 22 | * Store a newly created resource in storage. 23 | * 24 | * @param \Illuminate\Http\Request $request 25 | * @return \Illuminate\Http\Response 26 | */ 27 | public function store(Request $request, AssetRepository $assetRepository) 28 | { 29 | $this->validate($request, [ 30 | 'file' => 'required|array', 31 | 'file.*' => 'required|file' 32 | ]); 33 | 34 | return response()->json([ 35 | 'data' => $assetRepository->uploadFilesFromRequest('file') 36 | ]); 37 | } 38 | 39 | public function proxy(Request $request) 40 | { 41 | try { 42 | $file = $request->get('file'); 43 | 44 | [$url, $isLocal] = $this->replaceLocalUrlToFilePath($file); 45 | 46 | if (!$isLocal) { 47 | $headers = get_headers($url, true); 48 | } 49 | 50 | if ($isLocal) { 51 | $headers = [ 52 | 'Content-Type' => mime_content_type($url), 53 | 'Content-Length' => filesize($url), 54 | ]; 55 | } 56 | 57 | header('Content-Description: File Transfer'); 58 | header('Content-Type: ' . (isset($headers['Content-Type']) ? $headers['Content-Type'] : 'application/octet-stream')); 59 | header('Content-Disposition: inline; filename="' . basename($url) . '"'); 60 | header('Cache-Control: ' . (isset($headers['Cache-Control']) ? $headers['Cache-Control'] : 'must-revalidate')); 61 | header('Pragma: public'); 62 | header('Access-Control-Allow-Origin: *'); 63 | header('Access-Control-Allow-Methods: *'); 64 | header("Access-Control-Allow-Headers: X-Requested-With"); 65 | if (isset($headers['Content-Length'])) { 66 | header('Content-Length: ' . $headers['Content-Length']); 67 | } 68 | readfile($url); 69 | exit; 70 | 71 | } catch (\Exception $ex) { 72 | abort(404,$ex->getMessage()); 73 | } 74 | } 75 | 76 | private function replaceLocalUrlToFilePath($url) 77 | { 78 | $urlParts = parse_url($url); 79 | if ($urlParts['host'] == 'localhost') { 80 | return [public_path($urlParts['path']), true]; 81 | } 82 | 83 | return [$url, false]; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/App/Http/Controllers/EditorController.php: -------------------------------------------------------------------------------- 1 | route()->parameters['model'] ?? null; 18 | 19 | if(!empty($model)){ 20 | $request->route()->setParameter('model', str_replace('-', '\\', $model)); 21 | } 22 | } 23 | 24 | public function editor(Request $request, $model, $id) 25 | { 26 | return $this->show_gjs_editor($request, $model::findOrFail($id)); 27 | } 28 | 29 | public function store(Request $request, $model, $id) 30 | { 31 | return $this->store_gjs_data($request, $model::findOrFail($id)); 32 | } 33 | 34 | public function templates(Request $request, $model, $id) 35 | { 36 | $model = $model::findOrFail($id); 37 | 38 | return collect([ 39 | 'templates', 40 | 'gjs-blocks', 41 | ]) 42 | ->map(function($type) use ($model){ 43 | $type = Str::of($type); 44 | $base_path_package_views = __DIR__ . '/../../../resources/views/'; 45 | $base_path_project_views = resource_path('views/vendor/laravel-grapesjs/'); 46 | 47 | $path_getter_method = "get" . $type->studly() . 'Path'; 48 | 49 | if(method_exists($model, $path_getter_method)){ 50 | $path = $model->{$path_getter_method}(); 51 | 52 | if(!empty($path)){ 53 | $path = $base_path_project_views . $path; 54 | } 55 | }else{ 56 | $path = $base_path_project_views . $type; 57 | 58 | if(!File::exists($path)) { 59 | $path = $base_path_package_views . $type; 60 | } 61 | } 62 | 63 | if(empty($path) || !File::exists($path)) return; 64 | 65 | $type_name = $type->replace('gjs-', ''); 66 | 67 | $id_prefix = (string)$type_name->singular() . '-'; 68 | $category = (string)$type_name->title(); 69 | 70 | $templates = []; 71 | foreach (File::allFiles($path) as $fileInfo) { 72 | $file_name = Str::of($fileInfo->getBasename())->replace(".blade.php", ""); 73 | $view_base = Str::of($fileInfo->getPath())->replace([ 74 | $base_path_package_views, 75 | $base_path_project_views, 76 | rtrim($base_path_package_views, '/'), 77 | rtrim($base_path_project_views, '/'), 78 | ], ''); 79 | 80 | if(!empty('' . $view_base)){ 81 | $view_base .= '.'; 82 | } 83 | 84 | $content = view("laravel-grapesjs::{$view_base}{$file_name}")->render(); 85 | 86 | // dd($content); 87 | $templates [] = [ 88 | 'id' => $id_prefix . $fileInfo->getFilename(), 89 | 'category' => $category, 90 | 'label' => $file_name->replace('-', ' ')->title(), 91 | 'media' => app('template-icon')->url(), 92 | 'content' => $content, 93 | ]; 94 | } 95 | 96 | return $templates; 97 | }) 98 | ->flatten(1) 99 | ->filter() 100 | ->values(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/App/Repositories/AssetRepository.php: -------------------------------------------------------------------------------- 1 | storage = Storage::disk(config('laravel-grapesjs.assets.disk')); 17 | $this->diskPath = config('laravel-grapesjs.assets.path') ?? 'laravel-grapesjs/media'; 18 | } 19 | 20 | public function getAllMediaLinks() 21 | { 22 | return collect($this->storage->allFiles($this->diskPath)) 23 | ->map(fn ($file) => $this->storage->url($file)) 24 | ->toArray(); 25 | } 26 | 27 | public function getUploadUrl() 28 | { 29 | return config('laravel-grapesjs.assets.upload_url') ?? route('laravel-grapesjs.asset.store'); 30 | } 31 | 32 | public function uploadSinglgeFile(UploadedFile $file) 33 | { 34 | /** 35 | * Check if file is submitted by Image Editor Its name will be blob 36 | */ 37 | if ( 'blob' == $file->getClientOriginalName()){ 38 | $path = $this->storage->putFile($this->diskPath, $file, 'public'); 39 | }else{ 40 | $path = $this->storage->putFileAs($this->diskPath, $file, $file->getClientOriginalName(), 'public'); 41 | } 42 | 43 | return $this->storage->url($path); 44 | } 45 | 46 | public function uploadFilesFromRequest($file_name = 'file') 47 | { 48 | $files = request()->file($file_name); 49 | 50 | if (!is_array($files)){ 51 | $files = [$files]; 52 | } 53 | 54 | $uploaded_files = []; 55 | 56 | foreach ($files as $file) { 57 | $uploaded_files[] = $this->uploadSinglgeFile($file); 58 | } 59 | 60 | return $uploaded_files; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/App/Traits/EditableTrait.php: -------------------------------------------------------------------------------- 1 | getModelClass()) ?? ['Item']; 17 | return end($explode); 18 | } 19 | 20 | protected function getKeyValue() 21 | { 22 | return $this->{$this->getKeyName()}; 23 | } 24 | 25 | public function getEditorPageTitleAttribute(): string 26 | { 27 | $title = $this->name ?: $this->title ?: $this->slug ?: ''; 28 | 29 | $title = "{$title} " . $this->getModelBaseClass(); 30 | 31 | return $title; 32 | } 33 | 34 | public function setGjsDataAttribute($value) 35 | { 36 | $this->attributes['gjs_data'] = json_encode($value); 37 | } 38 | 39 | public function getGjsDataAttribute($value): array 40 | { 41 | return json_decode($value, true) ?? []; 42 | } 43 | 44 | protected function getPlaceholderAttributes($placeholder) 45 | { 46 | $attributes = ['item' => $this]; 47 | try { 48 | $placeholder = html_entity_decode($placeholder); 49 | $dom = new DOMDocument; 50 | libxml_use_internal_errors(TRUE); 51 | $dom->loadHTML("<$placeholder />"); 52 | libxml_use_internal_errors(FALSE); 53 | 54 | $body = $dom->documentElement->firstChild; 55 | $placeholder = $body->childNodes[0]; 56 | $length = $placeholder->attributes->length; 57 | 58 | for ($i = 0; $i < $length; ++$i) { 59 | $name = $placeholder->attributes->item($i)->name; 60 | $value = $placeholder->getAttribute($name); 61 | 62 | if(empty($value) || $value == "''"){ 63 | $value = true; 64 | } 65 | 66 | $attributes[$name] = $value; 67 | } 68 | } catch (\Throwable $th) { 69 | //throw $th; 70 | } 71 | return $attributes; 72 | } 73 | 74 | protected function findAndSetPlaceholders($html){ 75 | $re = '/\[\[[A-Z][a-z]*(-[A-Z][a-z]*)*([\s]+[a-z]+(=[^]]+)?)*\]\]/'; 76 | 77 | preg_match_all($re, $html, $placeholders); 78 | 79 | $placeholders = $placeholders[0] ?? []; 80 | 81 | foreach ($placeholders as $_placeholder) { 82 | if(empty($this->placeholders[$_placeholder])){ 83 | $placeholder = str_replace(['[[', ']]'], '', $_placeholder); 84 | $attributes = $this->getPlaceholderAttributes($placeholder); 85 | 86 | $view = preg_split('/[\s]+/', $placeholder); 87 | $view = array_shift($view); 88 | $view = strtolower($view); 89 | 90 | if(view()->exists("laravel-grapesjs::placeholders.{$view}")){ 91 | $this->setPlaceholder($_placeholder, view("laravel-grapesjs::placeholders.{$view}", $attributes)->render()); 92 | } 93 | } 94 | } 95 | 96 | $placeholders = $this->getPlaceholders(); 97 | $html = str_replace(array_keys($placeholders), array_values($placeholders), $html); 98 | 99 | return $html; 100 | } 101 | 102 | public function getHtmlAttribute(): string 103 | { 104 | $html = $this->gjs_data['html'] ?? ''; 105 | 106 | if ( empty($html) ){ 107 | return ''; 108 | } 109 | 110 | return $this->findAndSetPlaceholders($html); 111 | } 112 | 113 | public function getCssAttribute() : string 114 | { 115 | return $this->gjs_data['css'] ?? ''; 116 | } 117 | 118 | public function getComponentsAttribute() : array 119 | { 120 | return json_decode($this->gjs_data['components'] ?? '[]'); 121 | } 122 | 123 | public function getStylesAttribute(): array 124 | { 125 | return json_decode($this->gjs_data['styles'] ?? '[]'); 126 | } 127 | 128 | public function getStyleSheetLinksAttribute(): array 129 | { 130 | return []; 131 | } 132 | 133 | public function getScriptLinksAttribute(): array 134 | { 135 | return []; 136 | } 137 | 138 | public function getAssetsAttribute() :array 139 | { 140 | return []; 141 | } 142 | 143 | public function getStoreUrlAttribute(): string 144 | { 145 | return route('laravel-grapesjs.model.store', [$this->getModelClass(true), $this->getKeyValue()]); 146 | } 147 | 148 | public function getTemplatesUrlAttribute(): ?string 149 | { 150 | return route('laravel-grapesjs.model.templates', [$this->getModelClass(true), $this->getKeyValue()]); 151 | } 152 | 153 | public function getPlaceholders() 154 | { 155 | return $this->placeholders; 156 | } 157 | 158 | public function setPlaceholder($placeolder, $content) 159 | { 160 | $this->placeholders[$placeolder] = $content; 161 | 162 | return $this; 163 | } 164 | } -------------------------------------------------------------------------------- /src/App/Traits/EditorTrait.php: -------------------------------------------------------------------------------- 1 | initialize($model); 12 | 13 | return view('laravel-grapesjs::edittor', compact('editorConfig', 'model')); 14 | } 15 | 16 | protected function store_gjs_data(Request $request, $model) 17 | { 18 | $model->gjs_data = [ 19 | 'components' => $request->get('laravel-grapesjs-components'), 20 | 'styles' => $request->get('laravel-grapesjs-styles'), 21 | 'css' => $request->get('laravel-grapesjs-css'), 22 | 'html' => $request->get('laravel-grapesjs-html'), 23 | ]; 24 | 25 | $model->save(); 26 | 27 | return response()->noContent(200); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/GrapesjsServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadViewsFrom(realpath(__DIR__.'/resources/views/'), $this->namespace); 34 | $this->mergeConfigFrom(__DIR__.'/config.php', $this->namespace); 35 | 36 | $this->setupRoutes($this->app->router); 37 | 38 | if ($this->app->runningInConsole()) { 39 | $this->publishFiles(); 40 | } 41 | 42 | $this->setupViewDirectives(); 43 | } 44 | 45 | 46 | 47 | /** 48 | * Define the routes for the application. 49 | * 50 | * @param \Illuminate\Routing\Router $router 51 | * 52 | * @return void 53 | */ 54 | protected function setupRoutes(Router $router) 55 | { 56 | // by default, use the routes file provided in vendor 57 | $routeFilePathInUse = __DIR__.$this->routeFilePath; 58 | 59 | // but if there's a file with the same name in routes/backpack, use that one 60 | if (file_exists($path = base_path($this->routeFilePath))) { 61 | $routeFilePathInUse = $path; 62 | } 63 | 64 | $this->loadRoutesFrom($routeFilePathInUse); 65 | } 66 | 67 | protected function publishFiles() 68 | { 69 | $this->publishes([ 70 | __DIR__.'/config.php' => config_path($this->confiFilePath), 71 | ], [$this->namespace, 'config']); 72 | 73 | $this->publishes([ 74 | __DIR__.'/../dist' => public_path($this->publicDirPath), 75 | ], [$this->namespace, 'public', 'laravel-assets']); 76 | 77 | $this->publishes([ 78 | __DIR__.'/resources/views' => resource_path($this->viewDirPath), 79 | ], [$this->namespace, 'views']); 80 | } 81 | 82 | protected function setupViewDirectives() 83 | { 84 | //To Handle error if there no icon defined for any template 85 | $this->app->singleton('template-icon', function($app){ 86 | return new class { 87 | public function url(){} 88 | }; 89 | }); 90 | 91 | Blade::directive('templateIcon', function ($args) { 92 | $args = Blade::stripParentheses($args); 93 | 94 | return "singleton('template-icon', function(\$app){ 95 | return new class { 96 | protected \$called = false; 97 | 98 | public function url() { 99 | if(\$this->called) return null; 100 | 101 | \$this->called = true; 102 | 103 | return ''; 104 | } 105 | }; 106 | }); ?>"; 107 | }); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/config.php: -------------------------------------------------------------------------------- 1 | false, 15 | 16 | /* 17 | |-------------------------------------------------------------------------- 18 | | Routes 19 | |-------------------------------------------------------------------------- 20 | | 21 | | Routes Settings 22 | | 23 | */ 24 | 25 | 'routes' => [ 26 | 'middleware' => [ 27 | 'web', 'auth', 28 | ], 29 | ], 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Force Class 34 | |-------------------------------------------------------------------------- 35 | | 36 | | @See https://github.com/artf/grapesjs/issues/546 37 | | 38 | */ 39 | 40 | 'force_class' => false, 41 | 42 | /* 43 | |-------------------------------------------------------------------------- 44 | | Global Styles 45 | |-------------------------------------------------------------------------- 46 | | 47 | | Global Styles for the editor blade file. 48 | */ 49 | 50 | 'styles' => [ 51 | 'vendor/laravel-grapesjs/assets/editor.css' 52 | ], 53 | 54 | /* 55 | |-------------------------------------------------------------------------- 56 | | Global Scripts 57 | |-------------------------------------------------------------------------- 58 | | 59 | | Global scripts for the editor blade file. 60 | */ 61 | 62 | 'scripts' => [ 63 | 'vendor/laravel-grapesjs/assets/editor.js' 64 | ], 65 | 66 | /* 67 | |-------------------------------------------------------------------------- 68 | | Canvas styles and scripts 69 | |-------------------------------------------------------------------------- 70 | | 71 | | The styles and scripts for the editor content. 72 | | You need to add these also to your layout. 73 | | e.g the bootstrap files, etc 74 | | 75 | */ 76 | 77 | 'canvas' => [ 78 | 'styles' => [], 79 | 'scripts' => [], 80 | ], 81 | 82 | /* 83 | |-------------------------------------------------------------------------- 84 | | Assets Manager 85 | |-------------------------------------------------------------------------- 86 | | 87 | | Here you can configure the disk and custom upload URL for your asset 88 | | manager. 89 | | 90 | */ 91 | 92 | 'assets' => [ 93 | 'disk' => 'public', //Default: local 94 | 'path' => null, //Default: 'laravel-grapesjs/media', 95 | 'upload_url' => null, 96 | ], 97 | 98 | /* 99 | |-------------------------------------------------------------------------- 100 | | Style Manager 101 | |-------------------------------------------------------------------------- 102 | | 103 | | Enable/Disable selectors. 104 | | @see https://grapesjs.com/docs/api/style_manager.html#stylemanager 105 | | 106 | */ 107 | 108 | 'style_manager' => [ 109 | 'limited_selectors' => true, 110 | ], 111 | 112 | /* 113 | |-------------------------------------------------------------------------- 114 | | Storage Manager 115 | |-------------------------------------------------------------------------- 116 | | 117 | | Enable/Disable the autosave function for your editor. 118 | | 119 | */ 120 | 121 | 'storage_manager' => [ 122 | 'autosave' => true, 123 | 'steps_before_save' => 10, 124 | ], 125 | 126 | /* 127 | |-------------------------------------------------------------------------- 128 | | Plugin Manager 129 | |-------------------------------------------------------------------------- 130 | | 131 | | You can enable/disable built-in plugins or can add any custom plugin from 132 | | this config. Formats for custom plugins are as below. 133 | | 134 | | 1. Simplest way 135 | | 'plugin-name' => 'https://url_to_plugin_script.com' 136 | | 137 | | 2. Simple with options (Plugin script will be added to global scrips above) 138 | | 'plugin-name' => [ 139 | | //plugin options goes here 140 | | ] 141 | | 142 | | 3. Advanced way 143 | | [ 144 | | 'enabled => true, 145 | | 'name' => 'plugin-name', 146 | | 'styles' => [ 147 | | 'https://url_to_plugin_styles.com', 148 | | ], 149 | | 'scripts' => [ 150 | | 'https://url_to_plugin_script.com', 151 | | ], 152 | | 'options' => [ 153 | | //plugin options goes here 154 | | ], 155 | | ] 156 | | 157 | */ 158 | 159 | 'plugins' => [ 160 | 'default' => [ 161 | 'basic_blocks' => true, 162 | 'bootstrap4_blocks' => false, 163 | 'code_editor' => true, 164 | 'image_editor' => false, 165 | 'custom_fonts' => [], 166 | 'templates' => true, 167 | ], 168 | 'custom' => [ 169 | 'grapesjs-custom-code' => 'https://unpkg.com/grapesjs-custom-code', 170 | [ 171 | 'enabled' => true, 172 | 'name' => 'gjs-plugin-ckeditor', 173 | 'scripts' => [ 174 | 'https://cdn.ckeditor.com/4.14.0/full-all/ckeditor.js', 175 | 'https://unpkg.com/grapesjs-plugin-ckeditor', 176 | ], 177 | 'options' => [ 178 | 'position' => 'left', 179 | /** 180 | * Config options for CKeditor 181 | * Available options can be found here https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_config.html 182 | * Or you can use config builder https://cdn.ckeditor.com/4.14.0/full-all/samples/toolbarconfigurator/index.html 183 | */ 184 | 'options' => [ 185 | 'toolbarGroups' => [ 186 | [ "name" => "document", "groups" => [ "mode", "document", "doctools" ] ], 187 | [ "name" => "clipboard", "groups" => [ "clipboard", "undo" ] ], 188 | [ "name" => "editing", "groups" => [ "find", "selection", "spellchecker", "editing" ] ], 189 | [ "name" => "forms", "groups" => [ "forms" ] ], 190 | [ "name" => "basicstyles", "groups" => [ "basicstyles", "cleanup" ] ], 191 | [ "name" => "styles", "groups" => [ "styles" ] ], 192 | [ "name" => "paragraph", "groups" => [ "list", "indent", "blocks", "align", "bidi", "paragraph" ] ], 193 | [ "name" => "links", "groups" => [ "links" ] ], 194 | [ "name" => "insert", "groups" => [ "insert" ] ], 195 | [ "name" => "colors", "groups" => [ "colors" ] ], 196 | [ "name" => "tools", "groups" => [ "tools" ] ], 197 | [ "name" => "others", "groups" => [ "others" ] ], 198 | [ "name" => "about", "groups" => [ "about" ] ] 199 | ], 200 | 'removeButtons' => 'Save,NewPage,Preview,Print,Templates,Source,Form,Checkbox,Radio,TextField,Textarea,Select,Button,ImageButton,HiddenField,Flash,Table,About' 201 | ], 202 | ], 203 | ], 204 | [ 205 | 'enabled' => false, 206 | 'name' => 'grapesjs-plugin-forms', 207 | 'options' => [], 208 | 'scripts' => [ 209 | 'https://unpkg.com/grapesjs-plugin-forms', 210 | ], 211 | ], 212 | ], 213 | ], 214 | ]; -------------------------------------------------------------------------------- /src/resources/js/gjs.js: -------------------------------------------------------------------------------- 1 | import grapesjs from 'grapesjs'; 2 | import 'grapesjs-blocks-basic'; 3 | import 'grapesjs-blocks-bootstrap4'; 4 | import CodeEditor from "./plugins/code-editor" 5 | import ExtraButtons from "./plugins/extra-buttons" 6 | import ImageEditor from "./plugins/image-editor" 7 | import CustomFontFamily from "./plugins/custom-font-family" 8 | import Loader from "./plugins/loader" 9 | import Notifications from "./plugins/notifications" 10 | import SaveButton from "./plugins/save-button" 11 | import BackButton from "./plugins/back-button" 12 | import Templates from "./plugins/templates" 13 | import CustomTypes from "./plugins/custom-types" 14 | import DeviceButtons from './plugins/device-buttons' 15 | import BackgroundImage from "./plugins/background-image" 16 | import PluginsLoader from "./plugins/plugins-loader" 17 | import StyleEditor from "./plugins/style-editor" 18 | import LinkableImage from "./plugins/linkable-image" 19 | 20 | let config = window.editorConfig; 21 | delete window.editorConfig; 22 | 23 | let plugins = [] 24 | let pluginsOpts = {} 25 | 26 | if(config.pluginManager.basicBlocks){ 27 | plugins.push('gjs-blocks-basic') 28 | pluginsOpts['gjs-blocks-basic'] = config.pluginManager.basicBlocks; 29 | } 30 | 31 | if(config.pluginManager.bootstrap4Blocks){ 32 | plugins.push('grapesjs-blocks-bootstrap4') 33 | pluginsOpts['grapesjs-blocks-bootstrap4'] = config.pluginManager.bootstrap4Blocks; 34 | } 35 | 36 | if(config.pluginManager.codeEditor){ 37 | plugins.push(CodeEditor) 38 | pluginsOpts[CodeEditor] = config.pluginManager.codeEditor 39 | } 40 | 41 | if(config.pluginManager.imageEditor){ 42 | plugins.push(ImageEditor) 43 | pluginsOpts[ImageEditor] = config.pluginManager.imageEditor 44 | } 45 | 46 | if(config.pluginManager.templates){ 47 | plugins.push(Templates) 48 | pluginsOpts[Templates] = config.pluginManager.templates 49 | } 50 | 51 | plugins = [ 52 | ...plugins, 53 | CustomFontFamily, 54 | BackgroundImage, 55 | Loader, 56 | Notifications, 57 | CustomTypes, 58 | ExtraButtons, 59 | SaveButton, 60 | BackButton, 61 | DeviceButtons, 62 | PluginsLoader, 63 | StyleEditor, 64 | LinkableImage, 65 | ] 66 | 67 | pluginsOpts = { 68 | ...pluginsOpts, 69 | [BackgroundImage]: {}, 70 | [CustomFontFamily]: {fonts: config.pluginManager.customFonts}, 71 | [Loader]: {}, 72 | [Notifications]: {}, 73 | [CustomTypes]: {}, 74 | [ExtraButtons]: {}, 75 | [SaveButton]: {}, 76 | [BackButton]: {}, 77 | [DeviceButtons]: {}, 78 | [PluginsLoader]: config.pluginManager.pluginsLoader, 79 | [StyleEditor]: {}, 80 | [LinkableImage]: {}, 81 | }; 82 | 83 | config.plugins = plugins 84 | config.pluginsOpts = pluginsOpts 85 | 86 | let editor = grapesjs.init(config); 87 | 88 | if(config.exposeApi){ 89 | Object.defineProperty(window, 'gjsEditor', { 90 | value: editor 91 | }) 92 | } 93 | -------------------------------------------------------------------------------- /src/resources/js/index.js: -------------------------------------------------------------------------------- 1 | let config = window.editorConfig; 2 | 3 | if(Object.keys(config).length === 0){ 4 | throw new Error('No config found'); 5 | }else{ 6 | require('./gjs') 7 | } -------------------------------------------------------------------------------- /src/resources/js/plugins/back-button/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/back-button/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/back-button/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Back Button 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/back-button/README.md: -------------------------------------------------------------------------------- 1 | # Back Button 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['back-button'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `back-button` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/back-button` 63 | * NPM 64 | * `npm i back-button` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/back-button.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'back-button'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/back-button.git 120 | $ cd back-button 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/back-button/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "back-button", 3 | "version": "1.0.0", 4 | "description": "Back Button", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/back-button.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/back-button/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | let options = { 3 | icon: 'fa fa-arrow-left', 4 | title: 'Go back', 5 | link: null, 6 | ...opts, 7 | }; 8 | 9 | editor.Panels.addButton('options', { 10 | id: 'cancel', 11 | className: options.icon, 12 | command(editor) { 13 | if(options.link){ 14 | window.location = options.link; 15 | }else{ 16 | window.history.back() 17 | } 18 | }, 19 | attributes: { 20 | title: options.title 21 | } 22 | }); 23 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/back-button/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/background-image/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/background-image/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/background-image/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Background Image 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/background-image/README.md: -------------------------------------------------------------------------------- 1 | # Background Image 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['background-image'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `background-image` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/background-image` 63 | * NPM 64 | * `npm i background-image` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/background-image.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'background-image'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/background-image.git 120 | $ cd background-image 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/background-image/index.scss: -------------------------------------------------------------------------------- 1 | .jd-bg-settings { 2 | .gjs-sm-property { 3 | &:not(.gjs-sm-property--full){ 4 | width: 50%; 5 | } 6 | 7 | .background-image-preview { 8 | .gjs-sm-preview-file-cnt{ 9 | height: 180px; 10 | } 11 | } 12 | 13 | [type=color]{ 14 | height: 50px; 15 | padding-right: 5px; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/resources/js/plugins/background-image/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "background-image", 3 | "version": "1.0.0", 4 | "description": "Background Image", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/background-image.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/background-image/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | const COMMAND_ID = 'jd-open-change_bg-modal'; 3 | const TOOL_ICON = 'fa fa-image'; 4 | const BG_IMAGE = 'background-image'; 5 | 6 | let modal = editor.Modal; 7 | 8 | editor.Commands.add(COMMAND_ID, { 9 | run: (editor, sender) => setModalContent(), 10 | }); 11 | 12 | let setModalContent = content => { 13 | modal.setTitle('Change Background settings'); 14 | 15 | modal.setContent(''); 16 | modal.setContent(content || createModalContent()); 17 | 18 | !content && bindEventHandlers(); 19 | 20 | modal.open(); 21 | } 22 | 23 | let createModalContent = () => { 24 | let fields = [ 25 | { 26 | name: 'background-image', 27 | title: 'Image', 28 | type: 'image', 29 | full_width: true, 30 | }, 31 | { 32 | name: 'background-color', 33 | title: 'Color', 34 | type: 'color', 35 | full_width: true, 36 | }, 37 | { 38 | name: 'background-repeat', 39 | title: 'Repeat', 40 | type: 'select', 41 | options: ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'], 42 | }, 43 | { 44 | name: 'background-position', 45 | title: 'Position', 46 | type: 'select', 47 | options: ['left top', 'left center', 'left bottom', 'right top', 'right center', 'right bottom', 'center top', 'center center', 'center bottom'], 48 | }, 49 | { 50 | name: 'background-attachment', 51 | title: 'Attachment', 52 | type: 'select', 53 | options: ['scroll', 'fixed', 'local'], 54 | }, 55 | { 56 | name: 'background-size', 57 | title: 'Size', 58 | type: 'select', 59 | options: ['auto', 'cover', 'contain'], 60 | }, 61 | ]; 62 | 63 | let styles = editor.getSelected().getStyle(); 64 | let fields_html = fields.map(field => { 65 | let { name, title, type, options, full_width } = field, 66 | field_html = '', 67 | isImage = type == 'image', 68 | value = styles[name] || null; 69 | 70 | if (isImage) { 71 | field_html = ` 72 | 73 | 74 | 75 | 76 | Choose Image 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | `; 89 | } else if (type == 'color') { 90 | field_html = ` 91 | 92 | 93 | 94 | 95 | 96 | `; 97 | } else if (type == 'select') { 98 | let options_html = ''; 99 | 100 | (options || []).forEach(option => { 101 | options_html += `${option}`; 102 | }); 103 | 104 | field_html = ` 105 | 106 | 107 | 108 | ${options_html} 109 | 110 | 111 | 112 | 113 | 114 | 115 | `; 116 | } 117 | 118 | return ` 119 | 120 | 121 | 122 | ${title} 123 | 124 | 125 | 126 | 127 | 128 | 129 | ${field_html} 130 | 131 | 132 | `; 133 | }).join(''); 134 | 135 | return ` 136 | ${fields_html} 137 | `; 138 | }; 139 | 140 | let bindEventHandlers = () => { 141 | let elements = document.querySelectorAll('.jd-bg-settings .jd-bg-setting[data-property]'); 142 | 143 | elements.forEach(element => { 144 | let property = element.dataset.property; 145 | 146 | if (property == BG_IMAGE) { 147 | element.addEventListener('click', () => openAssetModal(property)); 148 | let previewClose = document.querySelector(`.jd-bg-settings .jd-bg-setting.${property}-preview #gjs-sm-close svg`); 149 | 150 | previewClose.addEventListener('click', e => setSelectedComponentStyle(property)); 151 | } else { 152 | element.addEventListener('change', function (e) { 153 | setSelectedComponentStyle(property, this.value); 154 | }); 155 | } 156 | }); 157 | 158 | }; 159 | 160 | let openAssetModal = (property) => { 161 | let am = editor.AssetManager; 162 | let oldContent = modal.getContentEl().childNodes[1] || ''; 163 | 164 | am.open({ 165 | types: ['image'], 166 | select(asset, complete) { 167 | am.close(); 168 | 169 | setModalContent(oldContent); 170 | 171 | setSelectedComponentStyle(property, asset.getSrc()); 172 | } 173 | }); 174 | }; 175 | 176 | let setSelectedComponentStyle = (property, value) => { 177 | let styles = editor.getSelected().getStyle(); 178 | 179 | if (property == BG_IMAGE) { 180 | 181 | let previewContainer = document.querySelector(`.jd-bg-settings .jd-bg-setting.${property}-preview`); 182 | let preview = previewContainer.firstElementChild; 183 | 184 | if (value) { 185 | value = `url(${value})`; 186 | 187 | previewContainer.style.display = 'block'; 188 | } else { 189 | previewContainer.style.display = 'none'; 190 | } 191 | 192 | preview.style.backgroundImage = value || null; 193 | } 194 | 195 | if (value) { 196 | styles[property] = value; 197 | } else { 198 | delete styles[property]; 199 | } 200 | 201 | editor.getSelected().setStyle(styles); 202 | }; 203 | 204 | editor.on('component:selected', () => { 205 | const component = editor.getSelected(); 206 | const toolbar = component.get('toolbar'); 207 | 208 | const commandExists = toolbar.some(item => item.command === COMMAND_ID); 209 | 210 | // if it doesn't already exist, add it 211 | if (!commandExists && !component.is('image') && component.get('tagName') !== 'body') { 212 | let tool = { 213 | attributes: { 'class': TOOL_ICON }, 214 | command: COMMAND_ID 215 | }; 216 | 217 | toolbar.splice(-2, 0, tool); 218 | 219 | component.set('toolbar', toolbar); 220 | } 221 | }); 222 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/background-image/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/code-editor/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/code-editor/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/code-editor/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Code Editor 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/code-editor/README.md: -------------------------------------------------------------------------------- 1 | # Code Editor 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['code-editor'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `code-editor` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/code-editor` 63 | * NPM 64 | * `npm i code-editor` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/code-editor.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'code-editor'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/code-editor.git 120 | $ cd code-editor 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/code-editor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "code-editor", 3 | "version": "1.0.0", 4 | "description": "Code Editor", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/code-editor.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/code-editor/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | const options = { 3 | btn_icon: 'fa fa-edit', 4 | btn_title: 'Edit code.', 5 | model: { 6 | title: 'Edit code', 7 | message: 'Code chagnes Applied.', 8 | btn_text: 'Save', 9 | }, 10 | ...opts 11 | }; 12 | 13 | let stylePrefix = editor.getConfig().stylePrefix; 14 | let modal = editor.Modal; 15 | let codeViewer = editor.CodeManager.getViewer('CodeMirror').clone(); 16 | 17 | let container = document.createElement('div'); 18 | let btnEdit = document.createElement('button'); 19 | 20 | codeViewer.set({ 21 | codeName: 'htmlmixed', 22 | readOnly: 0, 23 | theme: 'hopscotch', 24 | autoBeautify: true, 25 | autoCloseTags: true, 26 | autoCloseBrackets: true, 27 | lineWrapping: true, 28 | styleActiveLine: true, 29 | smartIndent: true, 30 | indentWithTabs: true 31 | }); 32 | 33 | btnEdit.innerHTML = options.model.btn_text; 34 | btnEdit.style.float = 'right'; 35 | btnEdit.style.backgroundColor = '#090'; 36 | btnEdit.className = stylePrefix + 'btn-prim ' + stylePrefix + 'btn-import'; 37 | btnEdit.onclick = function () { 38 | let html = (codeViewer.editor.getValue() || '').trim(); 39 | let css = editor.getCss(); 40 | 41 | editor.DomComponents.getWrapper().set('content', ''); 42 | editor.setComponents(html); 43 | editor.setStyle(css); 44 | 45 | modal.close(); 46 | 47 | editor.runCommand('notify',{ 48 | type: 'info', 49 | title: 'Success', 50 | message: options.model.message, 51 | }) 52 | }; 53 | 54 | editor.Commands.add('html-edit', { 55 | run: function (editor, sender) { 56 | sender && sender.set('active', 0); 57 | var viewer = codeViewer.editor; 58 | modal.setTitle(options.model.title); 59 | if (!viewer) { 60 | let txtarea = document.createElement('textarea'); 61 | container.appendChild(txtarea); 62 | container.appendChild(btnEdit); 63 | codeViewer.init(txtarea); 64 | viewer = codeViewer.editor; 65 | } 66 | 67 | modal.setContent(''); 68 | modal.setContent(container); 69 | 70 | codeViewer.setContent(editor.getHtml()); 71 | 72 | modal.open(); 73 | viewer.refresh(); 74 | } 75 | }); 76 | 77 | editor.Panels.addButton('options', { 78 | id: 'edit', 79 | className: options.btn_icon, 80 | command: 'html-edit', 81 | attributes: { 82 | title: options.btn_title 83 | } 84 | }); 85 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/code-editor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-font-family/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-font-family/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-font-family/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Custom Font Family 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-font-family/README.md: -------------------------------------------------------------------------------- 1 | # Custom Font Family 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['custom-font-family'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `custom-font-family` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/custom-font-family` 63 | * NPM 64 | * `npm i custom-font-family` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/custom-font-family.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'custom-font-family'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/custom-font-family.git 120 | $ cd custom-font-family 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-font-family/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "custom-font-family", 3 | "version": "1.0.0", 4 | "description": "Custom Font Family", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/custom-font-family.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-font-family/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | const options = { 3 | fonts: [], 4 | ...opts 5 | }; 6 | 7 | let fonts = options.fonts; 8 | 9 | editor.on('load', () => { 10 | try{ 11 | if (!fonts || !Array.isArray(fonts)) { 12 | fonts = []; 13 | } 14 | 15 | fonts.push({ 16 | value: '', 17 | name: 'Unset', 18 | prepend: true, 19 | }); 20 | 21 | let fontProperty = editor.StyleManager.getProperty('typography', 'font-family'); 22 | if(!fontProperty) return; 23 | 24 | let options = fontProperty.getOptions(); 25 | 26 | fonts.forEach(font => { 27 | if (typeof font === 'string' || font instanceof String) { 28 | font = { 29 | name: font, 30 | value: font, 31 | }; 32 | } 33 | 34 | if (typeof font.value === 'undefined') { 35 | console.error('Invalid font', font) 36 | return; 37 | } 38 | 39 | options[font.prepend ? 'unshift' : 'push']({ 40 | id: font.value, 41 | label: font.name || font.value, 42 | }); 43 | }) 44 | 45 | fontProperty.setOptions(options); 46 | styleManager.render(); 47 | }catch(e){ 48 | 49 | } 50 | }) 51 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-font-family/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-types/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-types/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-types/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Custom Types 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-types/README.md: -------------------------------------------------------------------------------- 1 | # Custom Types 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['custom-types'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `custom-types` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/custom-types` 63 | * NPM 64 | * `npm i custom-types` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/custom-types.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'custom-types'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/custom-types.git 120 | $ cd custom-types 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "custom-types", 3 | "version": "1.0.0", 4 | "description": "Custom Types", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/custom-types.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-types/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | editor.BlockManager.add("iframe", { 3 | category: 'Basic', 4 | label: "iframe", 5 | type: "iframe", 6 | content: " ", 7 | selectable: true, 8 | attributes: { class: 'fa fa-file' }, 9 | }); 10 | 11 | editor.DomComponents.addType("iframe", { 12 | isComponent: el => el.tagName === "IFRAME", 13 | model: { 14 | defaults: { 15 | type: "iframe", 16 | traits: [ 17 | { 18 | type: "text", 19 | label: "src", 20 | name: "src" 21 | } 22 | ] 23 | } 24 | } 25 | }); 26 | 27 | editor.DomComponents.addType('image', { 28 | isComponent: el => el.tagName == 'IMG', 29 | model: { 30 | defaults: { 31 | traits: [ 32 | { 33 | name: 'src', 34 | placeholder: 'Insert image url here.', 35 | }, 36 | { 37 | type: 'button', 38 | text: 'Choose Image', 39 | full: true, // Full width button 40 | command: function (editor) { 41 | editor.getSelected().trigger('active') 42 | }, 43 | 44 | }, 45 | 'alt', 46 | ], 47 | }, 48 | }, 49 | }); 50 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/custom-types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/device-buttons/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/device-buttons/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/device-buttons/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Device Buttons 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/device-buttons/README.md: -------------------------------------------------------------------------------- 1 | # Device Buttons 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['device-buttons'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `device-buttons` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/device-buttons` 63 | * NPM 64 | * `npm i device-buttons` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/device-buttons.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'device-buttons'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/device-buttons.git 120 | $ cd device-buttons 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/device-buttons/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "device-buttons", 3 | "version": "1.0.0", 4 | "description": "Device Buttons", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/device-buttons.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/device-buttons/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | editor.getConfig().showDevices = 0; 3 | editor.Panels.addPanel({ 4 | id: 'devices-c', 5 | buttons: [ 6 | { 7 | id: 'set-device-desktop', 8 | className: 'fa fa-desktop', 9 | attributes: { 10 | title: 'Desktop', 11 | }, 12 | command: e => e.setDevice('Desktop'), 13 | }, 14 | { 15 | id: 'set-device-tablet', 16 | className: 'fa fa-tablet', 17 | attributes: { 18 | title: 'Tablet', 19 | }, 20 | command: e => e.setDevice('Tablet'), 21 | }, 22 | { 23 | id: 'set-device-mobile', 24 | className: 'fa fa-mobile', 25 | attributes: { 26 | title: 'Mobile', 27 | }, 28 | command: e => e.setDevice('Mobile portrait'), 29 | }, 30 | ] 31 | }); 32 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/device-buttons/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/extra-buttons/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/extra-buttons/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/extra-buttons/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Extra Buttons 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/extra-buttons/README.md: -------------------------------------------------------------------------------- 1 | # Extra Buttons 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['extra-buttons'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `extra-buttons` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/extra-buttons` 63 | * NPM 64 | * `npm i extra-buttons` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/extra-buttons.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'extra-buttons'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/extra-buttons.git 120 | $ cd extra-buttons 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/extra-buttons/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "extra-buttons", 3 | "version": "1.0.0", 4 | "description": "Extra Buttons", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/extra-buttons.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/extra-buttons/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | editor.Panels.addButton('options', [ 3 | { 4 | id: 'undo', 5 | className: 'fa fa-undo', 6 | attributes: { 7 | title: 'Undo', 8 | }, 9 | command: e => e.runCommand('core:undo'), 10 | }, 11 | { 12 | id: 'redo', 13 | className: 'fa fa-repeat', 14 | attributes: { 15 | title: 'Redo', 16 | }, 17 | command: e => e.runCommand('core:redo'), 18 | }, 19 | { 20 | id: 'canvas-clear', 21 | className: 'fa fa-trash', 22 | attributes: { 23 | title: 'Clear Canvas', 24 | }, 25 | command: e => { 26 | if(confirm('Are you sure to clean the canvas?')) { 27 | e.DomComponents.clear(); 28 | setTimeout(() => localStorage.clear(), 0) 29 | } 30 | }, 31 | }, 32 | ]); 33 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/extra-buttons/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/image-editor/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/image-editor/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/image-editor/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Image Editor 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/image-editor/README.md: -------------------------------------------------------------------------------- 1 | # Image Editor 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['image-editor'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `image-editor` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/image-editor` 63 | * NPM 64 | * `npm i image-editor` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/image-editor.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'image-editor'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/image-editor.git 120 | $ cd image-editor 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/image-editor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "image-editor", 3 | "version": "1.0.0", 4 | "description": "Image Editor", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/image-editor.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/image-editor/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, options = {}) => { 2 | const opts = { 3 | ...{ 4 | proxy_url : null, 5 | 6 | proxy_url_input: 'file', 7 | 8 | // TOAST UI's configurations 9 | // http://nhnent.github.io/tui.image-editor/latest/ImageEditor.html 10 | config: { 11 | includeUI: { 12 | initMenu: 'filter', 13 | } 14 | }, 15 | 16 | // Pass the editor constructor. By default, the `tui.ImageEditor` will be called 17 | constructor: '', 18 | 19 | // Label for the image editor (used in the modal) 20 | labelImageEditor: 'Image Editor', 21 | 22 | // Label used on the apply button 23 | labelApply: 'Apply', 24 | 25 | // Default editor height 26 | height: '650px', 27 | 28 | // Default editor width 29 | width: '100%', 30 | 31 | // Id to use to create the image editor command 32 | commandId: 'tui-image-editor', 33 | 34 | // Icon used in the component toolbar 35 | toolbarIcon: ` 36 | 37 | 38 | `, 39 | 40 | // Hide the default editor header 41 | hideHeader: 1, 42 | 43 | // By default, GrapesJS takes the modified image, adds it to the Asset Manager and update the target. 44 | // If you need some custom logic you can use this custom 'onApply' function 45 | // eg. 46 | // onApply: (imageEditor, imageModel) => { 47 | // const dataUrl = imageEditor.toDataURL(); 48 | // editor.AssetManager.add({ src: dataUrl }); // Add it to Assets 49 | // imageModel.set('src', dataUrl); // Update the image component 50 | // } 51 | onApply: 0, 52 | 53 | // If no custom `onApply` is passed and this option is `true`, the result image will be added to assets 54 | addToAssets: 1, 55 | 56 | // If no custom `onApply` is passed, on confirm, the edited image, will be passed to the AssetManager's 57 | // uploader and the result (eg. instead of having the dataURL you'll have the URL) will be 58 | // passed to the default `onApply` process (update target, etc.) 59 | upload: 1, 60 | 61 | // The apply button (HTMLElement) will be passed as an argument to this function, once created. 62 | // This will allow you a higher customization. 63 | onApplyButton: () => { }, 64 | 65 | // The TOAST UI editor isn't compiled with icons, so generally, you should download them and indicate 66 | // the local path in the `includeUI.theme` configurations. 67 | // Use this option to change them or set it to `false` to keep what is come in `includeUI.theme` 68 | // By default, the plugin will try to use the editor's remote icons (which involves a cross-origin async 69 | // request, indicated as unsafe by most of the browsers) 70 | icons: { 71 | 'menu.normalIcon.path': `${options.dist_path}/svg/icon-d.svg`, 72 | 'menu.activeIcon.path': `${options.dist_path}/svg/icon-b.svg`, 73 | 'menu.disabledIcon.path': `${options.dist_path}/svg/icon-a.svg`, 74 | 'menu.hoverIcon.path': `${options.dist_path}/svg/icon-c.svg`, 75 | 'submenu.normalIcon.path': `${options.dist_path}/svg/icon-d.svg`, 76 | 'submenu.activeIcon.path': `${options.dist_path}/svg/icon-c.svg`, 77 | }, 78 | 79 | // Scripts to load dynamically in case no TOAST UI editor instance was found 80 | script: [ 81 | 'https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.7/fabric.js', 82 | 'https://uicdn.toast.com/tui.code-snippet/v1.5.0/tui-code-snippet.min.js', 83 | 'https://uicdn.toast.com/tui-color-picker/v2.2.0/tui-color-picker.min.js', 84 | 'https://uicdn.toast.com/tui-image-editor/v3.4.0/tui-image-editor.js' 85 | ], 86 | 87 | // In case the script is loaded this style will be loaded too 88 | style: [ 89 | 'https://uicdn.toast.com/tui-color-picker/v2.2.0/tui-color-picker.min.css', 90 | 'https://uicdn.toast.com/tui-image-editor/v3.4.0/tui-image-editor.min.css' 91 | ], 92 | }, ...options 93 | }; 94 | 95 | const { script, style, height, width, hideHeader, icons, onApply, upload, addToAssets, commandId } = opts; 96 | const getConstructor = () => opts.constructor || (window.tui && window.tui.ImageEditor); 97 | let constr = getConstructor(); 98 | 99 | // Dynamic loading of the image editor scripts and styles 100 | if (!constr && script) { 101 | const { head } = document; 102 | const scripts = Array.isArray(script) ? [...script] : [script]; 103 | const styles = Array.isArray(style) ? [...style] : [style]; 104 | const appendStyle = styles => { 105 | if (styles.length) { 106 | const link = document.createElement('link'); 107 | link.href = styles.shift(); 108 | link.rel = 'stylesheet'; 109 | head.appendChild(link); 110 | appendStyle(styles); 111 | } 112 | } 113 | const appendScript = scripts => { 114 | if (scripts.length) { 115 | const scr = document.createElement('script'); 116 | scr.src = scripts.shift(); 117 | scr.onerror = scr.onload = appendScript.bind(null, scripts); 118 | head.appendChild(scr); 119 | } else { 120 | constr = getConstructor(); 121 | } 122 | } 123 | appendStyle(styles); 124 | appendScript(scripts); 125 | } 126 | 127 | // Update image component toolbar 128 | const domc = editor.DomComponents; 129 | const typeImage = domc.getType('image').model; 130 | domc.addType('image', { 131 | model: { 132 | initToolbar() { 133 | typeImage.prototype.initToolbar.apply(this, arguments); 134 | const tb = this.get('toolbar'); 135 | const tbExists = tb.some(item => item.command === commandId); 136 | 137 | if (!tbExists) { 138 | tb.unshift({ 139 | command: commandId, 140 | label: opts.toolbarIcon, 141 | }); 142 | this.set('toolbar', tb); 143 | } 144 | } 145 | } 146 | }) 147 | 148 | // Add the image editor command 149 | editor.Commands.add(commandId, { 150 | run(ed, s, options = {}) { 151 | const { id } = this; 152 | 153 | if (!constr) { 154 | ed.log('TOAST UI Image editor not found', { 155 | level: 'error', 156 | ns: commandId, 157 | }); 158 | return ed.stopCommand(id); 159 | } 160 | 161 | this.editor = ed; 162 | this.target = options.target || ed.getSelected(); 163 | const content = this.createContent(); 164 | const title = opts.labelImageEditor; 165 | const btn = content.children[1]; 166 | ed.Modal.open({ title, content }) 167 | .getModel().once('change:open', () => ed.stopCommand(id)); 168 | this.imageEditor = new constr(content.children[0], this.getEditorConfig()); 169 | ed.getModel().setEditing(1); 170 | btn.onclick = () => this.applyChanges(); 171 | opts.onApplyButton(btn); 172 | }, 173 | 174 | stop(ed) { 175 | const { imageEditor } = this; 176 | imageEditor && imageEditor.destroy(); 177 | ed.getModel().setEditing(0); 178 | }, 179 | 180 | getEditorConfig() { 181 | const config = { ...opts.config }; 182 | let path = this.target.get('src'); 183 | 184 | if ( opts.proxy_url && !path.startsWith('data:')){ 185 | path = `${opts.proxy_url}?${opts.proxy_url_input}=${encodeURI(path)}` 186 | } 187 | 188 | if (!config.includeUI) config.includeUI = {}; 189 | config.includeUI = { 190 | theme: {}, 191 | ...config.includeUI, 192 | loadImage: { path, name: 1 }, 193 | uiSize: { height, width }, 194 | }; 195 | if (hideHeader) config.includeUI.theme['header.display'] = 'none'; 196 | if (icons) config.includeUI.theme = { 197 | ...config.includeUI.theme, 198 | ...icons, 199 | } 200 | 201 | return config; 202 | }, 203 | 204 | createContent() { 205 | const content = document.createElement('div'); 206 | content.style = 'position: relative'; 207 | content.innerHTML = ` 208 | 209 | 220 | ${opts.labelApply} 221 | 222 | `; 223 | 224 | return content; 225 | }, 226 | 227 | applyChanges() { 228 | const { imageEditor, target, editor } = this; 229 | const { AssetManager } = editor; 230 | 231 | if (onApply) { 232 | onApply(imageEditor, target); 233 | } else { 234 | if (imageEditor.getDrawingMode() === 'CROPPER') { 235 | imageEditor.crop(imageEditor.getCropzoneRect()).then(() => { 236 | this.uploadImage(imageEditor, target, AssetManager); 237 | }); 238 | } else { 239 | this.uploadImage(imageEditor, target, AssetManager); 240 | } 241 | } 242 | }, 243 | 244 | uploadImage(imageEditor, target, am) { 245 | const dataURL = imageEditor.toDataURL(); 246 | if (upload) { 247 | const file = this.dataUrlToBlob(dataURL); 248 | am.FileUploader().uploadFile({ 249 | dataTransfer: { files: [file] } 250 | }, res => { 251 | const obj = res && res.data && res.data[0]; 252 | const src = obj && (typeof obj === 'string' ? obj : obj.src); 253 | src && this.applyToTarget(src); 254 | }); 255 | } else { 256 | addToAssets && am.add({ 257 | src: dataURL, 258 | name: (target.get('src') || '').split('/').pop(), 259 | }); 260 | this.applyToTarget(dataURL); 261 | } 262 | }, 263 | 264 | applyToTarget(result) { 265 | this.target.set({ src: result }); 266 | this.editor.Modal.close(); 267 | }, 268 | 269 | dataUrlToBlob(dataURL) { 270 | const data = dataURL.split(','); 271 | const byteStr = window.atob(data[1]); 272 | const type = data[0].split(':')[1].split(';')[0]; 273 | const ab = new ArrayBuffer(byteStr.length); 274 | const ia = new Uint8Array(ab); 275 | 276 | for (let i = 0; i < byteStr.length; i++) { 277 | ia[i] = byteStr.charCodeAt(i); 278 | } 279 | 280 | return new Blob([ab], { type }); 281 | }, 282 | }); 283 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/image-editor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/linkable-image/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/linkable-image/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/linkable-image/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Linkable Image 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/linkable-image/README.md: -------------------------------------------------------------------------------- 1 | # Linkable Image 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['linkable-image'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `linkable-image` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/linkable-image` 63 | * NPM 64 | * `npm i linkable-image` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/linkable-image.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'linkable-image'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/linkable-image.git 120 | $ cd linkable-image 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/linkable-image/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linkable-image", 3 | "version": "1.0.0", 4 | "description": "Linkable Image", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/linkable-image.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/linkable-image/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | const LINK_COMMAND_ID = 'jd-add-link-image'; 3 | const UNLINK_COMMAND_ID = 'jd-remove-link-image'; 4 | const LINK_TOOL_ICON = 'fa fa-link'; 5 | const UNLINK_TOOL_ICON = 'fa fa-unlink'; 6 | 7 | editor.on('component:selected', () => { 8 | const component = editor.getSelected(); 9 | if(!component) return; 10 | 11 | const toolbar = component.get('toolbar'); 12 | 13 | if (component.is('image')) { 14 | let command, icon; 15 | 16 | if(component.closest('a') === 0){ 17 | icon = LINK_TOOL_ICON; 18 | command = LINK_COMMAND_ID; 19 | }else{ 20 | let parent = component.parent(); 21 | if(parent.get('tagName') == 'a' && parent.components().length == 1){ 22 | icon = UNLINK_TOOL_ICON; 23 | command = UNLINK_COMMAND_ID; 24 | } 25 | } 26 | 27 | if(command && !toolbar.some(item => item.command === command)){ 28 | toolbar.splice(-2, 0, { 29 | attributes: { 'class': icon }, 30 | command 31 | }); 32 | 33 | component.set('toolbar', toolbar); 34 | } 35 | } 36 | }); 37 | 38 | editor.Commands.add(LINK_COMMAND_ID, { 39 | run: (editor, sender) => { 40 | let component = editor.getSelected(); 41 | if(!component || component.closest('a') !== 0) return; 42 | 43 | let toolbar = component.get('toolbar'); 44 | let toolIndex = toolbar.findIndex(item => item.command === LINK_COMMAND_ID) 45 | toolbar.splice(toolIndex, 1); 46 | 47 | component.set('toolbar', toolbar); 48 | let new_component = component.replaceWith(''); 49 | new_component.components(component = component.clone()) 50 | 51 | editor.select(); 52 | editor.select(new_component); 53 | 54 | document.querySelector('.gjs-pn-panels .gjs-pn-views .gjs-pn-buttons [title="Settings"]').click(); 55 | let hrefInput = document.querySelector('.gjs-pn-panels .gjs-pn-views-container .gjs-trt-trait__wrp-href input'); 56 | 57 | hrefInput.focus(); 58 | hrefInput.select(); 59 | }, 60 | }); 61 | 62 | editor.Commands.add(UNLINK_COMMAND_ID, { 63 | run: (editor, sender) => { 64 | let component = editor.getSelected(); 65 | if(!component) return; 66 | 67 | let parent = component.parent(); 68 | if(!parent || !(parent.get('tagName') == 'a' && parent.components().length == 1)) return; 69 | 70 | if(!confirm('Are you sure?')) return; 71 | 72 | let toolbar = component.get('toolbar'); 73 | let toolIndex = toolbar.findIndex(item => item.command === UNLINK_COMMAND_ID) 74 | toolbar.splice(toolIndex, 1); 75 | 76 | component.set('toolbar', toolbar); 77 | parent.replaceWith(component = component.clone()); 78 | editor.select() 79 | editor.select(component) 80 | }, 81 | }); 82 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/linkable-image/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/loader/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/loader/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/loader/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Loader 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/loader/README.md: -------------------------------------------------------------------------------- 1 | # Loader 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['loader'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `loader` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/loader` 63 | * NPM 64 | * `npm i loader` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/loader.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'loader'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/loader.git 120 | $ cd loader 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "loader", 3 | "version": "1.0.0", 4 | "description": "Loader", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/loader.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/loader/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | const options = { 3 | id: 'loader', 4 | container: 'body', 5 | styles: { 6 | "left": "0", 7 | "top": "0", 8 | "background-color": "white", 9 | "opacity": "0.7", 10 | "position": "absolute", 11 | "align-items": "center", 12 | "justify-content": "center", 13 | "width": "100%", 14 | "height": "100%", 15 | "font-size": "36pt", 16 | "display": "flex", 17 | "z-index": "100", 18 | }, 19 | ...opts 20 | }; 21 | 22 | let container = document.querySelector(options.container); 23 | let loader = document.getElementById('loader'); 24 | 25 | if (!loader) { 26 | loader = document.createElement('div'); 27 | loader.id = 'loader'; 28 | for (var style in options.styles) { 29 | loader.style[style] = options.styles[style]; 30 | } 31 | loader.innerHTML = ' '; 32 | } 33 | 34 | let commands = editor.Commands; 35 | commands.add('show-loader', (editor, sender, opts) => { 36 | if (container) { 37 | container.append(loader); 38 | container.style.position = 'relative'; 39 | } 40 | }) 41 | 42 | commands.add('hide-loader', (editor, sender, opts) => { 43 | if (container) { 44 | container.style.position = ''; 45 | let loaderElement = document.querySelector(`${options.container} #loader`); 46 | loaderElement && loaderElement.remove(); 47 | } 48 | }) 49 | 50 | editor.on('storage:start', () => { 51 | editor.runCommand('show-loader') 52 | }) 53 | 54 | editor.on('storage:end', () => { 55 | editor.runCommand('hide-loader') 56 | }) 57 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/loader/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/notifications/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/notifications/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/notifications/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Notifications 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/notifications/README.md: -------------------------------------------------------------------------------- 1 | # Notifications 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['notifications'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `notifications` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/notifications` 63 | * NPM 64 | * `npm i notifications` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/notifications.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'notifications'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/notifications.git 120 | $ cd notifications 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/notifications/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "notifications", 3 | "version": "1.0.0", 4 | "description": "Notifications", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/notifications.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/notifications/src/index.js: -------------------------------------------------------------------------------- 1 | import toastr from 'toastr'; 2 | 3 | export default (editor, opts) => { 4 | editor.Commands.add('notify', (editor, sender, opts) => { 5 | toastr[opts.type](opts.message, opts.title) 6 | }); 7 | } -------------------------------------------------------------------------------- /src/resources/js/plugins/notifications/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/plugins-loader/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/plugins-loader/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/plugins-loader/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Plugins Loader 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/plugins-loader/README.md: -------------------------------------------------------------------------------- 1 | # Plugins Loader 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['plugins-loader'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `plugins-loader` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/plugins-loader` 63 | * NPM 64 | * `npm i plugins-loader` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/plugins-loader.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'plugins-loader'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/plugins-loader.git 120 | $ cd plugins-loader 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/plugins-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "plugins-loader", 3 | "version": "1.0.0", 4 | "description": "Plugins Loader", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/plugins-loader.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/plugins-loader/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, plugins = []) => { 2 | if(!plugins || !Array.isArray(plugins) || !plugins.length) return; 3 | 4 | plugins.forEach(plugin => { 5 | try { 6 | let callback = window.grapesjs.plugins.get(plugin.name); 7 | 8 | if(!callback){ 9 | callback = (window[plugin.name] || {}).default; 10 | } 11 | 12 | if(!callback){ 13 | console.error(`The defination for plugin '${plugin.name}' not found.`); 14 | return; 15 | } 16 | 17 | callback(editor, plugin.options); 18 | } catch (e) { 19 | console.error(e); 20 | } 21 | }); 22 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/plugins-loader/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/save-button/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/save-button/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/save-button/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Save Button 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/save-button/README.md: -------------------------------------------------------------------------------- 1 | # Save Button 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['save-button'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `save-button` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/save-button` 63 | * NPM 64 | * `npm i save-button` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/save-button.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'save-button'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/save-button.git 120 | $ cd save-button 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/save-button/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "save-button", 3 | "version": "1.0.0", 4 | "description": "Save Button", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/save-button.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/save-button/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | editor.Panels.addButton('options', { 3 | id: 'save', 4 | className: 'fa fa-save', 5 | command(editor) { 6 | editor.store(res => { 7 | editor.runCommand('notify',{ 8 | type: 'success', 9 | title: 'Success', 10 | message: "Page Saved Successfully" 11 | }) 12 | }); 13 | }, 14 | attributes: { 15 | title: 'Save' 16 | } 17 | }); 18 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/save-button/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/style-editor/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/style-editor/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/style-editor/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Style Editor 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/style-editor/README.md: -------------------------------------------------------------------------------- 1 | # Style Editor 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['style-editor'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `style-editor` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/style-editor` 63 | * NPM 64 | * `npm i style-editor` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/style-editor.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'style-editor'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/style-editor.git 120 | $ cd style-editor 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/style-editor/index.scss: -------------------------------------------------------------------------------- 1 | .gjs-pn-views-container{ 2 | z-index: 2; 3 | 4 | .jd-style-editor{ 5 | margin-top: 4px; 6 | 7 | .jd-expand-handle{ 8 | position: absolute; 9 | left: 7px; 10 | font-size: 22px; 11 | padding: 6px; 12 | cursor: pointer; 13 | 14 | &.active{ 15 | background-color: rgba(0,0,0,.15); 16 | box-shadow: 0 0 3px rgb(0 0 0 / 25%) inset; 17 | } 18 | } 19 | 20 | .jd-field-containter{ 21 | padding: 0 5px; 22 | margin-top: 12px; 23 | 24 | .gjs-field-styles{ 25 | .gjs-input-holder{ 26 | textarea{ 27 | min-height: 300px; 28 | } 29 | 30 | .CodeMirror{ 31 | .CodeMirror-code{ 32 | .CodeMirror-line{ 33 | text-align: left; 34 | // padding-left: 30px; 35 | } 36 | } 37 | } 38 | 39 | i{ 40 | position: absolute; 41 | left: 0px; 42 | bottom: 0px; 43 | width: 20px !important; 44 | height: 20px !important; 45 | cursor: ne-resize; 46 | resize: auto; 47 | overflow: auto; 48 | direction: rtl; 49 | z-index: 4; 50 | } 51 | } 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/resources/js/plugins/style-editor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "style-editor", 3 | "version": "1.0.0", 4 | "description": "Style Editor", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/style-editor.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/style-editor/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | const COMMAND_ID = 'css-edit'; 3 | let div, codeViewer, timer; 4 | 5 | let setCanvasWidth = w => { 6 | const canvas = document.querySelector(".gjs-cv-canvas"); 7 | const panel = document.querySelector(".gjs-pn-views-container"); 8 | 9 | let canvas_width = w; 10 | let panel_width = 100 - w; 11 | 12 | canvas.style.width = `${canvas_width}%`; 13 | panel.style.width = `${panel_width}%`; 14 | }; 15 | 16 | let updateCodeViewerContent = () => codeViewer && codeViewer.setContent(editor.getCss()); 17 | 18 | let setEventListners = (div) => { 19 | div.querySelector('.jd-expand-handle').addEventListener('click', function(e){ 20 | let handle = e.target; 21 | 22 | setCanvasWidth(handle.classList.contains('active') ? 85 : 50); 23 | handle.classList.toggle('active') 24 | }); 25 | 26 | codeViewer.editor.on('changes', (e, changes) => { 27 | if(changes.length == 1 && changes[0].origin != "setValue"){ 28 | clearTimeout(timer); 29 | 30 | timer = setTimeout(() => { 31 | editor.setStyle(e.getValue()); 32 | }, 500); 33 | } 34 | }) 35 | 36 | function resize(e){ 37 | const container = document.querySelector(".gjs-pn-views-container"); 38 | const canvas = document.querySelector(".gjs-cv-canvas"); 39 | const item = div.querySelector(".CodeMirror"); 40 | 41 | let height = e.pageY - item.getBoundingClientRect().top - 4; 42 | let container_width = 100 - Math.ceil(e.clientX / window.innerWidth * 100); 43 | let canvas_width = 100 - container_width; 44 | 45 | item.style.width = `100%`; 46 | if(height >= 300){ 47 | item.style.height = `${height}px`; 48 | } 49 | 50 | if(container_width >= 15){ 51 | canvas.style.width = `${canvas_width}%`; 52 | container.style.width = `${container_width}%`; 53 | } 54 | } 55 | 56 | div.querySelector('.gjs-input-holder i').addEventListener("mousedown", function(e){ 57 | document.addEventListener("mousemove", resize, false); 58 | }, false); 59 | 60 | document.addEventListener("mouseup", function(){ 61 | document.removeEventListener("mousemove", resize, false); 62 | }, false); 63 | }; 64 | 65 | let initCodeViewer = () => { 66 | if(div) return; 67 | 68 | codeViewer = editor.CodeManager.getViewer('CodeMirror').clone(); 69 | 70 | div = document.createElement('div') 71 | div.classList.add('jd-style-editor'); 72 | div.innerHTML= ` 73 | 74 | 75 | Update styles 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | `; 86 | 87 | codeViewer.set({ 88 | codeName: 'css', 89 | readOnly: 0, 90 | theme: 'hopscotch', 91 | autoBeautify: true, 92 | autoCloseTags: true, 93 | autoCloseBrackets: true, 94 | lineWrapping: true, 95 | styleActiveLine: true, 96 | smartIndent: true, 97 | indentWithTabs: true, 98 | }); 99 | 100 | codeViewer.init(div.querySelector('.jd-field-containter textarea')); 101 | 102 | setEventListners(div); 103 | 104 | editor 105 | .Panels 106 | .getPanel('views-container') 107 | .set('appendContent', div) 108 | .trigger('change:appendContent'); 109 | }; 110 | 111 | editor.on('update', updateCodeViewerContent); 112 | 113 | editor.Commands.add(COMMAND_ID, { 114 | run(editor, sender){ 115 | initCodeViewer(); 116 | updateCodeViewerContent(); 117 | div.style.display = 'block'; 118 | }, 119 | 120 | stop(editor, sender){ 121 | if(div){ 122 | setCanvasWidth(85); 123 | div.querySelector('.jd-expand-handle').classList.remove('active') 124 | 125 | div.style.display = 'none'; 126 | } 127 | } 128 | }); 129 | 130 | editor.Panels.addButton('views', { 131 | id: COMMAND_ID, 132 | className: 'fa fa-css3', 133 | command: COMMAND_ID, 134 | attributes: { 135 | title: 'Modify styles' 136 | }, 137 | active: false, 138 | }); 139 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/style-editor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/js/plugins/templates/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | private/ 3 | /locale 4 | node_modules/ 5 | *.log 6 | _index.html 7 | dist/ 8 | stats.json -------------------------------------------------------------------------------- /src/resources/js/plugins/templates/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.log 3 | *.html 4 | **/tsconfig.json 5 | **/webpack.config.js 6 | node_modules 7 | src -------------------------------------------------------------------------------- /src/resources/js/plugins/templates/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-current Templates 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /src/resources/js/plugins/templates/README.md: -------------------------------------------------------------------------------- 1 | # Templates 2 | 3 | [DEMO](##) 4 | > **Provide a live demo of your plugin** 5 | For a better user engagement create a simple live demo by using services like [JSFiddle](https://jsfiddle.net) [CodeSandbox](https://codesandbox.io) [CodePen](https://codepen.io) and link it here in your README (attaching a screenshot/gif will also be a plus). 6 | To help you in this process here below you will find the necessary HTML/CSS/JS, so it just a matter of copy-pasting on some of those services. After that delete this part and update the link above 7 | 8 | ### HTML 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### JS 18 | ```js 19 | const editor = grapesjs.init({ 20 | container: '#gjs', 21 | height: '100%', 22 | fromElement: true, 23 | storageManager: false, 24 | plugins: ['templates'], 25 | }); 26 | ``` 27 | 28 | ### CSS 29 | ```css 30 | body, html { 31 | margin: 0; 32 | height: 100%; 33 | } 34 | ``` 35 | 36 | 37 | ## Summary 38 | 39 | * Plugin name: `templates` 40 | * Components 41 | * `component-id-1` 42 | * `component-id-2` 43 | * ... 44 | * Blocks 45 | * `block-id-1` 46 | * `block-id-2` 47 | * ... 48 | 49 | 50 | 51 | ## Options 52 | 53 | | Option | Description | Default | 54 | |-|-|- 55 | | `option1` | Description option | `default value` | 56 | 57 | 58 | 59 | ## Download 60 | 61 | * CDN 62 | * `https://unpkg.com/templates` 63 | * NPM 64 | * `npm i templates` 65 | * GIT 66 | * `git clone https://github.com/YOUR-USERNAME/templates.git` 67 | 68 | 69 | 70 | ## Usage 71 | 72 | Directly in the browser 73 | ```html 74 | 75 | 76 | 77 | 78 | 79 | 80 | 90 | ``` 91 | 92 | Modern javascript 93 | ```js 94 | import grapesjs from 'grapesjs'; 95 | import plugin from 'templates'; 96 | import 'grapesjs/dist/css/grapes.min.css'; 97 | 98 | const editor = grapesjs.init({ 99 | container : '#gjs', 100 | // ... 101 | plugins: [plugin], 102 | pluginsOpts: { 103 | [plugin]: { /* options */ } 104 | } 105 | // or 106 | plugins: [ 107 | editor => plugin(editor, { /* options */ }), 108 | ], 109 | }); 110 | ``` 111 | 112 | 113 | 114 | ## Development 115 | 116 | Clone the repository 117 | 118 | ```sh 119 | $ git clone https://github.com/YOUR-USERNAME/templates.git 120 | $ cd templates 121 | ``` 122 | 123 | Install dependencies 124 | 125 | ```sh 126 | $ npm i 127 | ``` 128 | 129 | Start the dev server 130 | 131 | ```sh 132 | $ npm start 133 | ``` 134 | 135 | Build the source 136 | 137 | ```sh 138 | $ npm run build 139 | ``` 140 | 141 | 142 | 143 | ## License 144 | 145 | MIT 146 | -------------------------------------------------------------------------------- /src/resources/js/plugins/templates/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "templates", 3 | "version": "1.0.0", 4 | "description": "Templates", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/YOUR-USERNAME/templates.git" 9 | }, 10 | "scripts": { 11 | "start": "grapesjs-cli serve", 12 | "build": "grapesjs-cli build", 13 | "bump": "npm version patch -m 'Bump v%s'" 14 | }, 15 | "keywords": [ 16 | "grapesjs", 17 | "plugin" 18 | ], 19 | "devDependencies": { 20 | "grapesjs-cli": "^3.0.0" 21 | }, 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/js/plugins/templates/src/index.js: -------------------------------------------------------------------------------- 1 | export default (editor, opts = {}) => { 2 | const options = { 3 | url: null, 4 | ...opts 5 | }; 6 | 7 | if (options.url) { 8 | fetch(options.url) 9 | .then(resp => resp.json()) 10 | .then(data => { 11 | data.forEach(block => { 12 | editor.BlockManager.add('block-' + block.id, block); 13 | }); 14 | }) 15 | .catch(error => { 16 | console.log(error); 17 | }) 18 | } 19 | }; -------------------------------------------------------------------------------- /src/resources/js/plugins/templates/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "sourceMap": true, 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "isolatedModules": true, 21 | "noEmit": false 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/scss/gjs.scss: -------------------------------------------------------------------------------- 1 | @import 'grapesjs/dist/css/grapes.min.css'; 2 | @import 'toastr'; 3 | @import '../js/plugins/background-image'; 4 | @import '../js/plugins/style-editor'; 5 | -------------------------------------------------------------------------------- /src/resources/views/edittor.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Edit {{ $model->editor_page_title }} 10 | 11 | @foreach ($editorConfig->getStyles() as $style) 12 | 13 | @endforeach 14 | 15 | 21 | 76 | 77 | 78 | 79 | 80 | 81 | @foreach ($editorConfig->getScripts() as $script) 82 | 83 | @endforeach 84 | 85 | -------------------------------------------------------------------------------- /src/resources/views/gjs-blocks/example.blade.php: -------------------------------------------------------------------------------- 1 | Example Block -------------------------------------------------------------------------------- /src/resources/views/templates/example.blade.php: -------------------------------------------------------------------------------- 1 | 2 | Example Template 3 | -------------------------------------------------------------------------------- /src/routes/laravel-grapesjs.php: -------------------------------------------------------------------------------- 1 | name('laravel-grapesjs.') 8 | ->middleware(config('laravel-grapesjs.routes.middleware', [])) 9 | ->namespace('Dotlogics\Grapesjs\App\Http\Controllers') 10 | ->group(function(){ 11 | Route::post('asset/store', 'AssetController@store')->name('asset.store'); 12 | Route::get('asset/proxy', 'AssetController@proxy')->name('asset.proxy'); 13 | 14 | Route::get('{model}/{editable}', 'EditorController@editor')->name('model.editor'); 15 | Route::post('{model}/{editable}', 'EditorController@store')->name('model.store'); 16 | 17 | Route::get('{model}/{editable}/templates', 'EditorController@templates')->name('model.templates'); 18 | Route::get('templates', 'EditorController@templates')->name('templates'); 19 | }); 20 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | const mix = require('laravel-mix'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Mix Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Backpack maintainers use mix to: 9 | | - install and update CSS and JS assets; 10 | | - copy everything that needs to be published into src/public 11 | | 12 | | All JS will be bundled into one file (see bundle.js). 13 | | 14 | | How to use (for maintainers only): 15 | | - cd vendor/backpack/crud 16 | | - npm install 17 | | - npm run prod 18 | | (this will also publish the assets for you to test, so no need to do that too) 19 | */ 20 | 21 | // merge all needed JS into a big bundle file 22 | mix.sourceMaps(false, 'source-map').js('src/resources/js', 'dist/assets/editor.js') 23 | .sass('src/resources/scss/gjs.scss','dist/assets/editor.css') 24 | .options({ 25 | processCssUrls: false 26 | }); 27 | 28 | mix.copyDirectory('node_modules/grapesjs/dist/fonts', 'dist/fonts') 29 | mix.copyDirectory('src/resources/js/plugins/image-editor/svg', 'dist/svg') 30 | 31 | 32 | if(!mix.inProduction()){ 33 | // mix.copyDirectory('dist', '../../../public/vendor/laravel-grapesjs') 34 | } --------------------------------------------------------------------------------