Merge branch 'feature/grapejs' into develop
This commit is contained in:
commit
f48041eacd
|
@ -101,6 +101,7 @@ class PageAdminController extends CrudController
|
||||||
->setForm('edit', Type::class, [])
|
->setForm('edit', Type::class, [])
|
||||||
->setForm('filter', FilterType::class)
|
->setForm('filter', FilterType::class)
|
||||||
->setView('form', '@Core/site/page_admin/_form.html.twig')
|
->setView('form', '@Core/site/page_admin/_form.html.twig')
|
||||||
|
->setView('edit', '@Core/site/page_admin/edit.html.twig')
|
||||||
|
|
||||||
->setAction('index', 'new', false)
|
->setAction('index', 'new', false)
|
||||||
->setAction('index', 'show', false)
|
->setAction('index', 'show', false)
|
||||||
|
|
21
src/core/Form/Site/Page/GrapesJsBlockType.php
Normal file
21
src/core/Form/Site/Page/GrapesJsBlockType.php
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Form\Site\Page;
|
||||||
|
|
||||||
|
use App\Core\Form\Type\GrapesJsType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class GrapesJsBlockType extends TextareaBlockType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder->add(
|
||||||
|
'value',
|
||||||
|
GrapesJsType::class,
|
||||||
|
array_merge([
|
||||||
|
'required' => false,
|
||||||
|
'label' => false,
|
||||||
|
], $options['options']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
30
src/core/Form/Type/GrapesJsType.php
Normal file
30
src/core/Form/Type/GrapesJsType.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Form\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
|
|
||||||
|
class GrapesJsType extends TextareaType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||||
|
{
|
||||||
|
if (!isset($view->vars['attr']['data-grapesjs'])) {
|
||||||
|
$view->vars['attr']['data-grapesjs'] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::buildView($view, $form, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getBlockPrefix()
|
||||||
|
{
|
||||||
|
return 'grapesjs';
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ $pagination-active-bg: #343a40 !default;
|
||||||
@import "~@fortawesome/fontawesome-free/css/all.css";
|
@import "~@fortawesome/fontawesome-free/css/all.css";
|
||||||
@import "~flag-icon-css/sass/flag-icon.scss";
|
@import "~flag-icon-css/sass/flag-icon.scss";
|
||||||
@import "~flag-icon-css/sass/flag-icon.scss";
|
@import "~flag-icon-css/sass/flag-icon.scss";
|
||||||
|
@import '~grapesjs/dist/css/grapes.min.css';
|
||||||
|
|
||||||
@for $i from 1 through 100 {
|
@for $i from 1 through 100 {
|
||||||
.miw-#{$i*5} {
|
.miw-#{$i*5} {
|
||||||
|
@ -575,3 +576,12 @@ form {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gjs-editor-cont {
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gjs-one-bg {
|
||||||
|
background: map-get($theme-colors, 'dark-blue');
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ require('./modules/password.js')()
|
||||||
require('./modules/tooltip.js')()
|
require('./modules/tooltip.js')()
|
||||||
require('./modules/tinymce.js')()
|
require('./modules/tinymce.js')()
|
||||||
require('./modules/editorjs.js')()
|
require('./modules/editorjs.js')()
|
||||||
|
require('./modules/grapesjs.js')()
|
||||||
require('./modules/panel.js')()
|
require('./modules/panel.js')()
|
||||||
require('./modules/choices.js')()
|
require('./modules/choices.js')()
|
||||||
require('./modules/checkbox-checker.js')()
|
require('./modules/checkbox-checker.js')()
|
||||||
|
@ -25,3 +26,4 @@ require('./modules/batch.js')()
|
||||||
require('./modules/file-manager.js')()
|
require('./modules/file-manager.js')()
|
||||||
require('./modules/file-picker.js')()
|
require('./modules/file-picker.js')()
|
||||||
require('./modules/analytics.js')()
|
require('./modules/analytics.js')()
|
||||||
|
require('./modules/page.js')()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const $ = require('jquery')
|
const $ = require('jquery')
|
||||||
const EditorJS = require('@editorjs/editorjs')
|
const EditorJS = require('@editorjs/editorjs')
|
||||||
const InlineTools = require('editorjs-inline-tool')
|
const InlineTools = require('editorjs-inline-tool')
|
||||||
const Routing = require('../../../../../../../../friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js')
|
const Routing = require('../../../../../../../../friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js')
|
||||||
const routes = require('../../../../../../../../../public/js/fos_js_routes.json')
|
const routes = require('../../../../../../../../../public/js/fos_js_routes.json')
|
||||||
|
|
||||||
const UnderlineInlineTool = InlineTools.UnderlineInlineTool
|
const UnderlineInlineTool = InlineTools.UnderlineInlineTool
|
||||||
|
@ -84,24 +84,24 @@ const tools = {
|
||||||
bold: {
|
bold: {
|
||||||
class: createGenericInlineTool({
|
class: createGenericInlineTool({
|
||||||
sanitize: {
|
sanitize: {
|
||||||
strong: {},
|
strong: {}
|
||||||
},
|
},
|
||||||
shortcut: 'CMD+B',
|
shortcut: 'CMD+B',
|
||||||
tagName: 'STRONG',
|
tagName: 'STRONG',
|
||||||
toolboxIcon:
|
toolboxIcon:
|
||||||
'<svg class="icon icon--bold" width="12px" height="14px"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#bold"></use></svg>',
|
'<svg class="icon icon--bold" width="12px" height="14px"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#bold"></use></svg>'
|
||||||
}),
|
})
|
||||||
},
|
},
|
||||||
italic: {
|
italic: {
|
||||||
class: createGenericInlineTool({
|
class: createGenericInlineTool({
|
||||||
sanitize: {
|
sanitize: {
|
||||||
em: {},
|
em: {}
|
||||||
},
|
},
|
||||||
shortcut: 'CMD+I',
|
shortcut: 'CMD+I',
|
||||||
tagName: 'EM',
|
tagName: 'EM',
|
||||||
toolboxIcon:
|
toolboxIcon:
|
||||||
'<svg class="icon icon--italic" width="12px" height="14px"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#italic"></use></svg>',
|
'<svg class="icon icon--italic" width="12px" height="14px"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#italic"></use></svg>'
|
||||||
}),
|
})
|
||||||
},
|
},
|
||||||
underline: UnderlineInlineTool
|
underline: UnderlineInlineTool
|
||||||
}
|
}
|
||||||
|
|
106
src/core/Resources/assets/js/modules/grapesjs.js
Normal file
106
src/core/Resources/assets/js/modules/grapesjs.js
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
const $ = require('jquery')
|
||||||
|
const GrapesJs = require('grapesjs')
|
||||||
|
const bootstrap4 = require('grapesjs-blocks-bootstrap4').default
|
||||||
|
|
||||||
|
const makeId = () => {
|
||||||
|
let result = ''
|
||||||
|
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'
|
||||||
|
const charactersLength = characters.length
|
||||||
|
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * charactersLength))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'grapesjs-' + result
|
||||||
|
}
|
||||||
|
|
||||||
|
const doInitEditor = () => {
|
||||||
|
$('textarea[data-grapesjs]').each((i, v) => {
|
||||||
|
const textarea = $(v)
|
||||||
|
const element = textarea.parent().prev()
|
||||||
|
const id = element.attr('id') ? element.attr('id') : makeId()
|
||||||
|
|
||||||
|
element.attr('id', id)
|
||||||
|
|
||||||
|
const editor = GrapesJs.init({
|
||||||
|
container: '#' + id,
|
||||||
|
fromElement: false,
|
||||||
|
height: '900px',
|
||||||
|
width: 'auto',
|
||||||
|
storageManager: {
|
||||||
|
autoload: false
|
||||||
|
},
|
||||||
|
noticeOnUnload: 0,
|
||||||
|
showOffsets: 1,
|
||||||
|
showDevices: false,
|
||||||
|
plugins: ['grapesjs-blocks-bootstrap4'],
|
||||||
|
colorPicker: {
|
||||||
|
appendTo: 'parent',
|
||||||
|
offset: {
|
||||||
|
top: 26,
|
||||||
|
left: -166
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pluginsOpts: {
|
||||||
|
'grapesjs-blocks-bootstrap4': {
|
||||||
|
blocks: {},
|
||||||
|
blockCategories: {},
|
||||||
|
labels: {},
|
||||||
|
gridDevicesPanel: true,
|
||||||
|
formPredefinedActions: [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
canvas: {
|
||||||
|
styles: [
|
||||||
|
'https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css'
|
||||||
|
],
|
||||||
|
scripts: [
|
||||||
|
'https://code.jquery.com/jquery-3.5.1.slim.min.js',
|
||||||
|
'https://unpkg.com/@popperjs/core@2',
|
||||||
|
'https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const deviceManager = editor.DeviceManager
|
||||||
|
|
||||||
|
const devices = [
|
||||||
|
'Extra Small',
|
||||||
|
'Small',
|
||||||
|
'Medium',
|
||||||
|
'Large',
|
||||||
|
'Extra Large',
|
||||||
|
'Desktop',
|
||||||
|
'Tablet',
|
||||||
|
'mobileLandscape',
|
||||||
|
'mobilePortrait'
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const device of devices) {
|
||||||
|
deviceManager.remove(device)
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceManager.add('All', '100%')
|
||||||
|
|
||||||
|
editor.Panels.getPanels().remove('devices-buttons')
|
||||||
|
|
||||||
|
editor.on('update', () => {
|
||||||
|
textarea.val(JSON.stringify(editor.storeData()))
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(textarea.val())
|
||||||
|
|
||||||
|
try {
|
||||||
|
editor.loadData(JSON.parse(textarea.val()))
|
||||||
|
} catch (e) {
|
||||||
|
editor.loadData({ html: '' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
$(() => {
|
||||||
|
doInitEditor()
|
||||||
|
})
|
||||||
|
}
|
41
src/core/Resources/assets/js/modules/page.js
Normal file
41
src/core/Resources/assets/js/modules/page.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
const $ = require('jquery')
|
||||||
|
|
||||||
|
const doExpandCollapse = (stmt) => {
|
||||||
|
stmt = (stmt == 1)
|
||||||
|
|
||||||
|
const button = $('#page-form-expand')
|
||||||
|
const mainForm = $('#page-main-form')
|
||||||
|
const metasForm = $('#page-metas-form')
|
||||||
|
|
||||||
|
mainForm
|
||||||
|
.toggleClass('col-md-8', !stmt)
|
||||||
|
.toggleClass('col-md-12', stmt)
|
||||||
|
|
||||||
|
metasForm
|
||||||
|
.toggleClass('d-none', stmt)
|
||||||
|
|
||||||
|
button
|
||||||
|
.children()
|
||||||
|
.toggleClass('fa-expand-arrows-alt', !stmt)
|
||||||
|
.toggleClass('fa-compress-arrows-alt', stmt)
|
||||||
|
|
||||||
|
localStorage.setItem('pageFormExpandStmt', stmt ? 1 : null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const initExpander = () => {
|
||||||
|
const button = $('#page-form-expand')
|
||||||
|
|
||||||
|
if (button.length) {
|
||||||
|
doExpandCollapse(localStorage.getItem('pageFormExpandStmt'))
|
||||||
|
|
||||||
|
button.click(() => {
|
||||||
|
doExpandCollapse(button.children().hasClass('fa-expand-arrows-alt'))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
$(() => {
|
||||||
|
initExpander()
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,5 +1,12 @@
|
||||||
{% extends 'bootstrap_4_layout.html.twig' %}
|
{% extends 'bootstrap_4_layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block grapesjs_widget %}
|
||||||
|
<div class="gjs"></div>
|
||||||
|
<div class="d-none">
|
||||||
|
<textarea {{ block('widget_attributes') }}>{{ value }}</textarea>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block file_widget -%}
|
{% block file_widget -%}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
{% endset %}
|
{% endset %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-8 p-2">
|
<div class="col-md-8 p-2" id="page-main-form">
|
||||||
{{ form_widget(form, {attr: {class: 'row'}}) }}
|
{{ form_widget(form, {attr: {class: 'row'}}) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 p-3">
|
<div class="col-md-4 p-3" id="page-metas-form">
|
||||||
<ul class="nav nav-pills">
|
<ul class="nav nav-pills">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" data-toggle="tab" href="#form-page-metas">{{ 'Meta datas'|trans }}</a>
|
<a class="nav-link active" data-toggle="tab" href="#form-page-metas">{{ 'Meta datas'|trans }}</a>
|
||||||
|
|
11
src/core/Resources/views/site/page_admin/edit.html.twig
Normal file
11
src/core/Resources/views/site/page_admin/edit.html.twig
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends '@Core/admin/crud/edit.html.twig' %}
|
||||||
|
|
||||||
|
{% block header %}
|
||||||
|
{{ parent() }}
|
||||||
|
|
||||||
|
<div class="float-right">
|
||||||
|
<button class="btn btn-sm btn-light mr-2 mt-2" id="page-form-expand">
|
||||||
|
<span class="fa fa-expand-arrows-alt"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
40
src/core/Twig/Extension/GrapesJsExtension.php
Normal file
40
src/core/Twig/Extension/GrapesJsExtension.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Twig\Extension;
|
||||||
|
|
||||||
|
use App\Core\String\StringBuilder;
|
||||||
|
use Twig\Extension\AbstractExtension;
|
||||||
|
use Twig\TwigFilter;
|
||||||
|
use Twig\Environment;
|
||||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
|
|
||||||
|
class GrapesJsExtension extends AbstractExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getFilters()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new TwigFilter('grapesjs_html', [$this, 'getHtml']),
|
||||||
|
new TwigFilter('grapesjs_css', [$this, 'getCss']),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHtml(?string $value): ?string
|
||||||
|
{
|
||||||
|
return $this->extractData($value, 'html');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCss(?string $value): ?string
|
||||||
|
{
|
||||||
|
return $this->extractData($value, 'css');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function extractData(?string $value, string $key): ?string
|
||||||
|
{
|
||||||
|
$data = json_decode($value, true);
|
||||||
|
|
||||||
|
return $data[$key] ?? '';
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue