CKEditor Character Count (charcount) is not working - javascript

If anyone has any experience with adding a charcount (Characters count) plugin for CKEditor, I sure could use a hand. This is my understanding of what needs to be done to add a plugin to CKEditor to count characters.
Create a plugin.js file which has the JavaScript to count the characters, and place this file at /web/server/root/ckeditor/plugins/charcount/plugin.js
Add the line config.extraPlugin = 'charcount'; to the config file at /web/server/root/ckeditor/config.js
Style the Character Count by adding CSS to the file at /web/server/root/ckeditor/skin/skin_name/editor.css.
Here is the plugin.js file I am using. Note: This JavaScript comes from the first post from this thread on the CKEditor forum.
CKEDITOR.plugins.add( 'charcount',
{
init : function( editor )
{
var defaultLimit = 'unlimited';
var defaultFormat = '<span class="cke_charcount_count">%count%</span> of <span class="cke_charcount_limit">%limit%</span> characters';
var limit = defaultLimit;
var format = defaultFormat;
var intervalId;
var lastCount = 0;
var limitReachedNotified = false;
var limitRestoredNotified = false;
if ( true )
{
function counterId( editor )
{
return 'cke_charcount_' + editor.name;
}
function counterElement( editor )
{
return document.getElementById( counterId(editor) );
}
function updateCounter( editor )
{
var count = editor.getData().length;
if( count == lastCount ){
return true;
} else {
lastCount = count;
}
if( !limitReachedNotified && count > limit ){
limitReached( editor );
} else if( !limitRestoredNotified && count < limit ){
limitRestored( editor );
}
var html = format.replace('%count%', count).replace('%limit%', limit);
counterElement(editor).innerHTML = html;
}
function limitReached( editor )
{
limitReachedNotified = true;
limitRestoredNotified = false;
editor.setUiColor( '#FFC4C4' );
}
function limitRestored( editor )
{
limitRestoredNotified = true;
limitReachedNotified = false;
editor.setUiColor( '#C4C4C4' );
}
editor.on( 'themeSpace', function( event )
{
if ( event.data.space == 'bottom' )
{
event.data.html += '<div id="'+counterId(event.editor)+'" class="cke_charcount"' +
' title="' + CKEDITOR.tools.htmlEncode( 'Character Counter' ) + '"' +
'> </div>';
}
}, editor, null, 100 );
editor.on( 'instanceReady', function( event )
{
if( editor.config.charcount_limit != undefined )
{
limit = editor.config.charcount_limit;
}
if( editor.config.charcount_format != undefined )
{
format = editor.config.charcount_format;
}
}, editor, null, 100 );
editor.on( 'dataReady', function( event )
{
var count = event.editor.getData().length;
if( count > limit ){
limitReached( editor );
}
updateCounter(event.editor);
}, editor, null, 100 );
editor.on( 'key', function( event )
{
//updateCounter(event.editor);
}, editor, null, 100 );
editor.on( 'focus', function( event )
{
editorHasFocus = true;
intervalId = window.setInterval(function (editor) {
updateCounter(editor)
}, 1000, event.editor);
}, editor, null, 100 );
editor.on( 'blur', function( event )
{
editorHasFocus = false;
if( intervalId )
clearInterval(intervalId);
}, editor, null, 100 );
}
}
});
Here is my config.js file. Notice I do have config.extraPlugin = 'charcount'; near the beginning of this file.
CKEDITOR.editorConfig = function( config ) {
config.extraPlugin = 'charcount';
config.toolbar = 'MyToolbar';
config.toolbar_MyToolbar =
[
{ name: 'document', items : [ 'Source','Save' ] },
{ name: 'editing', items : [ 'Find','Replace','Scayt', 'TextColor' ] },
{ name: 'insert', items : [ 'Image','CodeSnippet','Table','HorizontalRule' ] },
{ name: 'basicstyles', items : [ 'Bold','Italic','Strike','-','RemoveFormat' ] },
{ name: 'paragraph', items : [ 'NumberedList','BulletedList','-','Outdent','Indent','-','Blockquote' ] },
{ name: 'links', items : [ 'Link','Unlink','Anchor' ] },
{ name: 'tools', items : [ 'Maximize','ShowBlocks','-' ] }
];
};
I added the following to the bottom of my editor.css file.
.cke_skin_kama .cke_charcount {
display:block;
float:right;
margin-top:5px;
margin-right:3px;
color:#60676A;
}
.cke_charcount span.cke_charcount_count,
.cke_charcount span.cke_charcount_limit {
font-style: italic;
}
Here is my stage.html file.
<script src="ckeditor/ckeditor.js"></script>
<textarea id="editor1"></textarea>
<script> CKEDITOR.replace('editor1'); </script>
Here is a screen shot of the expected outcome, where the bottom right hand corner of my CKEditor should have text which counts the characters.
Here is a screen shot showing that my CKEditor does not have a character count.
There are some other similar threads on this. However, the similar threads add a button to the CKEditor toolbar. The JavaScript I am using does not add a button to the toolbar, and instead displays text at the bottom right-hand corner of CKEditor, which is what I am attempting to achieve. Hopefully this difference makes this post unique enough to not be considered a duplicate.
If it helps, my Web Server OS is Linux Mint version 17.2.

I was not able to figure out what the issue is with the JavaScript I posted in my original question. However, I did come across a solution to this issue, which I want to share here in case others happen upon this post with a similar issue. I found a plugin for CKEditor called the Word Count & Char Count plugin. This plugin can be downloaded from http://ckeditor.com/addon/wordcount or https://github.com/w8tcha/CKEditor-WordCount-Plugin. This plugin totally works, and display the number of words, paragraphs and/or characters in CKEditor.

Related

Dynamically change ckeditor dialog

I'm trying to modify the contents of a dialog field based on another field. I've tried the replace method, but I'm throw this error: The editor instance "edit-body-und-0-value" is already attached to the provided element.
The basic goal is to add a class to the table. Using the table dialog I figured if I could fill in the advCSSClassess default value, then replace the editor, I'd now have a dialog in with the class attached.
Here's my plugin code:
CKEDITOR.on('dialogDefinition', function( ev ) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
if ( dialogName === 'table' ) {
var tableProperties = dialogDefinition.getContents( 'info' );
var advancedTab = dialogDefinition.getContents( 'advanced' );
var classField = advancedTab.get( 'advCSSClasses' );
classField['default'] = 'stackable';
tableProperties.add({
type: 'checkbox',
id: 'stackTable',
label: 'Make table responsive',
'default': false,
onClick: function( button ) {
classField[ 'default' ] = 'stackable';
var thisEditor = CKEDITOR.instances;
CKEDITOR.replace('edit-body-und-0-value', thisEditor);
}
});
}
});
I've been able to hack it in like this in the click handler, but that doesn't seem sustainable.:
var classInput = $("label:contains('Stylesheet Classes')").attr('for');
$('#' + classInput).val('stackable');
I've used this and this for reference.
Since this question got a new request, here's the code that I ended up with. This is old enough that I can't remember the details, but I hope this helps.
CKEDITOR.on('dialogDefinition', function( ev ) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
if ( dialogName === 'table' ) {
var tableProperties = dialogDefinition.getContents( 'info' );
tableProperties.add({
type: 'checkbox',
id: 'stackTable',
label: 'Make table stackable on mobile. Does not work with header row.',
'default': false,
onClick: function( button ) {
var classInput = CKEDITOR.dialog.getCurrent().getContentElement('advanced', 'advCSSClasses').getElement().$;
$('#' + classInput.id).find('input').val('sy-stacktable');
}
});
}
});

Character does not bind with Ckeditor bind

i am using a plugin to add new language characters for Ckeditor, i have debug this plugin it is changing English to my desired language character but does not showing me this new character in Editor.
One thing more
CKEDITOR.plugins.add( 'plugin_Name',
{
init : function( editor )
{
editor.on( 'contentDom', function( e ) {
var doc = editor.document.$;
if ( CKEDITOR.env.ie ) { // If Internet Explorer.
doc.attachEvent("onkeydown", DenIE_OnKeyDown ) ;
doc.attachEvent("onkeypress", DenIE_OnKeyPress ) ;
} else { // If Gecko.
doc.addEventListener( 'keydown', DenGecko_OnKeyDown, true ) ;
doc.addEventListener( 'keypress', DenGecko_OnKeyPress, true ) ;
}
});
} //Init
} );
I have console doc variable this returns
Object { $: HTMLDocument → blank }

Ckeditor not working with angular App

I am having issue with ckeditor4.When I run it independently its working fine.But when I trying to run it with my angular app its not working.Here is my sample code:
var initSample = ( function() {
var wysiwygareaAvailable = isWysiwygareaAvailable(),
isBBCodeBuiltIn = !!CKEDITOR.plugins.get( 'bbcode' );
return function() {
var editorElement = CKEDITOR.document.getById( 'editor' );
// :(((
if ( isBBCodeBuiltIn ) {
editorElement.setHtml(
'Hello world!\n\n' +
'I\'m an instance of [url=http://ckeditor.com]CKEditor[/url].'
);
}
// Depending on the wysiwygare plugin availability initialize classic or inline editor.
if ( wysiwygareaAvailable ) {
CKEDITOR.replace( 'editor' );
} else {
editorElement.setAttribute( 'contenteditable', 'true' );
CKEDITOR.inline( 'editor' );
// TODO we can consider displaying some info box that
// without wysiwygarea the classic editor may not work.
}
};
function isWysiwygareaAvailable() {
// If in development mode, then the wysiwygarea must be available.
// Split REV into two strings so builder does not replace it :D.
if ( CKEDITOR.revision == ( '%RE' + 'V%' ) ) {
return true;
}
return !!CKEDITOR.plugins.get( 'wysiwygarea' );
}
}
When I console after "isBBCodeBuiltIn = !!CKEDITOR.plugins.get( 'bbcode' )" line its consoling fine.But it is not entering inside return function() { }.Any suggestion?

How to change data produced by CKEditor dialog

I want to do some stuff with the image that is added using Image toolbar button in CKEditor.
I actually want to get the url and modify if required.
How can I do it?
I am able to do that stuff using dataFilter but only when image is directly pasted into the
editor. But dataFilter rule doesn't execute when image is added using default Image button in editor.
CKEDITOR.replace( 'idContent' );
CKEDITOR.on( 'instanceReady', function( e ) {
CKEDITOR.instances.idContent.dataProcessor.dataFilter.addRules( {
elements: {
"img": function (element) {
var imageSrcUrl = element.attributes.src;
// Do some stuffs here.
}
}
} );
} );
I achieved my purpose using following code
CKEDITOR.on( 'dialogDefinition', function( ev ) {
// Take the dialog name and its definition from the event data
var dialogName = ev.data.name,
dialogDefinition = ev.data.definition;
if ( dialogName == 'image' ) {
var onOk = dialogDefinition.onOk;
dialogDefinition.onOk = function( e ) {
var input = this.getContentElement( 'info', 'txtUrl' ),
imageSrcUrl = input.getValue();
//! Manipulate imageSrcUrl and set it
input.setValue( imageSrcUrl );
onOk && onOk.apply( this, e );
};
}
});

javascript change event fires when page loads - how to avoid this?

I have a form with chained select boxes. The zend controller sets the default values for these select boxes (values come from the db). I am a jquery novice.
$form->setDefaults($data);
a jquery file is loaded :
$(document).ready(function(){
// set up the chained select
$("#region").remoteChained("#country", "/ws/regionstructure");
$("#province").remoteChained("#region", "/ws/regionstructure");
$("#town").remoteChained("#province", "/ws/regionstructure");
});
The problem is that when the page loads it is triggering the change event for country and resetting all of the selects.
Here is the remoteChained jquery code that is being called:
/*
* Remote Chained - jQuery AJAX(J) chained selects plugin
*
* Copyright (c) 2010-2011 Mika Tuupola
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/mit-license.php
*
*/
(function($) {
$.fn.remoteChained = function(parent_selector, url, options) {
return this.each(function() {
/* Save this to self because this changes when scope changes. */
var self = this;
var backup = $(self).clone();
/* Handles maximum two parents now. */
$(parent_selector).each(function() {
$(this).bind("change", function() {
/* Build data array from parents values. */
var data = {};
$(parent_selector).each(function() {
var id = $(this).attr("id");
var value = $(":selected", this).val();
data[id] = value;
});
$.getJSON(url, data, function(json) {
/* Clear the select. */
$("option", self).remove();
/* Add new options from json. */
for (var key in json) {
if (!json.hasOwnProperty(key)) {
continue;
}
/* This sets the default selected. */
if ("selected" == key) {
continue;
}
var option = $("<option />").val(key).append(json[key]);
$(self).append(option);
}
/* Loop option again to set selected. IE needed this... */
$(self).children().each(function() {
if ($(this).val() == json["selected"]) {
$(this).attr("selected", "selected");
}
});
/* If we have only the default value disable select. */
if (1 == $("option", self).size() && $(self).val() === "") {
$(self).attr("disabled", "disabled");
} else {
$(self).removeAttr("disabled");
}
/* Force updating the children. */
$(self).trigger("change");
});
});
/* Force updating the children. */
$(this).trigger("change");
});
});
};
/* Alias for those who like to use more English like syntax. */
$.fn.remoteChainedTo = $.fn.remoteChained;
})(jQuery);
I don't see any issue with removing the change event, but the way that plugin works seems highly inefficient. I refactored this (untested), so give this a go and see how it works for you.
You can call it like so:
$( "#region" ).remoteChained( { parentSelector: "#country", url: "/ws/regionstructure" } );
$( "#province" ).remoteChained( { parentSelector: "#region", url: "/ws/regionstructure" } );
$( "#town" ).remoteChained( { parentSelector: "#province", url: "/ws/regionstructure" } );
This shouldn't trigger the change event. If you find you need to do this, you can do something like this:
$( '#region' ).trigger( 'change' );
Here is the new plugin code. Let me know if you have any issues with it:
( function( $ ) {
$.fn.remoteChained = function ( options ) {
var defaults = { },
settings = $.extend( { }, defaults, options );
return this.each( function () {
var el = $( this ),
parent = $(settings.parentSelector),
data = { };
parent.each( function () {
var el = $(this);
data[ el.attr( 'id' ) ] = el.find( ':selected' ).val();
});
parentSelector.bind( 'change.remotechanged', function ( e ) {
var request = $.ajax( { url: settings.url, data: data } );
request.done( function ( response ) {
var newOption;
el.find( 'option' ).remove();
for ( var key in response ) {
if ( !response.hasOwnProperty( key ) ) {
continue;
}
newOption = $( '<option />' )
.val( key )
.append( response[ key ] );
key === 'selected' && newOption.attr( 'selected', 'selected' );
newOption.appendTo( el );
}
if ( el.find( 'option' ).length === 1 && el.val() === '' ) {
el.attr( 'disabled', 'disabled' );
} else {
el.removeAttr( 'disabled' );
}
});
});
});
};
})( jQuery );

Categories