How to link count chars in CK editor textarea? - ckeditor

Ckeditor is magic, but it was programmed to mess with me.
I've linked to the CDN and instantiated a textarea that is given the id cke_quotation. In the original textarea, I had a jquery function that on keyup and focusout, there was a count for characters. Now I want to link this function to the ckeditor quotation, which has the id cke_quotation. It won't work, though. What am I doing wrong?

CKEditor doesn't work on plain textarea - it's working with contenteditable element instead. If you would like to listen for key events you'd need to listen to, so called, editable.
var editor = CKEDITOR.instances.quotation;
editor.editable().on( 'keydown', function( evt ){
console.log( 'keydown', evt );
// You could call editor.getData() to get current editor
// contents and then count anything you like.
} );
But instead of looking for events like keydown you should be more interested in more "input agnostic" event like change (because change might be caused by different sources, like paste, cut, drag and drop).
Then again if you're looking for word counting feature for CKE then why bother with creating your own plugin? You could simply use something like wordcount plugin.

Related

Pass Pasted Clipboard Image From CKeditor to Dropzone

We currently have code that handles all our image uploads via Dropzone.js. This includes functionality to paste from the clipboard and upload via dropzone.js, which currently works. This is that event code:
document.onpaste = function(event)
{
alert('pasted');
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
for (index in items) {
var item = items[index];
if (item.kind === 'file') {
// adds the file to your dropzone instance
myDropzone.addFile(item.getAsFile());
}
}
}
Following this, we have added a CKEditor (v4.10) html text editor to that page. The CKEditor has its own clipboard handling built in. If you activate the CKEditor (for example by clicking the text area), the CKEditor effectively takes control of the clipboard from that point. Which is correct, because we want the editor to be able to copy and paste text still.
However, CKEditor does not natively have image uploading built into it. It requires a plugin. But we would prefer not to use this plugin, and rather intercept the paste event, and if the data pasted is an image, pass that along to our dropzone.js handler instead.
While I am able to intercept that event, I am not sure what event data (if any) I can extract from the CKEditor paste event to pass along to the Dropzone handler. Here is the code so far:
var editor = CKEDITOR.instances.NoteText;
editor.on( 'paste', function( event )
{
alert('pasted ck');
console.dir(event);
//myDropzone.addFile(item.getAsFile());
} );
I have tried inspecting the event to see if anything is available for me to use, but don't seem to find anything.
Is what I'm trying to accomplish possible? Is it possible for me to somehow find and pass along the pasted event data from CKEditor to DropZone? Or am I going to have to implement the CKEditor image upload plugin?
Thanks.

CKEDITOR how to Identify scroll event

Does anyone know how to catch the 'scroll' event in CKEDITOR? there is easy to identify change and other events, but I am unable to cathc Scroll event..
CKEDITOR.instances[i].on('change', function() {alert('text changed!');});
but when want to use same for scroll it does not working
CKEDITOR.instances[i].on('scroll', function() {alert('I am scrolling!');});
does anyone know some workaround?
Thx a lot
M
First thing you need to know is that CKEditor's instance (which you get from CKEDITOR.instances object) is not a DOM element. It indeed fires some events like change, focus, blur, or save, but they are just short cuts or facades to more complex things.
Therefore, if you want to add a DOM event listener, then you need to retrieve the "editable" element (an element in which editing happens). It can be accessed by the editor.editable() method. However, the tricky thing about editable element is that it's not always available, it's not ready right after starting editor initialization and that editor may replace this element with a new one (usually after switching between modes). Therefore, editor fires a contentDom to notify that the new editable is available and the editable has an attachListener method which, unlike the on cleans the listener when editable is destroyed.
The way to use all those methods is explained in the documentation and there are code samples, but just to save you one click:
editor.on( 'contentDom', function() {
var editable = editor.editable();
editable.attachListener( editable.getDocument(), 'scroll', function() {
console.log( 'Editable has been scrolled' );
});
});
Update: I forgot that for 'scroll' event you have to listen on document. I updated the code above.

The view area of ckEditor sometimes shows empty at the start

I am using the following directive to create a ckEditor view. There are other lines to the directive to save the data but these are not included as saving always works for me.
app.directive('ckEditor', [function () {
return {
require: '?ngModel',
link: function ($scope, elm, attr, ngModel) {
var ck = ck = CKEDITOR.replace(elm[0]);
ngModel.$render = function (value) {
ck.setData(ngModel.$modelValue);
setTimeout(function () {
ck.setData(ngModel.$modelValue);
}, 1000);
}; }
};
}])
The window appears but almost always the first time around it is empty. Then after clicking the [SOURCE] button to show the source and clicking it again the window is populated with data.
I'm very sure that the ck.setData works as I tried a ck.getData and then logged the output to the console. However it seems like ck.setData does not make the data visible at the start.
Is there some way to force the view window contents to appear?
You can call render on the model at any time and it will simply do whatever you've told it to do. In your case, calling ngModel.$render() will grab the $modelValue and pass it to ck.setData(). Angular will automatically call $render whenever it needs to during its digest cycle (i.e. whenever it notices that the model has been updated). However, I have noticed that there are times when Angular doesn't update properly, especially in instances where the $modelValue is set prior to the directive being compiled.
So, you can simply call ngModel.$render() when your modal object is set. The only problem with that is you have to have access to the ngModel object to do that, which you don't have in your controller. My suggestion would be to do the following:
In your controller:
$scope.editRow = function (row, entityType) {
$scope.modal.data = row;
$scope.modal.visible = true;
...
...
// trigger event after $scope.modal is set
$scope.$emit('modalObjectSet', $scope.modal); //passing $scope.modal is optional
}
In your directive:
ngModel.$render = function (value) {
ck.setData(ngModel.$modelValue);
};
scope.$on('modalObjectSet', function(e, modalData){
// force a call to render
ngModel.$render();
});
Its not a particularly clean solution, but it should allow you to call $render whenever you need to. I hope that helps.
UPDATE: (after your update)
I wasn't aware that your controllers were nested. This can get really icky in Angular, but I'll try to provide a few possible solutions (given that I'm not able to see all your code and project layout). Scope events (as noted here) are specific to the nesting of the scope and only emit events to child scopes. Because of that, I would suggest trying one of the three following solutions (listed in order of my personal preference):
1) Reorganize your code to have a cleaner layout (less nesting of controllers) so that your scopes are direct decendants (rather than sibling controllers).
2) I'm going to assume that 1) wasn't possible. Next I would try to use the $scope.$broadcast() function. The specs for that are listed here as well. The difference between $emit and $broadcast is that $emit only sends event to child $scopes, while $broadcast will send events to both parent and child scopes.
3) Forget using $scope events in angular and just use generic javascript events (using a framework such as jQuery or even just roll your own as in the example here)
There's a fairly simple answer to the question. I checked the DOM and found out the data was getting loaded in fact all of the time. However it was not displaying in the Chrome browser. So the problem is more of a display issue with ckEditor. Strange solution seems to be to do a resize of the ckEditor window which then makes the text visible.
This is a strange issue with ckeditor when your ckeditor is hidden by default. Trying to show the editor has a 30% chance of the editor being uneditable and the editor data is cleared. If you are trying to hide/show your editor, use a css trick like position:absolute;left-9999px; to hide the editor and just return it back by css. This way, the ckeditor is not being removed in the DOM but is just positioned elsewhere.
Use this java script code that is very simple and effective.Note editor1 is my textarea id
<script>
$(function () {
CKEDITOR.timestamp= new Date();
CKEDITOR.replace('editor1');
});
</script>
Second way In controller ,when your query is fetch data from database then use th
is code after .success(function().
$http.get(url).success(function(){
CKEDITOR.replace('editor1');
});
I know, that this thread is dead for a year, but I got the same problem and I found another (still ugly) solution to this problem:
instance.setData(html, function(){
instance.setData(html);
});

jQuery children of cloned element not responding to events

Summary
I am using jQuery to clone a div ("boxCollection") containing groups ("groupBox") each of which contains a set of inputs. The inputs have change events tied to them at $(document).ready, but the inputs inside the cloned divs do not respond to the event triggers. I can not get this to work in IE7, IE8, or FF3.
Here is my sample code:
HTML:
<div class="boxCollection"><div class="groupBox" id="group_1"><input type="text"></input></div></div>
jQuery events:
$(".groupBox[id*='group']").change(function(){
index = $(this).attr("id").substring(6);
if($("input[name='collection_"+index+"']").val() == "")
{
$("input[name='collection_"+index+"']").val("Untitled Collection "+index);
}
});
jQuery clone statement:
$(".boxCollection:last").clone(true).insertAfter($(".boxCollection:last"));
Use live() to automatically put event handlers on dynamically created elements:
$(".groupBox[id*='group']").live("change", function() {
...
});
You appear to be putting a change() event handler on a <div> however (based on your sample HTML). Also, I would recommend not using an attribute selector for this. You've given it a class so instead do:
$("div.groupBox ...")...
Lastly, you are trying to give each text input a unique name. You don't say what your serverside technology is but many (most?) will handle this better than that. In PHP for example you can do:
And $_POST will contain an element "box" with an array of three values.
I'm not sure if this will work, but I'm going to give it a shot and say that you need to assign live events
$(".groupBox[id*='group']").live('change', function() { });
You'll probably have a problem with change and live in IE6/7, so I advise you to use the livequery plugin to resolve that issue.

JQuery: how do I see which events are defined on an element?

I use
$(window).bind( ... )
to set up event handlers, but for some reason I keep losing event handlers (i think).
Is there any way when debugging (firebug) to see which custom events have been added to a given element?
Yours
Andreas
All events bound by jQuery (e.g not inline events) can be accessed through .data
var $el = $('#someId');
var allEvents = $.data( $el , "events" );
or
$('#someId').data('events');
its very rare I bind events to the window object but the same notion should still apply so try $(window).data('events')
This does indeed work demo here (writes to console so use firefox + firebug)

Resources