I needed a word count in the toolbar so adapted the code written by "yfrommelt". Although I've still given credit, it's mostly been rewritten :p It doesn't require any hacking of the main source, but is dependent upon your browser supporting the document.getElementsByClassName method. I would also recommend using a build that as Paste As Plain Text enabled - this exposes the paste event to the plugin.
The following code needs to be put into "plugins/charcount/plugin.js" (create folder and file as necessary).
/*******************************************************************************
Create Date : 11/10/2013
----------------------------------------------------------------------
Plugin name : charcount/wordcount
Version : 2.0
Author : Frommelt Yoann
Pete Allison
Description : Character/word counter for CKEditor v 3
********************************************************************************/
CKEDITOR.plugins.add('charcount',{
init:function(editor){
var labelCounter = ''
// Only implement if config.maxLength or config.maxWords has been defined
if (editor.config.maxLength != null || editor.config.maxWords != null) {
if (editor.maxLength != null)
labelCounter = editor.lang.labelCharcount ? editor.lang.labelCharcount : 'Character counter';
else
labelCounter = editor.lang.labelWordcount ? editor.lang.labelWordcount : 'Word counter';
// Attach the key event to this editor
addEventOnkey(editor);
// And ensure the button is registered
editor.ui.addButton('CharCount',{
label: labelCounter,
command:'charcount'
});
}
}
});
/**
* Attach the keyup event to the editor
* @param {CKEDITOR} editor <p>The editor to attach the events to.</p>
*/
function addEventOnkey(editor) {
var initilised = false;
editor.on('contentDom', function() {
// Perform an initial calculation when the contentDom has just been built
calculate(editor);
/*
* CKE only exposes the editor.document.on method at first creation of
* the editor, however if a setData is called, then all events added in
* this manner are erased. setData will perform a contentDom event
* every time it is called, so we must directly hook new listeners to
* the recreated document.
*/
var editable = editor.editable();
editable.attachListener(editor.document, 'keyup', function() {
calculate(editor);
});
// This will only work if the paste as plain text plugin is available
if (!initilised)
editor.on('paste', function() {
calculate(editor);
});
/*
* So that we don't have to hack around any of the main CKE javascript
* files, we need to directly modify the button that's added so that it is
* not fixed width and has no icon.
* Although not available in some browsers getElementsByClassName is a good
* way of doing this.
*/
var buttons = document.getElementsByClassName('cke_button__charcount');
for (button in buttons) {
if (!isNaN(button)) {
// We know that each button has two spans - the icon and text
var spans = buttons[button].getElementsByTagName('span');
spans[0].style.display = 'none';
spans[1].style.display = 'inline';
spans[1].style['padding-left'] = '0px';
}
}
});
}
/**
* This performs the necessary character or word calculation and display
* @param {CKEDITOR} editor <p>The editor that you wish to count.</p>
*/
function calculate(editor) {
var buttonLabel = document.getElementById('cke_' + editor.name).getElementsByClassName('cke_button__charcount_label')[0],
plainText = editor.document.getBody().getText();
if (editor.config.maxLength != null) {
// Character count
if (editor.config.maxLength == 0)
buttonLabel.innerHTML = plainText.length;
else
buttonLabel.innerHTML = editor.config.maxLength - plainText.length
} else {
// Word count
if (editor.config.maxWords == 0)
buttonLabel.innerHTML = wordCount(plainText);
else
buttonLabel.innerHTML = editor.config.maxWords - wordCount(plainText);
}
}
/**
* Counts the number of words within the passed text.
* @param {String} text
* @return {Integer}
*/
function wordCount(text) {
var r = 0,
item = text.trim();
if (item === '') return 0;
/*
* This should remove any html tags if they exist
*/
item = item.replace(/(<([^>]+)>)/ig, '');
/*
* If using a dot to separate words, prevent it, unless it is within a
* number
*/
item = item.replace(/\.[^0-9]/g, '. $&');
/*
* Replace any underscores with a space - there should be no reason to
* use them
*/
item = item.replace(/\_/g, ' ');
// Replace all multiple spaces with a single space
a = item.replace(/\s/g, ' ');
a = a.split(' ');
for (z = 0; z < a.length; z++) {
if (a[z].length > 0)
r++;
}
return r;
}
This will allow either a character count or a word count. To enable the character counter, initialise your CKEditor as follows:
Setting maxLength or maxWords as 0 will just display the actual character or word counts, setting them to a greater value will display a value of the number of characters/words remaining out of the limit.
PeteAUK, might be easier for users if you would create a new plugin and add it to the repository. Nobody said we can only have one plugin per feature. You can give yfrommelt credit in the plugin's description.
I am trying to create similar type of plug-in for my application.
But I am facing issue with getData() function.Actually I have 'keyup' event on which i am updating counter and showing counter in footer of CKEditor.For this I am using editor.getData().length,but this getData function is asynchronous and hence on keyup event sometimes it doesn't return me latest data and hence data loss is there,so my counter value is wrong.
So I went for using editor.getSnapshot(),but that has some other issues like getData() removes extra <br> tags but getSnapShot doesn't and hence both are not same is that scenario and we are saving data using getData().
Can anybody help me here,so that my counter should update correctly inspite of getData() being Async.I dont want to use settimeout.
Hello please pass me the files of this plugin created.
Hello please pass me the files of this plugin created.
I was making the changes, but I vote errors.
thanks,
I needed a word count in the
I needed a word count in the toolbar so adapted the code written by "yfrommelt". Although I've still given credit, it's mostly been rewritten :p It doesn't require any hacking of the main source, but is dependent upon your browser supporting the document.getElementsByClassName method. I would also recommend using a build that as Paste As Plain Text enabled - this exposes the paste event to the plugin.
The following code needs to be put into "plugins/charcount/plugin.js" (create folder and file as necessary).
This will allow either a character count or a word count. To enable the character counter, initialise your CKEditor as follows:
To enable the word counter use the following:
Setting maxLength or maxWords as 0 will just display the actual character or word counts, setting them to a greater value will display a value of the number of characters/words remaining out of the limit.
PeteAUK, might be easier for
PeteAUK, might be easier for users if you would create a new plugin and add it to the repository. Nobody said we can only have one plugin per feature. You can give yfrommelt credit in the plugin's description.
Customer and Community Manager, CKSource
Follow us on: Facebook, Twitter, LinkedIn
If you think you found a bug in CKEditor, read this!
Very good point :s Plugin
Very good point :s Plugin created here :)
Thanks!
Two editors in same page
Hi everyone, I implemented this solution and worked very well, except for one thing:
I have two ckeditors in my page, and every time I insert any text in editor 1, the charcount of editor 2 is updated with charcount of editor 1.
Has one ever experienced this?
thanks
bon boulot et merci depuis l
bon boulot et merci depuis l'australie!
getData() doesn't return latest data and hence counter value is
I am trying to create similar type of plug-in for my application.
But I am facing issue with getData() function.Actually I have 'keyup' event on which i am updating counter and showing counter in footer of CKEditor.For this I am using editor.getData().length,but this getData function is asynchronous and hence on keyup event sometimes it doesn't return me latest data and hence data loss is there,so my counter value is wrong.
So I went for using editor.getSnapshot(),but that has some other issues like getData() removes extra <br> tags but getSnapShot doesn't and hence both are not same is that scenario and we are saving data using getData().
Can anybody help me here,so that my counter should update correctly inspite of getData() being Async.I dont want to use settimeout.