I have a series of <td> elements within a table that, in my context, are "slots" of a space that a user can select. Each slot has an attribute (data-slot-stamp) that holds the ID (a timestamp) of the slot. When the user clicks a slot, that timestamp is added to another element's (.addButton) attribute data-selected-slots. If the user clicks the slot again, that slot is to be removed from the .addButton's data-selected-slots attribute.
The below snippet is working, except on the first click IF a user is removing the slot from their selection.
Example of desired behavior:
User clicks any slot
The value of that slot's data-slot-stamp attribute is added to the value of the data-selected-slots attribute of the .addButton element
If the user clicks that same slot again, the value of that slot's data-slot-stamp attribute should be removed from the value of the data-selected-slots attribute of the .addButton element.
What's happening in my case:
User clicks any slot
The value of that slot's data-slot-stamp attribute is added to the value of the data-selected-slots attribute of the .addButton element
If the user clicks that same slot again (but ONLY if it was the FIRST slot clicked since a page refresh) the value of that slot's data-slot-stamp attribute is NOT removed, but stays in the value of the data-selected-slots attribute.
On subsequent clicks of any slot, the functionality works as expected but the initially clicked slot's data is never removed.
Html Structure:
<table class="spacesTable">
<tr>
<td class="slot used unselected" data-slot-stamp="123456789">
Slot 1
</td>
<td class="slot used unselected" data-slot-stamp="987654321">
Slot 2
</td>
<td class="slot used unselected" data-slot-stamp="654321987">
Slot 3
</td>
<td>
<div class="addButton" data-selected-slots="">
Add Button
</div>
</td>
</tr>
</table>
Relevant jQuery:
$('.spacesTable').on('click', '.slot.used', function() {
var curAtts = $(this).siblings('.addButton').attr('data-selected-slots');
var clickedStamp = $(this).attr('data-slot-stamp');
if ($(this).hasClass('unselected')) {
$(this).addClass('selected').removeClass('unselected');
//Add to the values stored in the data-selected-slots attr of the button for this row
var spacer = ',';
if (!curAtts) {
curAtts = '';
spacer = '';
}
$(this).siblings('.addButton').attr('data-selected-slots', clickedStamp+spacer+curAtts);
} else if ($(this).hasClass('selected')) {
$(this).removeClass('selected').addClass('unselected');
//check to see if the slot timestamp is in the button's data-selected-slots attr, and if so, remove it
var findStamp = curAtts.indexOf(clickedStamp);
if (findStamp != -1) {
curAtts = curAtts.replace(clickedStamp+',','');
$(this).siblings('.addButton').attr('data-selected-slots', curAtts);
}
}
});
Because the ","
change this:
curAtts = curAtts.replace(clickedStamp+',','');
with something like:
if (curAtts.indexof(",") > 0) {
curAtts = curAtts.replace(clickedStamp+',','');
}else{
curAtts = curAtts.replace(clickedStamp,'');
}
hope it helps
Related
I am new to programming and JS as can be seen in my code. The background colour and text on the page changes according to which target <li> tag is clicked, possibly i.e. function, objects, arrays or if statements using eventListeners and events handlers.
I am looking for inspiration here so that I can finally understand how programming really works.
See my code below.
let navLink1 = document.querySelector('color1');
let navLink2 = document.querySelector('color2');
let navLink3 = document.querySelector('color3');
let navLink4 = document.querySelector('color4');
let p1 = document.querySelector('para');
navLink1.addEventListener('click', function (e) {
document.body.style.background = "color1";
document.innerHTML(p1) = "New text!";
});
navLink2.addEventListener('click', function (e) {
document.body.style.background = "color2";
document.innerHTML(p1) = "New text!";
});
navLink3.addEventListener('click', function (e) {
document.body.style.background = "color3";
document.innerHTML(p1) = "New text!";
});
navLink4.addEventListener('click', function (e) {
document.body.style.background = "color4";
document.innerHTML(p1) = "New text!";
});
<ul class ='nav'>
<li class ='color1'><a href=''>color1</a></li>
<li class ='color2'><a href=''>color2</a></li>
<li class ='color3'><a href=''>color3</a></li>
<li class ='color4'><a href=''>color4</a></li>
</ul>
<h2>The text in the <p> tag below changes according to clicked link in the menu</h2>
<p class ='para'>This is (color)</p>
<!-- if color1 is clicked in the menu then the <body> background will be changed to color1 and the innerHTML will also be changed to color1. The background color and targeted text changes according to the menu item clicked ->
There are a few issues with that code, but basically: Yes, you can use a single event handler to handle all four links. The process is called "event delegation" — delegating the handling of the event to some ancestor element. In this case, the ul makes a good place to put a click handler. click events "bubble" from the target element (the li) to its parent, then its parent, etc., so we can handle a click on any li in the ul by handling it on the ul.
See comments:
// Handle click on the `ul.nav`:
document.querySelector(".nav").addEventListener("click", function(event) {
// `event.target` is the element the event was targeted at (the `li`
// element). We can use the `closest` method to find the first element
// starting with that one and then working through its parent, parent's
// parent, etc., until we find one that matches the selector. The
// selector looks for an element that has a `data-color` attribute.
const li = event.target.closest("[data-color]");
// If we found one and it's within the element we hooked `click` on
// (the `ul`), we handle the click
if (li && this.contains(li)) {
// Get the color from the attribute
const color = li.getAttribute("data-color");
// Assign it to the body
document.body.style.backgroundColor = color;
// Show the color name in the `span`
document.querySelector(".color").textContent = color;
}
});
li[data-color] {
cursor: pointer;
}
<ul class="nav">
<!-- I've removed the classes and set a data-* attribute with the color to set -->
<!-- I've also removed the `a` elements. Because they're links, clicking follows them -->
<li data-color="#E0E0E0">color1</li>
<li data-color="#D0D0D0">color2</li>
<li data-color="#C0C0C0">color3</li>
<li data-color="#B0B0B0">color4</li>
</ul>
<!-- Note that I've changed the opening angle bracket in the `p` tag below to its
character reference form (<) so it's not handled as a paragraph -->
<h2>The text in the <p> tag below changes according to clicked link in the menu</h2>
<!-- I've added a span with a class so we can set the color name -->
<p class="para">This is <span class="color">(no color yet)</span></p>
More
Introduction to events
data-* attributes
CSS selectors
closest
contains
If you wanted to do it with the a elements (so we get default tabbing and "activation" on various user gestures, like pressing Enter), we can do much the same thing just with a event.preventDefault() call to tell the browser not to follow the href of the a. When doing that, it's usually best to have the href indicate to the user what it's going to do, so we can use that rather than a data-* attribute:
// The prefix used on `a` element `href`s:
const prefix = "#set-color-";
// Handle click on the `ul.nav`:
document.querySelector(".nav").addEventListener("click", function(event) {
// `event.target` is the element the event was targeted at (the `li`
// element). We can use the `closest` method to find the first element
// starting with that one and then working through its parent, parent's
// parent, etc., until we find one that matches the selector. The
// selector looks for an `a` element whose `href` *starts with* the
// text `set-color-`
const anchor = event.target.closest(`a[href^="${prefix}"]`);
// If we found one and it's within the element we hooked `click` on
// (the `ul`), we handle the click
if (anchor && this.contains(anchor)) {
// Get the color from the `href` by grabbing the part after the
// prefix
const color = anchor.getAttribute("href").substring(prefix.length);
// Assign it to the body
document.body.style.backgroundColor = color;
// Show the color name in the `span`
document.querySelector(".color").textContent = color;
// Prevent the default of following the anchor
event.preventDefault();
}
});
li[data-color] {
cursor: pointer;
}
<ul class="nav">
<!-- I've removed the classes and set a data-* attribute with the color to set -->
<!-- I've also removed the `a` elements. Because they're links, clicking follows them -->
<li>color1</li>
<li>color2</li>
<li>color3</li>
<li>color4</li>
</ul>
<!-- Note that I've changed the opening angle bracket in the `p` tag below to its
character reference form (<) so it's not handled as a paragraph -->
<h2>The text in the <p> tag below changes according to clicked link in the menu</h2>
<!-- I've added a span with a class so we can set the color name -->
<p class="para">This is <span class="color">(no color yet)</span></p>
I am using some code based on the following JSFiddle. The intention is to show more information when the user clicks the "Show Extra" link.
The problem that I'm having is that when the link is clicked on all but the bottom row of the table the hidden element is shown briefly and then closes.
I am populating my table using template strings in javascript. Here is the code that I use to add rows to the table:
this.addRecordToTable = function(bet, index, id){
console.log(index);
console.log($.data(bet));
var butId = id.toString();
if (bet.bookies == null){
bet.bookies = "";
}
if (bet.bet == null){
bet.bet = "";
}
var newRow = `
<tr>
<td>${bet.date}</td>
<td>${bet.bookies}</td>
<td>${bet.profit}</td>
<td><button id=${butId}>Delete</button></td>
<td>Show Extra</td>
</tr>
<tr>
<td colspan=\"5\">
<div id=\"extra_${index}\" style=\"display: none;\">
<br>hidden row
<br>hidden row
<br>hidden row
</div>
</td>
</tr>
`
console.log(newRow);
console.log("#"+butId);
$(newRow).appendTo($("#betTable"));
$("#"+butId).click(
function()
{
if (window.confirm("Are you sure you want to delete this record?"))
{
var rec = new Records();
rec.removeRecordAt(index);
$("#betTable tbody").remove();
var c = new Controller();
c.init();
}
});
$("a[id^=show_]").click(function(event) {
$("#extra_" + $(this).attr('id').substr(5)).slideToggle("slow");
event.preventDefault();
});
}
EDIT:
I had to change $("a[id^=show_]").click to $("a[id=show_"+index).click..., as the event handler was being added to each element every time I added a new element. Thanks to #freedomn-m.
This code:
$("a[id^=show_]")
adds a new event handler to every existing link as well as the new one as it's not ID/context specific so all the show a's match the selector.
You need to add the context (newRow) or use the existing variable(s) as part of the loop that are already defined, eg:
$("a[id^=show_]", newRow)
$("a#show_" + index)
(or any other variation that works).
An alternative would be to use even delegation for the dynamically added elements, eg:
$(document).on("click", "a[id^=show_]", function...
in which case you'd only need to define/call the event once and it would be fired for new elements (ie put that outside the new row loop).
I have a buttton inside a table.
<input type="button" onclick="I_Have('IS-12-78',this)" class="i_have_it" value="Yes, I have">
When I click the button I need to get the value of select box in the same row.
I haven't maintained separate class or id for this select box.
function I_Have(itm_id,obj)
{
xmlReq=new XMLHttpRequest();
xmlReq.open("POST","./requests/store.jsp",false);
xmlReq.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlReq.send("item="+itm_id+"&wt=1");
if(xmlReq.responseText.trim()!="")
{
alert(xmlReq.responseText)
obj.style.display="none"
return false
}
//obj.innerHTML("Used")
obj.setAttribute('onclick','I_Dont_Have("'+itm_id+'",this)')
obj.setAttribute('value','No, I dont have')
obj.setAttribute('class','i_dont_have_it')
}
Using "this"(passed into the function) property can I get the value of select box in javascript.
You can use Dom object's previousElementSibling property:
this.previousElementSibling.value
Have a look on this fiddle.
But this will only work if select is immediate sibling of your button element.
If that's not your case then first get the parent element then reach to your required element:
window.callback = function(obj){
var parent = obj.parentElement;
// Uncomment following to get value from nearest <TD> if your htmls is structured in table
//parent = parent.parentElement;
var select = parent.getElementsByTagName('select')[0];
alert(select.value);
}
Here is updated fiddle.
<input type="checkbox" onfocus="EnsureSelectionHandlerOnFocus(event,this,12)" onclick="ToggleAllItems(event,this,12)" title="Select or deselect all items" class="s4-selectAllCbx">
Whenever I refresh the page, these attributes have been changed with "12" in both EnsureSelectionHandlerOnFocus and ToggleAllItems. Therefore, I would like to get "12" of the onfocus and set "12" to the onlick attribute with Javascript?
If I understand you correct, you want to extract the number - the last param of the inline event listeners?
//get the event, example EnsureSelectionHandlerOnFocus(event,this,12)
var event = document.getElementById('cbSelectAll').getAttribute('onfocus');
//extract the params, example event,this,12
var params = event.match(/\(([^)]+)\)/)[1];
//get the last param, example 12
var number = params.split(',')[2];
//outputs 12
console.log(number);
To set the onclick event number param :
var click = 'ToggleAllItems(event, this, NUMBER)';
click = click.replace('NUMBER', number);
document.getElementById('cbSelectAll').setAttribute('onclick', click);
Example alternatives to document.getElementById
//selecting the checkbox by its class (if the class is unique)
var element = document.querySelector('.s4-selectAllCbx');
console.log(element);
//alternatively selecting the checkbox by an attribute
var element = document.querySelector('[title="Select or deselect all items"]');
console.log(element);
or add an unique name to the checkbox :
<input type="checkbox" name="myCheckBox" ...>
var element = document.querySelector('[name="myCheckBox"]');
console.log(element);
both will return the checkbox. If multiple elements has the same class or the same attribute, the first occurrence in the document will be returned. Giving the checkbox an unique class is prefered, imho, since you will have to update your code each time you change the attribute of the title.
I have my CKEDITOR form prepopulated with hidden table which is being submitted together with user inputed text. This works fine, but sometimes user presses backspace too many times and deletes the hidden table.
Is there a way to block editing on this hidden table inside ckeditor textarea? So when user presses backspace the hidden table isn't affected and stays in.
As soon as CKEDITOR instance is ready this source (bellow) is put inside CkEditor Textarea (using setData() attribute) and User only sees the returned <p></p> value. In this case its <p>I really think I can do this!</p>. Its a description of his profile and he can keep it and edit it. The rest is hidden and only visible in e-mail when form is submitted. Its strange that <p></p> is on top but if user presses Backspace couple times the table gets deleted and therefor not submitted.
<span id="messageTemplate1" class="message">
<p>I really think I can do this!</p>
<table class="hide" style="font-size: 12px;">
<tbody>
<tr class="hide">
<td>
Application sent by <strong>Matt Faro</strong> for Audition: Actors Needed
</td>
</tr>
<tr class="hide">
<td>
Reply to applicant directly: mantas#mantas.co or visit full profile: http://www.globalcastingcenter.com/talent/jack-bolton
</td>
</tr>
</tbody>
</table>
<table class="hide" style="font-size: 12px;">
<tbody>
<tr class="hide">
<td><strong>Short Profile Summary:</strong></td>
</tr>
</tbody>
</table>
<table class="hide" style="font-size: 12px;">
<tbody>
<tr class="hide">
<td>
<img alt="" src="http://globalcastingcenter.com/talent_images/4164035_258551_foto.png?Action=thumbnail&Width=144&Height=215" />
</td>
</tr>
</tbody>
</table>
<table style="font-size: 12px;" class="hide">
<tbody>
<tr class="hide">
<td><strong>Areas:</strong></td>
<td>Actor,Extra</td>
</tr>
<tr class="hide">
<td><strong>Country:</strong></td>
<td>WORLDWIDE,Any</td>
</tr>
<tr class="hide">
<td><strong>Age:</strong></td>
<td>26</td>
</tr>
</tbody>
</table>
</span>
Now when I load your plugin my CKeditor box disapears, please press "Apply" on testing page http://gcc-july.themantas.co.uk/auditions/actors-needed please login first to be able to access the message box Login name: tiknius#gmail.com pssw: test
My config file:
CKEDITOR.editorConfig = function( config )
{
config.toolbar = 'MyToolbar';
config.toolbar_MyToolbar =
[
{ name: 'clipboard', items : [ 'Undo','Redo' ] },
{ name: 'styles', items : ['FontSize' ] },
{ name: 'basicstyles', items : [ 'Bold','Italic'] },
{ name: 'paragraph', items : ['Outdent','Indent' ] },
];
config.removePlugins = 'contextmenu';
config.forcePasteAsPlainText = true;
config.pasteFromWordRemoveFontStyles = true;
config.pasteFromWordRemoveStyles = true;
config.extraPlugins = 'cwjdsjcsconfineselection';
config.startupShowBorders = false;
config.disableObjectResizing = true;
};
This is how the box looks when I disable your plugin: http://screencast.com/t/Kc2bIOU8md2
I use your suggested HTML structure.
I had to play around with it a bit to get it to work. I added lots of documentation to the plugin code, if you have any questions after reading it through let me know.
I'm including an updated version of your content block and the plugin code block.
Here is your updated content block. It wasn't working when wrapped in the <span> tag, so I wrapped it in a table.
You may not like the border and resizing outlines that appear around the data cell, if that's the case, add these settings to your configuration:
config.startupShowBorders = false;
config.disableObjectResizing = true;
Some notes:
The empty <td> before your starting content is needed, it prevents the user from using "Ctrl A" to select everything which would allow them to delete the hidden table.
I removed the <p> tag from the starting content as it acted funky in this structure.
The <td> that holds the hidden tables has a character, it prevents the user from using "Ctrl A" to select everything which would allow them to delete the hidden table. It causes the cursor to get lost if you delete everything to the right of the cursor, but you can click on the content to begin editing again.
The contenteditable="false" attribute is used by CkEditor and is needed, but it doesn't do the whole job. You can try out the new HTML without activating the plugin to see what effect it has by itself.
There are notes in the plugin code about the classes and ID I used.
<!-- Begin Wrapper Table that Replaces <span> element -->
<table id="messageTemplate1" class="message cwjdsjcs_editable">
<tbody>
<tr>
<td class="cwjdsjcs_not_editable" contenteditable="false">
</td>
<td id="cwjdsjcs_editable_id">
I really think I can do this!
</td>
</tr>
<tr class="cwjdsjcs_not_editable" contenteditable="false">
<td colspan="2">
<!-- Begin Original Content -->
<table class="hide" style="font-size: 12px; display:none;">
<tbody>
<tr class="hide">
<td>
Application sent by <strong>Matt Faro</strong> for Audition: Actors Needed
</td>
</tr>
<tr class="hide">
<td>
Reply to applicant directly: mantas#mantas.co or visit full profile: http://www.globalcastingcenter.com/talent/jack-bolton
</td>
</tr>
</tbody>
</table>
<table class="hide" style="font-size: 12px; display:none;">
<tbody>
<tr class="hide">
<td><strong>Short Profile Summary:</strong></td>
</tr>
</tbody>
</table>
<table class="hide" style="font-size: 12px; display:none;">
<tbody>
<tr class="hide">
<td>
<img alt="" src="http://globalcastingcenter.com/talent_images/4164035_258551_foto.png?Action=thumbnail&Width=144&Height=215" />
</td>
</tr>
</tbody>
</table>
<table style="font-size: 12px; display:none;" class="hide">
<tbody>
<tr class="hide">
<td><strong>Areas:</strong></td>
<td>Actor,Extra</td>
</tr>
<tr class="hide">
<td><strong>Country:</strong></td>
<td>WORLDWIDE,Any</td>
</tr>
<tr class="hide">
<td><strong>Age:</strong></td>
<td>26</td>
</tr>
</tbody>
</table>
<!-- End Original Content -->
</td>
</tr>
</tbody>
</table>
<!-- End Wrapper Table that Replaces <span> element -->
Here's the plugin code, it's called "cwjdsjcsconfineselection".
To add the plugin:
Create a folder called "cwjdsjcsconfineselection" in the plugins directory: ckeditor/plugins/
Create a file called "plugins.js" in that directory and paste the code below into that file. My mistake: file is named plugin.js, not plugin(s).js.
If you already have extra plugins, add "cwjdsjcsconfineselection" to the extraPlugins config setting, otherwise add this setting to your configuration:
config.extraPlugins = 'cwjdsjcsconfineselection';
The plugin should work the next time you load the editor.
For my situation, I have a dialog box appear when the user clicks in a non-editable area to explain why the cursor was moved back to the previous selection. That doesn't seem necessary for your usage, so I commented it out.
/*
Plugin that prevents editing of elements with the "non-editable" class as well as elements outside of blocks with "editable" class.
*/
//* ************************** NOTES *************************** NOTES ****************************
/*
The "lastSelectedElement" variable is used to store the last element selected.
This plugin uses the "elementspath" plugin which shows all elements in the DOM
parent tree relative to the current selection in the editing area.
When the selection changes, "elementsPathUpdate" is fired,
we key on this and loop through the elements in the tree checking the classes assigned to each element.
Three outcomes are possible.
1) The non-editable class is found:
Looping stops, the current action is cancelled and the cursor is moved to the previous selection.
The "selectionChange" hook is fired to set the reverted selection throughout the instance.
2) The editable class is found during looping, the "in_editable_area" flag is set to true.
3) Neither the editable or the non-editable classes are found (user clicked outside your main container).
The "in_editable_area" flag remains set to false.
If the "in_editable_area" flag is false, the current action is cancelled and the cursor is moved to the previous location.
The "selectionChange" hook is fired to set the reverted selection throughout the instance.
If the "in_editable_area" flag is true,
the "lastSelectedElement" is updated to the currently selected element and the plugin returns true.
---------------
If you don't want the elements path to be displayed at the bottom of the editor window,
you can hide it with CSS rather than disabling the "elementspath" plugin.
The elementspath plugin creates and is left active because we are keying on changes to the path in our plugin.
#cke_path_content
{
visibility: hidden !important;
}
---------------
CSS Classes and ID that the plugin keys on. Use defaults or update variables to use your preferred classes and ID:
var starting_element_id = ID of known editable element that always occurs in the instance.
Don't use elements like <table>, <tr>, <br /> that don't contain HTML text.
Default value = cwjdsjcs_editable_id
var editable_class = class of editable containers.
Should be applied to all top level elements that contain editable elements.
Default = cwjdsjcs_editable
var non_editable_class = class of non-editable elements within editable containers
Apply to elements where all child elements are non-editable.
Default = cwjdsjcs_not_editable
*/
//* ************************** END NOTES *************************** END NOTES ****************************
// Register the plugin with the editor.
// http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.plugins.html
CKEDITOR.plugins.add( 'cwjdsjcsconfineselection',
{
requires : [ 'elementspath' ],
// The plugin initialization logic goes inside this method.
// http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.pluginDefinition.html#init
init: function( editor )
{
editor.on( 'instanceReady', function( instance_ready_data )
{
// Create variable that will hold the last allowed selection (for use when a non-editable selection is made)
var lastSelectedElement;
editor.cwjdsjcs_just_updated = false;
// This section starts things off right by selecting a known editable element.
// *** Enter the ID of the element that should have initial focus *** IMPORTANT *** IMPORTANT ***
var starting_element_id = "cwjdsjcs_editable_id";
var resInitialRange = new CKEDITOR.dom.range( editor.document );
resInitialRange.selectNodeContents( editor.document.getById( starting_element_id ) );
resInitialRange.collapse();
var selectionObject = new CKEDITOR.dom.selection( editor.document );
editor.document.focus();
selectionObject.selectRanges( [ resInitialRange ] );
var sel = editor.getSelection();
var firstElement = sel.getStartElement();
var currentPath = new CKEDITOR.dom.elementPath( firstElement );
// Set path for known editable element, fire "selectionChange" hook to update selection throughout instance.
editor._.selectionPreviousPath = currentPath;
editor.fire( 'selectionChange', { selection : sel, path : currentPath, element : firstElement } );
}); // *** END - editor.on( 'instanceReady', function( e )
// When a new element is selected by the user, check if it's ok for them to edit it,
// if not move cursor back to last know editable selection
editor.on( 'elementsPathUpdate', function( resPath )
{
// When we fire the "selectionChange" hook at the end of this code block, the "elementsPathUpdate" hook fires.
// No need to check because we just updated the selection, so bypass processing.
if( editor.cwjdsjcs_just_updated == true )
{
editor.cwjdsjcs_just_updated = false;
return true;
}
var elementsList = editor._.elementsPath.list;
var in_editable_area = false;
var non_editable_class = "cwjdsjcs_not_editable";
var editable_class = "cwjdsjcs_editable";
for(var w=0;w<elementsList.length;w++){
var currentElement = elementsList[w];
// Sometimes a non content element is selected, catch them and return selection to editable area.
if(w == 0)
{
// Could change to switch.
if( currentElement.getName() == "tbody" )
{
in_editable_area = false;
break;
}
if( currentElement.getName() == "tr" )
{
in_editable_area = false;
break;
}
}
// If selection is inside a non-editable element, break from loop and reset selection.
if( currentElement.hasClass(non_editable_class) )
{
in_editable_area = false;
break;
}
if( currentElement.hasClass(editable_class) ) {
in_editable_area = true;
}
console.log(currentElement);
console.log(currentElement.getName());
}
// if selection is within an editable element, exit the plugin, otherwise reset selection.
if( in_editable_area ) {
lastSelectedElement = elementsList[0];
return true;
}
var resRange = new CKEDITOR.dom.range( editor.document );
resRange.selectNodeContents( lastSelectedElement );
resRange.collapse();
editor.getSelection().selectRanges( [ resRange ] );
resRange.endContainer.$.scrollIntoView();
// Open dialog window:
// It tells user they selected a non-editable area and cursor has been returned to previous selection
// currentEditorName = editor.name;
// openResDefaultDialog(currentEditorName);
try
{
var sel = editor.getSelection();
var firstElement = sel.getStartElement();
var currentPath = new CKEDITOR.dom.elementPath( firstElement );
editor.cwjdsjcs_just_updated = true;
editor._.selectionPreviousPath = currentPath;
editor.fire( 'selectionChange', { selection : sel, path : currentPath, element : firstElement } );
}
catch (e)
{}
});
} // *** END - init: function( editor )
}); // ************************************************************************************* END - CKEDITOR.plugins.add
To test that the plugin is loaded add an alert after the instance ready trigger:
editor.on( 'instanceReady', function( instance_ready_data )
{
alert("instanceReady");
To test that the plugin is being triggered when the selection changes, add an alert after the elementsPathUpdate trigger:
editor.on( 'elementsPathUpdate', function( resPath )
{
alert("elementsPathUpdate");
I realize that this is closed and solved, but here's an option:
Add the table just in time after the user submits your form or however your CKE content is being used. Simply don't add the invisible table, but when the user clicks "submit", add it then to whatever is being posted. Alternatively, if you need to edit it later, just remove it before inserting to the editor and then add it once again Just In Time before posting. No hacking of the CKE core and no plugins required as the action happens outside CKE.
I had a similar requirement but didn't find my answer online.
In my case, I want to support the tab character in the editor by adding a pre element to the content:
editor.on('key', function(ev) {
if (ev.data.keyCode == 9) { // TAB
// data-tab attribute added so we can identify it later
var tabHtml = '<pre data-tab="true" style="display:inline;"> </pre>';
var tabElement = CKEDITOR.dom.element.createFromHtml(tabHtml, editor.document);
editor.insertElement(tabElement);
ev.cancel();
}
});
But now the user can use the arrow keys or click the mouse and start editing inside the pre element. So I listen to the 'click' and 'keyup' events and move the cursor if they are inside the pre.
// this prevents the user from typing inside the tab span
var moveCursorOutOfTab = function() {
var ranges = editor.getSelection().getRanges();
if (ranges.length == 1) {
var parent = ranges[0].startContainer.getParent();
// is the cursor is inside a tab element
if (parent && parent.getAttribute('data-tab') == 'true') {
var newRange = editor.createRange();
newRange.setStartAfter(parent);
newRange.setEndAfter(parent);
// move the cursor after the tab element
editor.getSelection().selectRanges([newRange]);
}
}
};
// wait until the editor is initialized
editor.on('contentDom', function() {
var editable = editor.editable();
// listen for clicks
editable.attachListener(editable, 'click', function(ev) {
moveCursorOutOfTab();
});
// must use the keyup event because we want to
// act after any cursor movements
editor.document.on('keyup', function(ev) {
// check for left and right arrow keys
if (ev.data.getKey() == 37 || ev.data.getKey() == 39) {
moveCursorOutOfTab();
}
});
});