Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit 780dfbf

Browse files
authored
Merge pull request #15 from ckeditor/t/6
Other: Made `WordCount#characters` and `WordCount#words` getters synchronous to make it possible to retrieve precise content stats on demand. Closes #6.
2 parents aae2c2e + 726ba97 commit 780dfbf

File tree

7 files changed

+396
-112
lines changed

7 files changed

+396
-112
lines changed

docs/_snippets/features/build-word-count-source.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
/* globals window */
77

88
import ClassicEditor from '@ckeditor/ckeditor5-build-classic/src/ckeditor';
9+
import BalloonEditor from '@ckeditor/ckeditor5-build-balloon/src/ckeditor';
910

1011
import WordCount from '@ckeditor/ckeditor5-word-count/src/wordcount';
1112

1213
ClassicEditor.builtinPlugins.push( WordCount );
14+
BalloonEditor.builtinPlugins.push( WordCount );
1315

1416
window.ClassicEditor = ClassicEditor;
17+
window.BalloonEditor = BalloonEditor;
Lines changed: 69 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,80 @@
1-
21
<style>
3-
.customized-count__color-box {
4-
--hue: 56;
5-
width: 20px;
6-
height: 20px;
7-
background-color: hsl( var( --hue ), 100%, 50% );
8-
display: inline-block;
9-
vertical-align: middle;
10-
border-radius: 100%;
2+
.demo-update {
3+
border: 1px solid var(--ck-color-base-border);
4+
border-radius: var(--ck-border-radius);
5+
box-shadow: 2px 2px 0px hsla( 0, 0%, 0%, 0.1 );
6+
margin: 1.5em 0;
7+
padding: 1em;
8+
}
9+
10+
.demo-update h3 {
11+
font-size: 18px;
12+
font-weight: bold;
13+
margin: 0 0 .5em;
14+
padding: 0;
15+
}
16+
17+
.demo-update .ck.ck-editor__editable_inline {
18+
border: 1px solid hsla( 0, 0%, 0%, 0.15 );
19+
transition: background .5s ease-out;
20+
min-height: 6em;
21+
margin-bottom: 1em;
22+
}
23+
24+
.demo-update__controls {
25+
display: flex;
26+
flex-direction: row;
27+
align-items: center;
28+
}
29+
30+
.demo-update__chart {
31+
margin-right: 1em;
32+
}
33+
34+
.demo-update__chart__circle {
35+
transform: rotate(-90deg);
36+
transform-origin: center;
37+
}
38+
39+
.demo-update__chart__characters {
40+
font-size: 13px;
41+
font-weight: bold;
42+
}
43+
44+
.demo-update__words {
45+
flex-grow: 1;
46+
opacity: .5;
1147
}
1248

13-
.customized-count > div {
14-
margin-left: 1em;
49+
.demo-update__limit-close .demo-update__chart__circle {
50+
stroke: hsl( 30, 100%, 52% );
1551
}
1652

17-
.customized-count span {
18-
min-width: 90px;
19-
display: inline-block;
53+
.demo-update__limit-exceeded .ck.ck-editor__editable_inline {
54+
background: hsl( 0, 100%, 97% );
55+
}
56+
57+
.demo-update__limit-exceeded .demo-update__chart__circle {
58+
stroke: hsl( 0, 100%, 52% );
59+
}
60+
61+
.demo-update__limit-exceeded .demo-update__chart__characters {
62+
fill: hsl( 0, 100%, 52% );
2063
}
2164
</style>
2265

23-
<div id="demo-editor-update">
24-
<p>Tourists frequently admit that <a href="https://en.wikipedia.org/wiki/Taj_Mahal">Taj Mahal</a> “simply cannot be described with words”.</p>
25-
</div>
26-
<div class="word-count customized-count">
27-
<div class="customized-count__words">
28-
<label>
29-
<span>Words:</span>
30-
<progress value="12" max="20"></progress>
31-
</label>
66+
<div class="demo-update">
67+
<h3>Post editor with word count</h3>
68+
<div id="demo-update__editor">
69+
<p>Tourists frequently admit that <a href="https://en.wikipedia.org/wiki/Taj_Mahal">Taj Mahal</a> “simply cannot be described with words”.</p>
3270
</div>
33-
<div class="customized-count__characters">
34-
<span>Characters:</span>
35-
<div class="customized-count__color-box"></div>
71+
<div class="demo-update__controls">
72+
<span class="demo-update__words"></span>
73+
<svg class="demo-update__chart" viewbox="0 0 40 40" width="40" height="40" xmlns="http://www.w3.org/2000/svg">
74+
<circle stroke="hsl(0, 0%, 93%)" stroke-width="3" fill="none" cx="20" cy="20" r="17" />
75+
<circle class="demo-update__chart__circle" stroke="hsl(202, 92%, 59%)" stroke-width="3" stroke-dasharray="134,534" stroke-linecap="round" fill="none" cx="20" cy="20" r="17" />
76+
<text class="demo-update__chart__characters" x="50%" y="50%" dominant-baseline="central" text-anchor="middle"></text>
77+
</svg>
78+
<button type="button" class="demo-update__send">Send post</button>
3679
</div>
3780
</div>

docs/_snippets/features/word-count-update.js

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
44
*/
55

6-
/* global window, document, console, ClassicEditor */
6+
/* global window, document, console, BalloonEditor */
77

8-
ClassicEditor
9-
.create( document.querySelector( '#demo-editor-update' ), {
8+
BalloonEditor
9+
.create( document.querySelector( '#demo-update__editor' ), {
1010
toolbar: {
1111
items: [
1212
'heading',
@@ -26,42 +26,61 @@ ClassicEditor
2626
],
2727
viewportTopOffset: window.getViewportTopOffsetConfig()
2828
},
29+
placeholder: 'Text of the post',
2930
table: {
3031
contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ]
3132
}
3233
} )
3334
.then( editor => {
35+
const maxCharacters = 120;
3436
const wordCountPlugin = editor.plugins.get( 'WordCount' );
37+
const container = document.querySelector( '.demo-update' );
38+
const progressCircle = document.querySelector( '.demo-update__chart__circle' );
39+
const charactersBox = document.querySelector( '.demo-update__chart__characters' );
40+
const wordsBox = document.querySelector( '.demo-update__words' );
41+
const sendButton = document.querySelector( '.demo-update__send' );
42+
const circleCircumference = Math.floor( 2 * Math.PI * progressCircle.getAttribute( 'r' ) );
3543

36-
const progressBar = document.querySelector( '.customized-count progress' );
37-
const colorBox = document.querySelector( '.customized-count__color-box' );
44+
// Update the UI on editor load.
45+
updateWordCountStatsUI( wordCountPlugin.characters, wordCountPlugin.words );
3846

47+
// Update the UI as the content of the editor changes.
3948
wordCountPlugin.on( 'update', ( evt, data ) => {
40-
const charactersHue = calculateHue( {
41-
characters: data.characters,
42-
greenUntil: 70,
43-
maxCharacters: 120
44-
} );
45-
46-
progressBar.value = data.words;
47-
colorBox.style.setProperty( '--hue', charactersHue );
49+
updateWordCountStatsUI( data.characters, data.words );
4850
} );
4951

50-
// Calculates the hue based on the number of characters.
51-
//
52-
// For the character counter:
53-
//
54-
// * below greenUntil - Returns green.
55-
// * between greenUntil and maxCharacters - Returns a hue between green and red.
56-
// * above maxCharacters - Returns red.
57-
function calculateHue( { characters, greenUntil, maxCharacters } ) {
58-
const greenHue = 70;
59-
const redHue = 0;
60-
const progress = Math.max( 0, Math.min( 1, ( characters - greenUntil ) / ( maxCharacters - greenUntil ) ) ); // 0-1
61-
const discreetProgress = Math.floor( progress * 10 ) / 10; // 0, 0.1, 0.2, ..., 1
52+
function updateWordCountStatsUI( currentCharacters, currentWords ) {
53+
const charactersProgress = currentCharacters / maxCharacters * circleCircumference;
54+
const isLimitExceeded = currentCharacters > maxCharacters;
55+
const isCloseToLimit = !isLimitExceeded && currentCharacters > maxCharacters * .8;
56+
const circleDashArray = Math.min( charactersProgress, circleCircumference );
57+
58+
// Set the stroke of the circle to show the how many characters were typed.
59+
progressCircle.setAttribute( 'stroke-dasharray', `${ circleDashArray },${ circleCircumference }` );
60+
61+
// Display the number of characters in the progress chart. When exceeded the limit,
62+
// display how many characters should be removed.
63+
if ( isLimitExceeded ) {
64+
charactersBox.textContent = `-${ currentCharacters - maxCharacters }`;
65+
} else {
66+
charactersBox.textContent = currentCharacters;
67+
}
68+
69+
wordsBox.textContent = `Words in the post: ${ currentWords }`;
6270

63-
return ( redHue - greenHue ) * discreetProgress + greenHue;
71+
// If the content length is close to the characters limit, add a CSS class to warns the user.
72+
container.classList.toggle( 'demo-update__limit-close', isCloseToLimit );
73+
74+
// If exceeded the characters limit, add a CSS class that makes the content's background red.
75+
container.classList.toggle( 'demo-update__limit-exceeded', isLimitExceeded );
76+
77+
// If exceeded the characters limit, disable the send button.
78+
sendButton.toggleAttribute( 'disabled', isLimitExceeded );
6479
}
80+
81+
sendButton.addEventListener( 'click', () => {
82+
window.alert( 'Post sent!' ); // eslint-disable-line no-alert
83+
} );
6584
} )
6685
.catch( err => {
6786
console.error( err.stack );

0 commit comments

Comments
 (0)