Summernote add text from dropdown at the end - javascript

I have a custom button in summernote that has a dropdown of items "one", "two", "three" when I click on for example the text "one" the text is added at the start which is fine. But then when I click on "two" afterwards the text is also added at the start which produces this result.
twoone
I would like to have the following result
one
two
Update when I use this line
context.invoke("editor.pasteHTML", context.modules.editor.$editable[0].innerText ? "<br>" + $(this).html() : $(this).html() );
instead of
context.invoke('editor.insertText', $(this).html());
I get the following result wihch is better but the order is still incorrect
two
one
Here you can fiddle with my code
https://stackblitz.com/edit/angular-summernote-demo-n7xn2n?file=src%2Fapp%2Fapp.component.ts
Otherwise here is my code for the button that inserts the text
function customButtonGenerator(lstQuoteComments, title) {
return function (context) {
const ui = ($ as any).summernote.ui;
var i;
var listHtml = '';
for (i = 0; i < lstQuoteComments.length; i++) {
listHtml += '<li>' + lstQuoteComments[i] + '</li>';
}
const button = ui.buttonGroup([
ui.button({
className: 'dropdown-toggle',
contents:
'<i class="fa fa-comments text-primary"/><span id="summernot-caret" class="caret text-primary"></span>',
//tooltip: 'Comments', //Not working when howver over it top is not defined
data: {
toggle: 'dropdown',
},
}),
ui.dropdown({
className: 'drop-default summernote-list',
contents:
'<div id="container-comentario"><div id="dialog" title="' +
title +
'" ><h1 class="header-comentario">' +
title +
'</h1><ul id="summernote-list"><ul>' +
listHtml +
'</ul></div></div>',
callback: function ($dropdown) {
$dropdown.find('li').each(function () {
$(this).click(function () {
context.invoke('editor.insertText', $(this).html());
});
});
},
}),
]);
return button.render();
};
}
Thank you for your help.

As far as I can see, these answer don't quite get the question right.
You should append the button content to the existing content like this:
Example blitz - https://stackblitz.com/edit/angular-summernote-demo-ycvten?file=src%2Fapp%2Fapp.component.ts
Main code snippet:
...
callback: function ($dropdown) {
$dropdown.find('li').each(function () {
$(this).click(function () {
let newHtml = context.modules.editor.$editable[0].innerHTML
if (newHtml !== '') {
newHtml += '<br>'
}
newHtml += $(this).html()
context.invoke('code', newHtml)
})
})
}
...
I'll have a look if there is a way to keep track of the current cursor position, I think there must be. I'l update if that's possible, rather than just adding to the end.

You can try to replace this line in customButtonGenerator function:
context.invoke('editor.insertText', $(this).html());
With:
context.invoke('editor.pasteHTML', $(this).html());
OR
context.invoke('editor.pasteHTML', '<div>' + $(this).html() + '</div>');

Replace this line
context.invoke('editor.insertText', $(this).html());
with
context.invoke("code", context.modules.editor.$editable[0].innerHTML + '<br>' + $(this).html());
This will solve the issue.

Related

can't get value of dynamic remove/edit HTML table using javascript

I'm trying to write a piece of code that can handle remove or editing of dynamic HTML table. I've googled and stackoverflow this problem, I see many samples but none of them worked properly.
Here is my code:
server.js
router.get('/bookShow', (req, res) => {
bookModel.find({isDeleted : false}).sort('-pageCount').exec((err, data) => {
if (data) {
res.send(data);
}
});
});
BookModel in Database:
bookShow.html
<script>
$(document).ready(() => {
$.getJSON('/bookShow', (json) => {
var tr;
for (var i = 0; i < json.length; i++) {
tr = $('<tr/>');
tr.append("<td>" + "<button class='deleteButton'>" + "<i class='material-icons'>delete</i></button>" + "</td>");
tr.append("<td>" + "<button class='editButton'>" + "<i class='material-icons'>edit</i></button>" + "</td>");
tr.append("<td>" + json[i].pageCount + "</td>");
tr.append("<td>" + json[i].name + "</td>")
$('table').append(tr);
}
});
$(document).on('click', '.deleteButton', () => {
console.log($(this));
})
});
</script>
Problem: As it seen in bookShow.html, I've declared an eventlistener whenever .deleteButton clicked. But I can't access the other fields of that table row. for example when I click on delete button of Behzad, I can't be notified the book name and its page count.
By using ES6's Arrow function () => {} the this is not any more what you're used to like by using function. It's window, because of their nature of lexical scope binding. Not any more the jQuery's representation of the DOM Element "this".
$(this) =
jQuery.fn.init [Window] by usign Arrow function () => {}
jQuery.fn.init [button.deleteButton] by using Function function () {}
so your solution would be to use the standard $(document).on('click', '.deleteButton', function() {
or to add the click on button creation - which is doable by making your button an live in-memory jQuery element $('<button>', {on:{click(){}}, appendTo:'selector'}) instead of HTML string literal.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Here's a remake:
const json = [ // You use getJSON, I'll use this for my demo
{"name": "King of the Jungle","pageCount": 543},
{"name": "The Things I've Done","pageCount": 198}
];
jQuery($ => {
// $.getJSON
$('table').append(json.map((book, i) =>
$('<tr>', {
html: `
<td>${i+1}</td>
<td>${book.name}</td>
<td>${book.pageCount}</td>
`,
append: [ // or use prepend
$('<td>', {
append: $('<button>', {
class: "buttonEdit",
html: "<i class='material-icons'>edit</i>",
on: {
click() { // Same as using `click: function () {`
console.log(`Editing ${book.name} by:`, this); // this = <button>
}
}
})
}),
$('<td>', {
append: $('<button>', {
class: "buttonDelete",
html: "<i class='material-icons'>delete</i>",
on: {
click() {
console.log(`Deleting ${book.name} by:`, this);
}
}
})
}),
]
})
));
// END $.getJSON
});
table {
width: 100%;
}
td {
border: 1px solid #ddd;
}
<table></table>
<script src="//code.jquery.com/jquery-3.1.0.js"></script>

mcautocomplete disappearing over slickgrid

I added mcautocomplete to my slickgrid. if I check some of the checkboxes mcautocomplete table is not visible anymore on slickgrid. Please check the pic.
How do i make sure that my autocomplete options are visible over my slickgrid?
$.widget('custom.mcautocomplete', $.ui.autocomplete, {
_create: function () {
this._super();
this.widget().menu("option", "items", "> :not(.ui-widget-header)");
},
_renderMenu: function (ul, items) {
var self = this,
thead;
if (this.options.showHeader) {
table = $('<div class="ui-widget-header" style="width:100%"></div>');
$.each(this.options.columns, function (index, item) {
table.append('<span style="font-weight:bold;background-color:#EEE8AA;padding:0 4px;float:left;width:' + item.width + ';">' + item.name + '</span>');
});
table.append('<div style="clear: both;"></div>');
ul.append(table);
}
$.each(items, function (index, item) {
self._renderItem(ul, item);
});
},
_renderItem: function (ul, item) {
var t = '',
result = '';
$.each(this.options.columns, function (index, column) {
t += '<span style="background-color:#ADD8E6;padding:0 4px;float:left;width:' + column.width + ';">' + item[column.valueField ? column.valueField : index] + '</span>'
});
result = $('<div></div>')
.data('ui-autocomplete-item', item)
.append('<div class="mcacAnchor">' + t + '<div style="clear: both;"></div></div>')
.appendTo(ul);
return result;
}
});
You can try z-index (this can be complex and all comes down to the priority of the container elements), but I have found that the structure of some javascript controls are simply not compatible with SlickGrid.
(not saying that mcautocomplete is not compatible, with the right tweaks, but it MAY not be).
For example, I was using 'chosen' for dropdowns, but as it used table elements that would not play well with the slickgrid infrastructure, I had to abandon that for 'select2'. There is a 'select2' example in the 6pac github repository, and I think select2 has an autocorrect mode. Might be worth a try.

miss button click event when button is added dynamically

have the following headache: there is a knockout viewmodel with initialize function
initialize: function () {
// bla bla
this.toolbar.addButton({ text: 'View All', label_key: 'view_all', click: 'viewAll' });
},
and some handler-functions
viewAll: function () {
this.toolbar.removeButton('#view_all');
this.toolbar.addButton({ text: 'View Users Projects', label_key: 'view_users_projects', click: 'viewUsersProjects' });
//some things to do
});
viewUsersProjects: function () {
localstorage.clear()// I need this here but this function doesn't work
this.toolbar.removeButton('#view_users_projects');
});
}
So, the problem is following - when button viewAll is clicked - the same function works BUT if button viewUsersProjects is clicked viewUsersProjects function doesn't work, it moves straight off to initialize, I even can delete viewUsersProjects function and nothing is changed but view_users_projects button is disappeared somehow... What I need actually to clear localstorage when view_users_projects button is clicked. Appreciate your answers.
the prototype functions for add/remove buttons:
_.extend(Toolbar.prototype, {
addButton: function (options) {
$('.navbar ul.nav:eq(0)').append(
'<li class="kkvw-button" id="' + options.label_key + '">' +
'<a data-bind="click: ' + options.click + '" href="">' +
'</a>' +
'</li>'
);
return this;
},
removeButton: function (text) {
$(text).remove();
},
});

Changing CSS based on button state

in my application i post data to the server via ajax, while data is being posted to the server i want to be able to show the user that something is indeed happening, now a simple way to do this will be to display a loading gif. What i actually want to do is change the state of the button that was clicked. I have 4 classes in my css:
btn-ready-state
btn-working-state
btn-completed-state
btn-failed-state
Now each button has a class of btn-ready-state when you click the button the class changes to btn-working-state where the text of the button changes to "working" and a small loading icon appears inside the button. When the operation is done successfully it switches to btn-completed-state if it fails then btn-failed-state. Now i have been able to do this in my code with jquery but the code is so messy and untidy and doesn't work properly with angular. I have been told i can use directives to achieve this but since i am new to angular i am confused as to how to implement this with directives, i do know what a directive is and how to make one, my issue here is the implementation of this particular feature. This is how i did it with jquery:
<script type="text/javascript">
$(document).ready(function() {
var $loading = $('#loading');
$loading.on("change", function(){ //bind() for older jquery version
var index = parseInt($('#loading').val());
var done = parseInt($('#done').val());
if (done === 0) {
$('.btn.ticket:eq(' + [index] + ')').removeClass('btn-ready-state');
$('.btn.ticket:eq(' + [index] + ')').addClass('btn-working-state');
$('.btn.ticket:eq(' + [index] + ')').find('.text').text('Working..');
$('.btn.ticket:eq(' + [index] + ')').find('.state').addClass('loading');
$('.btn.ticket:eq(' + [index] + ')').find('i').replaceWith('<img src="/images/loading.gif">' + '</img>');
} else {
$('.btn.ticket:eq(' + [index] + ')').removeClass('btn-ready-state');
$('.btn.ticket:eq(' + [index] + ')').removeClass('btn-working-state');
$('.btn.ticket:eq(' + [index] + ')').addClass('btn-completed-state');
$('.btn.ticket:eq(' + [index] + ')').find('.text').text('Added');
$('.btn.ticket:eq(' + [index] + ')').find('.state').addClass('done');
$('.btn.ticket:eq(' + [index] + ')').find('i').replaceWith('<i class="glyphicon glyphicon-ok state"></i>');
$('.btn.ticket:eq(' + [index] + ')').find('img').replaceWith('<i class="glyphicon glyphicon-ok state"></i>');
}
}).change(); //could be change() or trigger('change')
});
$(document).on("click", ".btn.ticket", function() {
var index = $(".btn.ticket").index(this);
$('#loading').val(index).change();
});
$(document).on("click", ".btn.next", function() {
$(this).removeClass('btn-ready-state');
$(this).addClass('btn-working-state');
$(this).find('.text').text('Working..');
$(this).find('.state').addClass('loading');
$(this).find('i').replaceWith('<img src="/images/loading.gif">' + '</img>');
});
</script>
This is a sample html of the button:
<button class="btn-ready-state"><span class="img"></span><span class="text"></span></button>
90% of the script changes the style. You said you like to indicate ajax? Look at this:
<script>
jQuery.ajaxSetup({
ajaxStart:function(){
jQuery('body').toggleClass('ajaxing', true);
},
ajaxStop:function(){
jQuery('body').toggleClass('ajaxing', false);
}
})
</script>
This is better because you dont need to repeat yourself (DRY-Principle).
So instead of doing this in javascript:
$(this).find('i').replaceWith('<img src="/images/loading.gif">' + '</img>');
You can now do all the graphical stuff you did in javascript in CSS:
.ajaxing i {
background-image: url(/images/loading.gif);
}
// for text you can use this:
.ajaxing .btn.ticket:active:before{
position:relative;
content:'Working...';
}
Or in anguarjs:
angular.module('app', []).value('loadManager', {
c: 0,
requested: function() { c++; document.body.class="ajaxing";},
responded: function() { c--; if(!c)document.body.class="";}
}).factory('loadingInterceptor', function(loadManager) {
return {
request: function(e) {
loadManager.requested();
return e;
},
response: function(e) {
loadManager.responded();
return e;
},
}
});
$httpProvider.interceptors.push('loadManager');
All of this is only an example. I do not know the complete HTML you are using.

How to Show Dynamically Added Element

I'm trying to create tooltips with title attribute and jQuery but can't find method to show dynamically added element.
HTML
some page
CSS
.tooltip {
    …
display: none; /* I's needed for hard coded tooltips */
…
}
jQuery
$(function () {
if (window.matchMedia('(min-width: 980px)').matches) {
$('.dfn').hover(
function () {
var el = $(this);
var txtTitle = el.prop('title');
el.append('<p class="tooltip">' + txtTitle + '</p>');
                //That's it. My tooltip has been created, but it has not been shown
$(el + ' .tooltip').show('fast');
el.data('title', el.prop('title'));
el.removeAttr('title');
}, function () {
$(el + ' .tooltip').hide('fast').remove();
el.prop('title', el.data('title'));
}
);
}
});
As mentioned by others, $(el + ' .tooltip').show('fast'); is probably wrong.
The el is an object, not a string to concat', one way is to use el.find('.tooltip').show().
The other way is to use the context option: $('.tooltip', el).show();
You need to have correct code to find new element:
$('.tooltip', el).show('fast');
Your current one probably endup searching for something like [object] .tooltip or similar string depending on how JavaScript decides to convert HTML element to string.
As others have mentioned el.find('.tooltip').show() and el.find('.tooltip').hide().remove(); solve the problem.
Also, in HandlerOut function, you el was not declared. Fiddle here
$(function () {
//if (window.matchMedia('(min-width: 980px)').matches) {
$('.dfn').hover(
function () {
var el = $(this);
var txtTitle = el.prop('title');
el.append('<p class="tooltip">' + txtTitle + '</p>');
//That's it. My tooltip has been created, but it has not been shown
el.find('.tooltip').show()
el.data('title', el.prop('title'));
el.removeAttr('title');
}, function () {
var el = $(this);
el.find('.tooltip').hide().remove();
el.prop('title', el.data('title'));
}
);
//}
});

Categories