Insert HTML in NicEdit WYSIWYG - javascript

How can I insert text/code at the cursors place in a div created by NicEdit?
I've tried to read the documentation and create my own plugin, but I want it to work without the tool bar (Modal Window)

This is a quick solution and tested in firefox only. But it works and should be adaptable for IE and other browsers.
function insertAtCursor(editor, value){
var editor = nicEditors.findEditor(editor);
var range = editor.getRng();
var editorField = editor.selElm();
editorField.nodeValue = editorField.nodeValue.substring(0, range.startOffset) +
value +
editorField.nodeValue.substring(range.endOffset, editorField.nodeValue.length);
}

Insert Html Plugin
Don't know if this will help or not, but this is the plugin I created for inserting Html at the cursor position. The button opens a content pane and I just paste in the html I want and submit. Works for me!
var nicMyhtmlOptions = {
buttons : {
'html' : {name : 'Insert Html', type : 'nicMyhtmlButton'}
},iconFiles : {'html' : '/nicedit/html_add.gif'}
};
var nicMyhtmlButton=nicEditorAdvancedButton.extend({
addPane: function () {
this.addForm({
'': { type: 'title', txt: 'Insert Html' },
'code' : {type : 'content', 'value' : '', style : {width: '340px', height : '200px'}}
});
},
submit : function(e) {
var mycode = this.inputs['code'].value;
this.removePane();
this.ne.nicCommand('insertHTML', mycode );
}
});
nicEditors.registerPlugin(nicPlugin,nicMyhtmlOptions);
I used the html_add icon from Silk Icons, pasted onto a transparent 18 x 18 and saved as gif in the same folder as nicEditorIcons.gif.

It works for me when I use:
function neInsertHTML(value){
$('.nicEdit-main').focus(); // Without focus it wont work!
// Inserts into first instance, you can replace it by nicEditors.findEditor('ID');
myNicEditor.nicInstances[0].nicCommand('InsertHTML', value);
}

The way I solved this was to make the nicEdit Instance div droppable, using jQuery UI; but to also make all of the elements within the div droppable.
$('div.nicEdit-main').droppable({
activeClass: 'dropReady',
hoverClass: 'dropPending',
drop: function(event,ui) {
$(this).find('.cursor').removeClass('cursor');
},
over: function(event, ui) {
if($(this).find('.cursor').length == 0) {
var insertEl = $('<span class="cursor"/>').append($(ui.draggable).attr('value'));
$(this).append(insertEl);
}
},
out: function(event, ui) {
$(this).find('.cursor').remove();
},
greedy: true
});
$('div.nicEdit-main').find('*').droppable({
activeClass: 'dropReady',
hoverClass: 'dropPending',
drop: function(event,ui) {
$(this).find('.cursor').removeClass('cursor');
},
over: function(event, ui) {
var insertEl = $('<span class="cursor"/>').append($(ui.draggable).attr('value'));
$(this).append(insertEl);
},
out: function(event, ui) {
$(this).find('.cursor').remove();
},
greedy: true
});
Then make your code or text draggable:
$('.field').draggable({
appendTo: '.content', //This is just a higher level DOM element
revert: true,
cursor: 'pointer',
zIndex: 1500, // Make sure draggable drags above everything else
containment: 'DOM',
helper: 'clone' //Clone it while dragging (keep original intact)
});
Then finally make sure you set the value of the draggable element to what you want to insert, and/or modify the code below to insert the element (span) of your choice.
$sHTML .= "<div class='field' value='{{".$config[0]."}}'>".$config[1]."</div>";

A response to #Reto: This code works, I just needed to add some fix because it doesn't insert anything if text area is empty. Also it adds only plain text. Here is the code if anybody need it:
if(editorField.nodeValue==null){
editor.setContent('<strong>Your content</strong>');
}else{
editorField.nodeValue = editorField.nodeValue.substring(0, range.startOffset) +
'<strong>Your content</strong>' +
editorField.nodeValue.substring(range.endOffset, editorField.nodeValue.length);
editor.setContent(editorField.nodeValue);
}

Change follwoing in NicEdit.js File
Updated from Reto Aebersold Ans It will handle Null Node exception, if text area is empty
update: function (A) {
(this.options.command);
if (this.options.command == 'InsertBookmark') {
var editor = nicEditors.findEditor("cpMain_area2");
var range = editor.getRng();
var editorField = editor.selElm();
// alert(editorField.content);
if (editorField.nodeValue == null) {
// editorField.setContent('"' + A + '"')
var oldStr = A.replace("<<", "").replace(">>", "");
editorField.setContent("<<" + oldStr + ">>");
}
else {
// alert('Not Null');
// alert(editorField.nodeValue + ' ' + A);
editorField.nodeValue = editorField.nodeValue.substring(0, range.startOffset) + A + editorField.nodeValue.substring(range.endOffset, editorField.nodeValue.length);
}
}
else {
// alert(A);
/* END HERE */
this.ne.nicCommand(this.options.command, A);
}

This function work when nicEdit textarea is empty or cursor is in the blank or new line.
function addToCursorPosition(textareaId,value) {
var editor = nicEditors.findEditor(textareaId);
var range = editor.getRng();
var editorField = editor.selElm();
var start = range.startOffset;
var end = range.endOffset;
if (editorField.nodeValue != null) {
editorField.nodeValue = editorField.nodeValue.substring(0, start) +
value +
editorField.nodeValue.substring(end, editorField.nodeValue.length);
}
else {
var content = nicEditors.findEditor(textareaId).getContent().split("<br>");
var linesCount = 0;
var before = "";
var after = "";
for (var i = 0; i < content.length; i++) {
if (linesCount < start) {
before += content[i] + "<br>";
}
else {
after += content[i] + "<br>";
}
linesCount++;
if (content[i]!="") {
linesCount++;
}
}
nicEditors.findEditor(textareaId).setContent(before + value + after);
}
}

Related

JavaScript loop inside tinymce button

My JavaScript loop is not working properly inside a tinymce button.
I set a variable n which is the array size that I get from my html input.
var n = $('#total').val();
Then, I create the array of tinymce buttons: var menuItems = [];
In my tinymce editor init, I create the buttons:
editor.on('init', function (e) {
for (var i=1; i<=n; i++){
var obj = {
text: 'Item ' + i,
onclick: function() {
var msg = ' <strong>#item' + i + '#</strong> ';
editor.insertContent(msg);
}
}
menuItems.push(obj);
}
});
Last step is add the menuItems to the tinymce buttons:
editor.addButton('myButton', {
type: 'menubutton',
text: 'Items',
icon: false,
menu: menuItems
});
The buttons are displaying correct with the correct label. I have the buttons:
Item 1
Item 2
Item 3
However, doesn't matter which button I click, the text displayed in the editor is item3. It always get the last button text.
Does anyone know why it is happening?
Thanks
Use let instead of var since let would keep its lexical block scope where var would not:
editor.on('init', function(e) {
for (let i = 1; i <= n; i++) { // <-- use let here
var obj = {
text: 'Item ' + i,
onclick: function() {
var msg = ' <strong>#item' + i + '#</strong> ';
editor.insertContent(msg);
}
}
menuItems.push(obj);
}
});
Here is the documentation on let

How can I make Ckeditor richcombo searchable like html datalist normal search

I'm creating a Custom Drop Down Menu using rich combo in CKEDITOR.
I want to add a Search functionality within it like key press search or input textbox search.
My Drop Box looks like this.
Here I don't have any default methods that's why i am doing like this it'wroking fine.
editor.ui.addRichCombo( 'richcombo',{
init : function(){
this.startGroup("");
this.add('search', '<div onmouseover="parent.comboSearch(this);" onclick="parent.nemsComboSearch(this);"><input class="cke_search" placeholder="Search"/></div>', '');
this.add(styles[i].name,styles[i].name,styles[i].element);
},
});
and I am adding combo search here
window.comboSearch= function(element) {
var anchorID = $(element).closest('a').attr("id");
var liDom = $(element).closest('li');
liDom.empty().append('<div id="' + anchorID + '" style="padding:4px 5px;"><input class="cke_search" placeholder="Search" /></div>');
liDom.find('input').off("keyup").on("keyup", function() {
var data = this.value;
//create a jquery object of the rows
var jo = liDom.siblings('li');
data = data.toUpperCase();
var len = jo.length;
for(var i=0;i<len;i++){
if(jo[i].textContent.toUpperCase().indexOf(data)){
jo[i].hidden = true;
}else{
jo[i].hidden = false;
}
}
}).focus(function() {
this.value = "";
$(this).unbind('focus');
});
};
function filter(data, jo) {
if (this.value === "") {
jo.show();
return;
}
//hide all the rows
jo.hide();
//Recusively filter the jquery object to get results.
jo.filter(function(i, v) {
var $t = $(this);
if ($t.is(":icontains('" + data + "')")) {
return true;
}
return false;
}).show();
}
It' working fine.

jQuery DataTable - Column level filters on top and fixed height not working together

I am trying to display data in a jQuery DataTable which has column level filter at the top, fixed height and scroller enabled. I am able to display the column level filter at the top and have it working. But, as soon as I set the height (scrollY property), the column level filters at the top disappear.
Fiddler: https://jsfiddle.net/8f63kmeo/6/
HTML:
<table id="CustomFilterOnTop" class="display nowrap" width="100%"></table>
JS
var Report4Component = (function () {
function Report4Component() {
//contorls
this.customFilterOnTopControl = "CustomFilterOnTop"; //table id
//data table object
this.customFilterOnTopGrid = null;
}
Report4Component.prototype.ShowGrid = function () {
var instance = this;
//create the datatable object
instance.customFilterOnTopGrid = $('#' + instance.customFilterOnTopControl).DataTable({
columns: [
{ data: "Description", title: "Desc" },
{ data: "Status", title: "Status" },
{ data: "Count", title: "Count" }
],
"paging": true,
//scrollY: "30vh",
//deferRender: true,
//scroller: true,
dom: '<"top"Bf<"clear">>rt <"bottom"<"Notes">ilp<"clear">>',
buttons: [
{
text: 'Load All',
action: function (e, dt, node, config) {
instance.ShowData(10000);
}
}
]
});
//now, add a second row in header which will hold controls for filtering.
$('#' + instance.customFilterOnTopControl + ' thead').append('<tr role="row" id="FilterRow">' +
'<th>Desc</th>' +
'<th>Status</th>' +
'<th>Count</th>' +
'</tr>');
$('#' + instance.customFilterOnTopControl + ' thead tr#FilterRow th').each(function () {
var title = $('#' + instance.customFilterOnTopControl + ' thead th').eq($(this).index()).text();
$(this).html('<input type="text" onclick="StopPropagation(event);" placeholder="Search ' + title + '" class="form-control" />');
});
$("div.Notes").html('<div class="alert alert-warning">This is a notes section part of the table dom.</div>');
};
Report4Component.prototype.BindEvents = function () {
var instance = this;
$("#CustomFilterOnTop thead input").on('keyup change', function () {
instance.customFilterOnTopGrid
.column($(this).parent().index() + ':visible')
.search(this.value)
.draw();
});
};
Report4Component.prototype.ShowData = function (limit) {
if (limit === void 0) { limit = 100; }
var instance = this;
instance.customFilterOnTopGrid.clear(); //latest api function
var recordList = [];
for (var i = 1; i <= limit; i++) {
var record = {};
record.Description = "This is a test description of record " + i;
record.Status = "Some status " + i;
record.Count = i;
recordList.push(record);
}
instance.customFilterOnTopGrid.rows.add(recordList);
instance.customFilterOnTopGrid.draw();
};
return Report4Component;
}());
$(function () {
var report4Component = new Report4Component();
report4Component.ShowGrid();
report4Component.BindEvents();
report4Component.ShowData();
});
function StopPropagation(evt) {
if (evt.stopPropagation !== undefined) {
evt.stopPropagation();
}
else {
evt.cancelBubble = true;
}
}
Current Status
When the following properties are commented,
//scrollY: "30vh",
//deferRender: true,
//scroller: true,
the table appears with the column level filters on top as shown below,
Issue:
When the above properties are enabled, the column level filter disappears,
You can use the fiddler to see this behavior.
Expectation:
I want to have a DataTable with column level filter on top, fixed height and scroller enabled. What am I missing? Any help / suggestion is appreciated.
You need to use table().header() API function to access thead element instead of referencing it directly. When Scroller or FixedHeader extensions are used thead element appears outside of your table in a separate element.
See updated jsFiddle for code and demonstration.

jQuery - Function not triggering .show(), .toggle(), or (display, block)

So I have a div duplication function for when a user wants to add a speaker, and a function for deleting one of said speakers.
In the latter function, in the event that all the speakers have been removed, I want to reveal the only remaining div of class speaker (the ID doesn't matter).
My function for switching between speakers (bottom) works fine (.hide()), but not the removal function. Heck even when I take out the if statement it doesn't work. Please assist!
$('#submitSpeaker').click(
function duplicateSpeaker() {
var original = $('#speaker' + speakerCount);
var clone = original.clone(true, true);
var textnode = original.find('.speakerName').val();
var node = document.createElement("LI");
var a = document.createElement("a");
if (textnode == '') {
$.Dialog({
title: 'Wizard',
flat: true,
content: 'You must enter a Speaker Name.',
shadow: true,
padding: 10
});
return;
}
node.setAttribute('class', 'active speakerLI');
node.setAttribute('id', 'speakerLI' + speakerCount)
clone.attr("id", "speaker" + ++speakerCount);
original.hide();
original.parent().append(clone);
a.setAttribute('class', 'gotoSpeaker');
$(node).append(a);
$(a).append(textnode + ' ' + "<i class='icon-minus removeSpeaker'></i>");
document.getElementById("speakerList").appendChild(node);
clone.find('input').val('').end();
clone.find('textarea').val('').end();
clone.find('img').attr('src', '#');
});
$("#speakerList").on("click", "i.removeSpeaker", function () {
var speakerNum = $(this).closest('li').attr('id').replace(/speakerLI/, '');
$('#speaker' + speakerNum).remove();
$(this).closest('li').remove();
if ($('.speaker').length == 1) {
$('.speaker').show();
};
});
$("#speakerList").on("click", "a.gotoSpeaker", function () {
var speakerNum = $(this).closest('li').attr('id').replace(/speakerLI/, '');
$(".speaker").hide();
$('#speaker' + speakerNum).show();
});

Drupal - Tinynav js

When my website passes through the defined pixel threshold as stated in Tinynav.js module all the menu items appear as they should minus the parent menu items. I have defined the parent items through Special Menu Items module as no link, meaning the parent div is simply a placeholder for the child menu items and doesn't link to any content. The issue is when the website passes into the threshold and the dropdown scrollable menu appears in place of the navigational menu it doesn't show the parent items only the child items linked to the parent.
It seems because the parent item has been defined as a no link the Tiny.js module skips it and simply displays the child menu. I have tried multiple things and none have worked, I have uploaded the js associated with Tinynav.js and html so it can be edited.
It could be the editing of this file or something else.
Thanks for helping out
html
<div id="nav"><!--nav-->
<ul class="menu"><li class="first leaf">Home</li>
<li class="leaf">Public Courses</li>
<li class="expanded"><span title="" class="nolink">Tradition </span><ul class="menu"> <li class="first leaf">Egypt</li>
<li class="last leaf">Tibet</li>
</ul></li>
<li class="expanded">For Reflection<ul class="menu"><li class="first leaf">Current Reflections</li>
<li class="last leaf">Past Reflections</li>
</ul></li>
<li class="last leaf active-trail">About Us</li>
</ul>
</div><!--/nav-->
tinynav-fork.js
/*! Originally based on the tinynav.js library found at http://tinynav.viljamis.com by #viljamis */
(function ($, window, i) {
$.fn.tinyNav = function (options) {
// Default settings
var settings = $.extend({
'active' : 'selected', // String: Set the "active" class
'header' : false, // Boolean: Show header instead of the active item
'indent' : '--', // String: Set this to empty to disable identing
'depth_count' : 2 // Integer: depth to stop counting
}, options);
return this.each(function () {
// Used for namespacing
i++;
var $nav = $(this),
// Namespacing
namespace = 'tinynav',
namespace_i = namespace + i,
l_namespace_i = '.l_' + namespace_i,
$select = $('<select/>').addClass(namespace + ' ' + namespace_i);
if ($nav.is('ul,ol')) {
if (settings.header) {
$select.append(
$('<option value="-null-"/>').text(Drupal.t('Navigation'))
);
}
// Build options
var options = '';
$nav
.addClass('l_' + namespace_i)
.find('a')
.each(function () {
var indent = '';
// indent once for each parent this has
var parent_count = $(this).parents("ul,ol").length;
// apply indenting if found
for (var i=1; i<parent_count; i++) {
indent += settings.indent;
}
// add spacing to end if we indent at all
if (indent != '') {
indent += ' ';
}
if (parent_count < settings.depth_count) {
options +=
'<option value="' + $(this).attr('href') + '">' +
indent + $(this).text() +
'</option>';
}
});
// Append options into a select
$select.append(options);
// Select the active item
$select
.find(':eq(' + (settings.header + $(l_namespace_i + ' li')
.index($(l_namespace_i + ' .' + settings.active)) + ')'))
.attr('selected', true);
// Change window location
$select.change(function () {
if ($(this).val() != '-null-') {
window.location.href = $(this).val();
}
});
// Inject select
$(l_namespace_i).after($select);
}
});
};
})(jQuery, this, 0);
tinynav-drupal.js
(function ($) {
Drupal.behaviors.tinynav = {
attach: function (context, settings) {
// make sure we don't try to access an undefined array
settings.tinynav = settings.tinynav || {
selector: '#nav ul',
media_query: 'all and (max-width:795px)',
header: false,
active: 'active-trail'
}
// Add the class to the selectors so we can access it later
$(settings.tinynav.selector).addClass('tinyjs');
// Build the Settings array
var tinyNavSettings = {
header: settings.tinynav.header
};
if (settings.tinynav.active) {
tinyNavSettings.active = settings.tinynav.active;
}
// Tinynav (<-- new verb) them all
$('.tinyjs').tinyNav(tinyNavSettings);
// Add a wrapper to the select element
$('select.tinynav').wrap('<div class="tinynav-wrapper"/>');
},
weight: 99
};
})(jQuery);
The problem is in the Tinynav.js module because it's looking for an
<a>
but Special Menu Items module create a
<span>
this is a working code:
/*! http://tinynav.viljamis.com v1.03 by #viljamis
modified by l.tagliamonte to fix Special Menu Items module menu links*/
(function ($, window, i) {
$.fn.tinyNav = function (options) {
// Default settings
var settings = $.extend({
'active' : 'selected', // String: Set the "active" class
'header' : false // Boolean: Show header instead of the active item
}, options);
return this.each(function () {
// Used for namespacing
i++;
var $nav = $(this),
// Namespacing
namespace = 'tinynav',
namespace_i = namespace + i,
l_namespace_i = '.l_' + namespace_i,
$select = $('<select/>').addClass(namespace + ' ' + namespace_i);
if ($nav.is('ul,ol')) {
if (settings.header) {
$select.append(
$('<option/>').text('Navigation')
);
}
// Build options
var options = '';
var indent = 0;
var indented = [" "];
for ( var i = 0; i < 10; i++) {
indented.push(indented[indented.length-1]+indented[indented.length-1]);
}
indented[0] = "";
$nav
.addClass('l_' + namespace_i)
.children('li')
.each(buildNavTree=function () {
var a = $(this).children('a').first();
var nolink = $(this).children('span.nolink').first();
if (nolink.html() != null){
options +=
'<option value="' + nolink.html() + '" disabled>' +
indented[indent] + nolink.html() +
'</option>';
}else{
options +=
'<option value="' + a.attr('href') + '">' +
indented[indent] + a.text() +
'</option>';
}
indent++;
$(this).children('ul,ol').children('li').each(buildNavTree);
indent--;
});
// Append options into a select
$select.append(options);
// Select the active item
if (!settings.header) {
$select
.find(':eq(' + $(l_namespace_i + ' li')
.index($(l_namespace_i + ' li.' + settings.active)) + ')')
.attr('selected', true);
}
// Change window location
$select.change(function () {
window.location.href = $(this).val();
});
// Inject select
$(l_namespace_i).after($select);
}
$('option[value="'+document.location+'"]').attr("selected","selected");
});
};
})(jQuery, this, 0);
// Tinynav
jQuery(function(){
// Main Menu
jQuery('#main-menu > ul.menu').tinyNav({
active: 'selected', // Set the "active" class
});
});

Categories