Add a class to the 'Nearest' TD from my cursor in a plugin - ckeditor

I'm trying to create a plugin to add some preset style to a table cell.
Step-by-step:
User click in a cell.
User click on my plugin button in the toolbar
Select a style
A class attribute is add to the closest TD
I'm having a hard time with the 4th point. How can I know where my cursor is in the source? How can I select the closest TD? The cursor must be between a <td> </td>. If there is no TD around nothing happen.
The cursor can be between any <Tag> as long as they are in a <td>.

// nearest element that surrounds your cursor
var el = editor.getSelection().getStartElement();
while (el) {
// if element is <td>, set class attribute and break loop
if (el.getName() == 'td') {
el.setAttribute('class', 'myClass');
break;
}
// otherwise, continue with parent element
// until you find <td> or there are no more elements
el = el.getParent();
}

Related

get the Text of an element with out getting the element into view port

Following is my method where tableComponent is the table body element.
This method works fine when the text is visible in a row, but if the row has a scrolling and the text is out of view port, the method fails.
I tried the CSS as well, with out luck...
If I use the scroltoview option, I can get the text, but this is kind of a bootstrap, to scroll to the element, I need to find the right row and column, and to find the row and column, I only knows the text that it could appear in that cell.
This is Java, Selenium webdriver
public IUIElement getRowContainingText(final String text) {
return tableComponentElement.findUIElement(By
.xpath(".//tr[*[self::td|self::th]//text()[contains(.,\"" + text + "\")]]"));
}
Alternate solution-
List<webElement>rows=tableComponentElement.findElements(By.tagnamr("tr"));
for(webElement element:rows)
{
List<String>tabledata=rows.findElements(By.tagName("td"));
String desiredText=tableData.get(index);
//index will be the postion where text will appear in each row
}

How to indent the first line of a paragraph in CKEditor

I'm using CKEditor and I want to indent just the first line of the paragraph. What I've done before is click "Source" and edit the <p> style to include text-indent:12.7mm;, but when I click "Source" again to go back to the normal editor, my changes are gone and I have no idea why.
My preference would be to create a custom toolbar button, but I'm not sure how to do so or where to edit so that clicking a custom button would edit the <p> with the style attribute I want it to have.
Depending on which version of CKE you use, your changes most likely disappear because ether the style attribute or the text-indent style is not allowed in the content. This is due to the Allowed Content Filter feature of CKEditor, read more here: http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter
Like Ervald said in the comments, you can also use CSS to do this without adding the code manually - however, your targeting options are limited. Either you have to target all paragraphs or add an id or class property to your paragraph(s) and target that. Or if you use a selector like :first-child you are restricted to always having the first element indented only (which might be what you want, I don't know :D).
To use CSS like that, you have to add the relevant code to contents.css, which is the CSS file used in the Editor contents and also you have to include it wherever you output the Editor contents.
In my opinion the best solution would indeed be making a plugin that places an icon on the toolbar and that button, when clicked, would add or remove a class like "indentMePlease" to the currently active paragraph. Developing said plugin is quite simple and well documented, see the excellent example at http://docs.ckeditor.com/#!/guide/plugin_sdk_sample_1 - if you need more info or have questions about that, ask in the comments :)
If you do do that, you again need to add the "indentMePlease" style implementation in contents.css and the output page.
I've got a way to indent the first line without using style, because I'm using iReport to generate automatic reports. Jasper does not understand styles. So I assign by jQuery an onkeydown method to the main iframe of CKEditor 4.6 and I check the TAB and Shift key to do and undo the first line indentation.
// TAB
$(document).ready(function(){
startTab();
});
function startTab() {
setTimeout(function(){
var $iframe_document;
var $iframe;
$iframe_document = $('.cke_wysiwyg_frame').contents();
$iframe = $iframe_document.find('body');
$iframe.keydown(function(e){
event_onkeydown(e);
});
},300);
}
function event_onkeydown(event){
if(event.keyCode===9) { // key tab
event.preventDefault();
setTimeout(function(){
var editor = CKEDITOR.instances['editor1'], //get your CKEDITOR instance here
range = editor.getSelection().getRanges()[0],
startNode = range.startContainer,
element = startNode.$,
parent;
if(element.parentNode.tagName != 'BODY') // If you take an inner element of the paragraph, get the parentNode (P)
parent = element.parentNode;
else // If it takes BODY as parentNode, it updates the inner element
parent = element;
if(event.shiftKey) { // reverse tab
var res = parent.innerHTML.toString().split(' ');
var aux = [];
var count_space = 0;
for(var i=0;i<res.length;i++) {
// console.log(res[i]);
if(res[i] == "")
count_space++;
if(count_space > 8 || res[i] != "") {
if(!count_space > 8)
count_space = 9;
aux.push(res[i]);
}
}
parent.innerHTML = aux.join(' ');
}
else { // tab
var spaces = " ";
parent.innerHTML = spaces + parent.innerHTML;
}
},200);
}
}

How to I focus on an element after it is added in CKEditor?

I am using CKEditor 4.4.1 with CKEDITOR.config.enterMode set to ENTER_P.
I am adding a new paragraph programmatically and then moving the cursor to the new element:
var element = new CKEDITOR.dom.element('p', editor.document);
element.appendBogus();
var range = editor.createRange();
range.setStartAt(referenceNode, CKEDITOR.POSITION_AFTER_END);
range.collapse(true);
editor.editable().insertElement( element, range );
range.moveToElementEditStart( element );
editor.getSelection().selectRanges( [ range ] );
This creates and inserts the element in the correct place. However, for some reason, the cursor is not placed in the newly created element.
Why is this happening?
Because I was using a elements that were not part of CKEditor to trigger the insertion, the CKEditor instance was losing focus.
In addition to the code above, I also had to do editor.focus().

Why delete does not work on CKEDITOR when selected?

I'm having a inline editable div. I can type, delete, add. Works great. I wanted the text within he div to be selected on focus (or if you click it). So I added the following to the code
var editor = CKEDITOR.instances.div#{attr};
var element = editor.document.getById('div#{attr}');
editor.getSelection().selectElement( element );
This works too. Fully selected on focus. However, if I press the delete key or any other character key to overwrite the programmatically selected text, it doesn't change. It's as if more than only the text is selected, and the browser doesn't let me delete it. If I select the text manually, it works.
The selection#selectElement method will start selection before passed element and end after it. This means that not only editable's content will be selected but also non-editable parts of contents outside it and therefore selection may not be editable.
This is a correct solution:
var editor = CKEDITOR.instances.editable,
el = CKEDITOR.document.getById( 'editable' ),
range = editor.createRange();
editor.focus();
range.selectNodeContents( el );
range.select();
But the easiest solution is to use selectAll command defined in selectall plugin:
editor.execCommand( 'selectAll' );

Get current style information in CKEditor

How can I get information about the states of styles present on the toolbar, at the current cursor position.
The documentation is completely silent on this issue. As far as I can tell from digging into the source code, CKEditor doesn't keep an internal log of what the styles are at the current position. It simply recalculates them on an as-needed basis, namely whenever it needs to add new styles to a selection.
Please keep in mind that CKEditor is actually building and modifying an entire DOM tree, and so the styles it applies cascade down the nodes. It appears that the only way you can pull the style information is to traverse up the DOM tree from your current cursor position, recording the style information from each ancestor until you reach the body node of the editor.
The following code should get you started traversing up the ancestor nodes:
//Or however you get your current editor
var editor = CKEDITOR.currentInstance;
//This will pull the minimum ancestor that encompasses the entire selection,
//so if you just want to use the cursor it will give you the direct parent
//node that the cursor is inside
var node = editor.getSelection().getCommonAncestor();
//This is all the ancestors, up to the document root
var ancestors = node.getParents();
//This is the editors body node; you don't want to go past this
var editor_body = editor.getBody();
var body_ancestors = editor_body.getParents();
//The ancestors list descends from the root node, whereas we want
//to ascend towards the root
for (var i = ancestors.length - 1; i >= 0; i--;) {
//Pull the node
var a = ancestors[i];
//You've hit the body node, break out of the loop
if (a.getText() == editor_body.getText()) break;
//This is a node between the cursor's node and the editor body,
//pull your styling information from the node here
}
Thanks to the customizability of CKEditors style interface, there isn't a single set of styles that can be checked for, nor do they follow the same form (for instance, some will be CSS styles, while others will be span elements with a particular class).
My suggestion is to check for just those styles which you actually care about, and ignore the rest. It'll make the code much simpler.
Here is another way (based on a few attached links).
You can get the current element position by editor.getSelection().getStartElement() - (editor is CKEDITOR.instances.%the editor instance%.
Now, you can then wrap the actual element for jquery (or use the jquery adapter..):
$(editor.getSelection().getStartElement().$)
This will give you an access to use the following plugin which resolves all the styles of a given element (both inline and inherited):
/*
* getStyleObject Plugin for jQuery JavaScript Library
* From: http://upshots.org/?p=112
*
* Copyright: Unknown, see source link
* Plugin version by Dakota Schneider (http://hackthetruth.org)
*/
(function($){
$.fn.getStyleObject = function(){
var dom = this.get(0);
var style;
var returns = {};
if(window.getComputedStyle){
var camelize = function(a,b){
return b.toUpperCase();
}
style = window.getComputedStyle(dom, null);
for(var i=0;i<style.length;i++){
var prop = style[i];
var camel = prop.replace(/\-([a-z])/g, camelize);
var val = style.getPropertyValue(prop);
returns[camel] = val;
}
return returns;
}
if(dom.currentStyle){
style = dom.currentStyle;
for(var prop in style){
returns[prop] = style[prop];
}
return returns;
}
return this.css();
}
})(jQuery);
(Taken from: jQuery CSS plugin that returns computed style of element to pseudo clone that element?)
All that is left to do is:
$(editor.getSelection().getStartElement().$).getStyleObject()
Now you can check for any style asigned to the element.
Another small tip will be - what are the styles for the current cursor position, every time the position or styles are changed:
In which case you can use attachStyleStateChange callback (which is pretty atrophied by itself since is can only return boolean indication for weather or not a certain style is applied to current position).
The good thing about it is - callback is being recieved when ever the style state is changed - that is - whenever the cursor position is moved to a position with different style attributes - Any different attribute and not just the attribute the listener was ment to verify (Taken from the API http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.editor.html#attachStyleStateChange)
Combining everything together to figure out what is the current applied styles on the current cursor position Every time something is changed:
editor.on('instanceReady', function () {
//editor.setReadOnly(true);
var styleBold = new CKEDITOR.style(CKEDITOR.config.coreStyles_bold);
editor.attachStyleStateChange(styleBold, function (state) {
var currentCursorStyles = $(editor.getSelection().getStartElement().$).getStyleObject();
// For instance, the font-family is:
var fontFamily = currentCursorStyles.fontFamily;
});
});

Resources