Skip to content

Commit 7e9e5fe

Browse files
Johan Montenijpascalbaljet
Johan Montenij
andauthored
Jodit WYSIWYG editor (#415)
Co-authored-by: Pascal Baljet <[email protected]>
1 parent 723e5f6 commit 7e9e5fe

21 files changed

+345
-4
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ node_modules
1212
protonemedia-laravel-splade-*.tgz
1313
app/bootstrap/ssr*
1414
app/storage/splade-temporary-file-uploads/*
15+
dist/protone-media-laravel-splade*.cjs
16+
dist/protone-media-laravel-splade*.js

app/app/Http/Controllers/FormBuilderController.php

+27
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use ProtoneMedia\Splade\FormBuilder\Submit;
1616
use ProtoneMedia\Splade\FormBuilder\Text;
1717
use ProtoneMedia\Splade\FormBuilder\Textarea;
18+
use ProtoneMedia\Splade\FormBuilder\Wysiwyg;
1819
use ProtoneMedia\Splade\SpladeForm;
1920

2021
class FormBuilderController
@@ -110,4 +111,30 @@ public function storeMultifields2(MultiFieldsFormRequest2 $request)
110111
{
111112
return response()->json(['result' => $request->validated()]);
112113
}
114+
115+
public function wysiwyg()
116+
{
117+
return view('form.formbuilder', [
118+
'forms' => [
119+
SpladeForm::make()
120+
->action(route('formbuilder.wysiwyg.store'))
121+
->id('wysiwyg-form')
122+
->class('space-y-4')
123+
->fields([
124+
Wysiwyg::make('body')
125+
->label('Jodit Wysiwyg editor'),
126+
127+
Submit::make()->label('Submit'),
128+
])
129+
->fill([
130+
'body' => 'This is a <u>test</u> with the <b>Splade</b> <em>Jodit WYSIWYG editor</em>.',
131+
]),
132+
],
133+
]);
134+
}
135+
136+
public function storeWysiwyg(Request $request)
137+
{
138+
return response()->json(['result' => $request->all()]);
139+
}
113140
}

app/app/Http/Controllers/FormComponentsController.php

+5
Original file line numberDiff line numberDiff line change
@@ -296,4 +296,9 @@ public function storeValidateMessage(Request $request)
296296
'name.required' => 'Here is a <a href="#">Link</a>',
297297
]);
298298
}
299+
300+
public function wysiwyg()
301+
{
302+
return view('form.components.wysiwyg');
303+
}
299304
}

app/resources/js/app.js

+2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import { createApp } from "vue/dist/vue.esm-bundler.js";
77
// import "../../../lib/Components/choices.scss";
88
// import "../../../lib/Components/filepond.scss";
99
// import "../../../lib/Components/flatpickr.styl";
10+
// import "../../../lib/Components/jodit.scss";
1011
// import { renderSpladeApp, SpladePlugin } from "../../../dist/protone-media-laravel-splade";
1112

1213
// for build
1314
import "@protonemedia/laravel-splade/dist/style.css";
15+
import "@protonemedia/laravel-splade/dist/jodit.css";
1416
import { renderSpladeApp, SpladePlugin } from "@protonemedia/laravel-splade";
1517

1618
const el = document.getElementById("app");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@extends('layout')
2+
3+
@section('content')
4+
5+
FormWYSIWYG
6+
7+
<div class="mx-auto px-4">
8+
<x-splade-form
9+
class="space-y-4"
10+
:default="[
11+
'body' => 'This is a <u>test</u> with the <b>Splade</b> <em>Jodit WYSIWYG editor</em>.'
12+
]"
13+
>
14+
<x-splade-wysiwyg name="body" dusk="jodit" placeholder="Body" />
15+
16+
<div dusk="all">@{{ form.$all }}</div>
17+
</x-splade-form>
18+
</div>
19+
20+
@endsection

app/resources/views/form/formbuilder.blade.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<x-splade-component is="form" :for="$form">
99
<div v-if="form.wasSuccessful">
1010
Results:
11-
<pre v-text="form.$response" />
11+
<pre v-text="form.$response.result" />
1212
</div>
1313
</x-splade-component>
1414
@endforeach

app/routes/web.php

+5
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@
196196
Route::get('form/components/relation', [FormComponentsController::class, 'relation'])->name('form.components.relation');
197197
Route::get('form/components/transform', [FormComponentsController::class, 'transform'])->name('form.components.transform');
198198
Route::get('form/components/customSelectOptions', [FormComponentsController::class, 'customSelectOptions'])->name('form.components.customSelectOptions');
199+
Route::get('form/components/wysiwyg', [FormComponentsController::class, 'wysiwyg'])->name('form.components.wysiwyg');
199200

200201
Route::get('form/components/filepond', [FilepondController::class, 'show'])->name('form.components.filepond');
201202
Route::get('form/components/filepondValidation', [FilepondController::class, 'showValidation'])->name('form.components.filepondValidation');
@@ -237,6 +238,7 @@
237238

238239
Route::get('formbuilder/simple', [FormBuilderController::class, 'simple'])->name('formbuilder.simple.index');
239240
Route::post('formbuilder/simple', [FormBuilderController::class, 'storeSimple'])->name('formbuilder.simple.store');
241+
Route::post('formbuilder/simple', [FormBuilderController::class, 'storeSimple'])->name('formbuilder.simple.store');
240242

241243
Route::get('formbuilder/fromClass', [FormBuilderController::class, 'fromClass'])->name('formbuilder.fromClass.index');
242244
Route::post('formbuilder/fromClass', [FormBuilderController::class, 'storeFromClass'])->name('formbuilder.fromClass.store');
@@ -248,6 +250,9 @@
248250
Route::post('/formbuilder/multifields1', [FormBuilderController::class, 'storeMultifields1'])->name('formbuilder.multifields1.store');
249251
Route::post('/formbuilder/multifields2', [FormBuilderController::class, 'storeMultifields2'])->name('formbuilder.multifields2.store');
250252

253+
Route::get('formbuilder/wysiwyg', [FormBuilderController::class, 'wysiwyg'])->name('formbuilder.wysiwyg.index');
254+
Route::post('formbuilder/wysiwyg', [FormBuilderController::class, 'storeWysiwyg'])->name('formbuilder.wysiwyg.store');
255+
251256
Route::get('lazy', [LazyController::class, 'show'])->name('lazy');
252257
Route::get('lazy/nested', [LazyController::class, 'showNested'])->name('lazy.nested');
253258
Route::get('lazy/notifications', [LazyController::class, 'notifications'])->name('lazy.notifications');

app/tests/Browser/Form/LibrariesTest.php

+11
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,15 @@ public function it_can_submit_the_form_on_change()
228228
->assertRouteIs('navigation.one');
229229
});
230230
}
231+
232+
/** @test */
233+
public function it_can_use_jodit_as_a_wysiwyg_editor()
234+
{
235+
$this->browse(function (Browser $browser) {
236+
$browser->visit('form/components/wysiwyg')
237+
->waitForText('FormWYSIWYG')
238+
->keys('@jodit', 'Some new content!')
239+
->waitForText('Some new content!</p>');
240+
});
241+
}
231242
}

app/tests/Browser/FormBuilderTest.php

+15
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,19 @@ public function it_can_generate_multiple_forms_on_one_page()
120120
->assertSee('"additional_field": "Test value in additional field"');
121121
});
122122
}
123+
124+
/** @test */
125+
public function it_can_show_a_jodit_wysiwyg_editor()
126+
{
127+
$this->browse(function (Browser $browser) {
128+
$browser->visit('/formbuilder/wysiwyg')
129+
->waitForText('Jodit Wysiwyg editor')
130+
->assertInputPresent('body')
131+
->assertSee('This is a test with the Splade Jodit WYSIWYG editor.')
132+
->assertDontSee('This is a <u>test</u> with the <b>Splade</b> <em>Jodit WYSIWYG editor</em>.')
133+
->press('Submit')
134+
->waitForText('Results:')
135+
->assertSee('"body": "This is a <u>test</u> with the <b>Splade</b> <em>Jodit WYSIWYG editor</em>.');
136+
});
137+
}
123138
}

lib/Components/JoditEditor.vue

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<template>
2+
<div ref="jodit">
3+
<slot />
4+
</div>
5+
</template>
6+
7+
<script>
8+
export default {
9+
props: {
10+
options: {
11+
type: Object,
12+
required: false,
13+
default() {
14+
return {};
15+
},
16+
},
17+
18+
jsOptions: {
19+
type: Object,
20+
required: false,
21+
default: () => {
22+
return {};
23+
}
24+
},
25+
26+
modelValue: {
27+
type: [String, Number],
28+
required: false
29+
},
30+
31+
dusk: {
32+
type: String,
33+
required: false,
34+
default: null,
35+
},
36+
},
37+
38+
emits: ["update:modelValue"],
39+
40+
data() {
41+
return {
42+
instance: null,
43+
};
44+
},
45+
46+
mounted() {
47+
const textareaElement = this.$refs.jodit.querySelector("textarea");
48+
49+
50+
import("jodit").then((Jodit) => {
51+
const options = Object.assign({ defaultMode: Jodit.Jodit.MODE_WYSIWYG }, this.options, this.jsOptions);
52+
53+
this.instance = Jodit.Jodit.make(textareaElement, options);
54+
this.instance.value = this.modelValue;
55+
this.instance.events.on("change", newValue => this.$emit("update:modelValue", newValue));
56+
57+
if(this.dusk) {
58+
this.instance.editor.setAttribute("dusk", this.dusk);
59+
}
60+
});
61+
},
62+
63+
beforeUnmount () {
64+
this.instance.destruct();
65+
}
66+
};
67+
</script>

lib/Components/jodit.scss

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
@import "jodit/build/jodit.css";
2+
3+
.jodit-container:not(.jodit_inline) {
4+
@apply shadow-sm rounded-md border-gray-300;
5+
}
6+
7+
.jodit-toolbar__box:not(:empty) {
8+
@apply rounded-t-md;
9+
}
10+
11+
.jodit-status-bar,
12+
.jodit-container:not(.jodit_inline) .jodit-workplace {
13+
@apply rounded-b-md;
14+
}
15+
16+
.jodit-toolbar__box:not(:empty):not(:empty) {
17+
@apply bg-gray-50;
18+
}
19+
20+
.jodit-container:not(.jodit_inline) .jodit-wysiwyg {
21+
@apply px-3 py-2;
22+
}

lib/SpladePlugin.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import File from "./Components/File.vue";
1818
import Flash from "./Components/Flash.vue";
1919
import Form from "./Components/Form.vue";
2020
import Input from "./Components/Input.vue";
21+
import JoditEditor from "./Components/JoditEditor.vue";
2122
import Lazy from "./Components/Lazy.vue";
2223
import Link from "./Components/Link.vue";
2324
import Modal from "./Components/Modal.vue";
@@ -78,6 +79,7 @@ export default {
7879
.component(`${prefix}Flash`, Flash)
7980
.component(`${prefix}Form`, Form)
8081
.component(`${prefix}Input`, Input)
82+
.component(`${prefix}JoditEditor`, JoditEditor)
8183
.component(`${prefix}VueBridge`, VueBridge)
8284
.component(`${prefix}Lazy`, Lazy)
8385
.component(`${prefix}Modal`, Modal)
@@ -132,4 +134,4 @@ export default {
132134
app.component(name, definition);
133135
});
134136
}
135-
};
137+
};

lib/jodit.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import "./Components/jodit.scss";

package-lock.json

+29
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"import": "./dist/protone-media-laravel-splade.js",
1717
"require": "./dist/protone-media-laravel-splade.umd.cjs"
1818
},
19-
"./dist/style.css": "./dist/style.css"
19+
"./dist/style.css": "./dist/style.css",
20+
"./dist/jodit.css": "./dist/jodit.css"
2021
},
2122
"scripts": {
2223
"dev": "vite build --watch",
@@ -49,6 +50,7 @@
4950
"filepond-plugin-image-preview": "^4.6.11",
5051
"filepond-plugin-image-validate-size": "^1.2.7",
5152
"flatpickr": "^4.6.13",
53+
"jodit": "^3.24.9",
5254
"nprogress": "^0.2.0"
5355
}
5456
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<SpladeJoditEditor
2+
{{ $attributes->only(['v-if', 'v-show', 'class']) }}
3+
:options="@js($joditOptions())"
4+
:js-options="{!! $jsJoditOptions() !!}"
5+
v-model="{{ $vueModel() }}"
6+
:dusk="@js($attributes->get('dusk'))"
7+
>
8+
<label class="block">
9+
@includeWhen($label, 'splade::form.label', ['label' => $label])
10+
11+
<textarea {{ $attributes->except(['v-if', 'v-show', 'class'])->class(
12+
'block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 disabled:opacity-50'
13+
)->merge([
14+
'name' => $name,
15+
'v-model' => $vueModel(),
16+
'data-validation-key' => $validationKey(),
17+
]) }}></textarea>
18+
</label>
19+
20+
@includeWhen($help, 'splade::form.help', ['help' => $help])
21+
@includeWhen($showErrors, 'splade::form.error', ['name' => $validationKey()])
22+
</SpladeJoditEditor>

src/Commands/PublishFormStylesheetsCommand.php

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public function handle(): int
2222
copy(__DIR__ . '/../../lib/Components/choices.scss', resource_path('css/choices.scss'));
2323
copy(__DIR__ . '/../../lib/Components/filepond.scss', resource_path('css/filepond.scss'));
2424
copy(__DIR__ . '/../../lib/Components/flatpickr.styl', resource_path('css/flatpickr.styl'));
25+
copy(__DIR__ . '/../../lib/Components/jodit.scss', resource_path('css/jodit.scss'));
2526

2627
$this->comment('All done');
2728

0 commit comments

Comments
 (0)