Skip to content

Commit 5eed49b

Browse files
joedixondriesvints
authored andcommitted
Add new editor component
1 parent e00bdde commit 5eed49b

File tree

5 files changed

+138
-54
lines changed

5 files changed

+138
-54
lines changed

resources/css/threads.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,16 @@ div.forum-content {
1616

1717
div.forum-content div>* {
1818
@apply mb-4;
19+
}
20+
21+
div.forum-content h3 {
22+
@apply text-xl font-bold;
23+
}
24+
25+
div.forum-content a {
26+
@apply text-green-dark;
27+
}
28+
29+
div.forum-content blockquote {
30+
@apply border-l-2 border-gray-500 pl-2 italic;
1931
}

resources/js/components/Editor.vue

Lines changed: 114 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,136 @@
11
<template>
22
<div>
3-
<div>
3+
<div class="border-2 border-b-0 rounded-t p-2 bg-gray-200">
44
<ul>
55
<li>
6-
<button type="button" @click="handleClick('bold')">
7-
<i class="fa fa-bold"></i>
8-
</button>
9-
<button type="button" @click="handleClick('emphasis')">
10-
<i class="fa fa-italic"></i>
11-
</button>
12-
<button type="button" @click="handleClick">
13-
<i class="fa fa-header"></i>
14-
</button>
15-
<button type="button" @click="handleClick('code')">
16-
<i class="fa fa-code"></i>
6+
<button
7+
v-for="[key, value] of Object.entries(styles)"
8+
:key="key"
9+
type="button"
10+
class="text-gray-600 mr-4 cursor-pointer"
11+
@click="handleClick(key)"
12+
>
13+
<i class="fa" :class="value.class"></i>
1714
</button>
1815
</li>
1916
</ul>
2017
</div>
21-
<textarea
22-
:name="name"
18+
<textarea
19+
:name="name"
2320
:id="id"
2421
:value="content"
25-
class="editor"
26-
>
27-
</textarea>
22+
class="editor rounded-t-none resize-none h-40"
23+
></textarea>
2824
</div>
2925
</template>
3026

3127
<script>
32-
export default {
33-
props: ['name', 'id', 'content'],
34-
data: () => {
35-
return {
36-
styles: {
37-
'headings': {
38-
'h1': '# ',
39-
'h2': '## ',
40-
'h3': '### ',
41-
'h4': '#### ',
42-
'h5': '##### ',
43-
'h6': '###### ',
44-
},
45-
'bold': '**',
46-
'emphasis': '_',
47-
'code': '```'
28+
export default {
29+
props: ["name", "id", "content"],
30+
data: () => {
31+
return {
32+
// Style configuration.
33+
styles: {
34+
header: {
35+
before: "### ",
36+
class: {
37+
"fa-header": true
38+
}
39+
},
40+
bold: {
41+
before: "**",
42+
after: "**",
43+
class: {
44+
"fa-bold": true
45+
}
46+
},
47+
italic: {
48+
before: "_",
49+
after: "_",
50+
class: {
51+
"fa-italic": true
52+
}
53+
},
54+
quote: {
55+
before: "> ",
56+
class: {
57+
"fa-quote-left": true
58+
}
59+
},
60+
code: {
61+
before: "`",
62+
after: "`",
63+
class: {
64+
"fa-code": true
65+
}
66+
},
67+
link: {
68+
before: "[](",
69+
after: ")",
70+
class: {
71+
"fa-link": true
72+
}
73+
},
74+
image: {
75+
before: "![](",
76+
after: ")",
77+
class: {
78+
"fa-file-image-o": true
79+
}
4880
}
4981
}
50-
},
51-
methods: {
52-
handleClick(style) {
53-
const input = document.getElementById(this.id);
54-
let value = input.value;
55-
const selectionStart = input.selectionStart;
56-
const selectionEnd = input.selectionEnd;
57-
const styleCharacter = this.styles[style];
82+
};
83+
},
84+
methods: {
85+
/**
86+
* Handle the click event of one a style button.
87+
*/
88+
handleClick(style) {
89+
const input = this.$el.querySelectorAll("textarea")[0];
5890
59-
value = this.insertCharacterAtPosition(value, styleCharacter, selectionStart);
60-
value = this.insertCharacterAtPosition(value, styleCharacter, selectionEnd + styleCharacter.length);
91+
// Get the start and end positions of the current selection.
92+
const selectionStart = input.selectionStart;
93+
const selectionEnd = input.selectionEnd;
6194
62-
input.value = value;
63-
input.setSelectionRange(selectionStart + styleCharacter.length, selectionEnd + styleCharacter.length);
64-
input.focus();
65-
},
95+
// Find the style in the configuration.
96+
const styleFormat = this.styles[style];
6697
67-
insertCharacterAtPosition(string, character, position) {
68-
return [string.slice(0, position), character, string.slice(position)].join('');
69-
}
98+
// Get any prefix and/or suffix characters from the selected style.
99+
const prefix = styleFormat.before ? styleFormat.before : "";
100+
const suffix = styleFormat.after ? styleFormat.after : "";
101+
102+
// Insert the prefix at the relevant position.
103+
input.value = this.insertCharactersAtPosition(
104+
input.value,
105+
prefix,
106+
selectionStart
107+
);
108+
109+
// Insert the suffix at the relevant position.
110+
input.value = this.insertCharactersAtPosition(
111+
input.value,
112+
suffix,
113+
selectionEnd + prefix.length
114+
);
115+
116+
// Reselect the selection and focus the input.
117+
input.setSelectionRange(
118+
selectionStart + prefix.length,
119+
selectionEnd + prefix.length
120+
);
121+
input.focus();
122+
},
123+
124+
/**
125+
* Insert one or more characters at a certain position in a string.
126+
*/
127+
insertCharactersAtPosition(string, character, position) {
128+
return [
129+
string.slice(0, position),
130+
character,
131+
string.slice(position)
132+
].join("");
70133
}
71134
}
135+
};
72136
</script>

resources/views/forum/threads/_form.blade.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
<editor
1515
name="body"
1616
id="body"
17-
content="{{ isset($thread) ? $thread->body() : null }}"
18-
/>
17+
content="{{ old('body') ?: isset($thread) ? $thread->body() : null }}"
18+
></editor>
1919
@error('body')
2020
@endFormGroup
2121

resources/views/forum/threads/show.blade.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,11 @@
133133

134134
@formGroup('body')
135135
<label for="body">Write a reply</label>
136-
<textarea name="body" id="body" class="editor"></textarea>
136+
<editor
137+
name="body"
138+
id="body"
139+
content="{{ old('body') }}"
140+
></editor>
137141
@error('body')
138142
@endFormGroup
139143

resources/views/replies/edit.blade.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919
@method('PUT')
2020

2121
@formGroup('body')
22-
<textarea name="body" id="body" class="editor" v-pre>{{ $reply->body() }}</textarea>
22+
<editor
23+
name="body"
24+
id="body"
25+
content="{{ old('body') ?: $reply->body() }}"
26+
></editor>
2327
@error('body')
2428
@endFormGroup
2529

0 commit comments

Comments
 (0)