I am in process of implementing CKEditor5 into my app which is chat app.
I am trying to make shift+enter combination key to work like enter key to make new lines, add new points to list etc. I can't use enter key because it is for sending message.
So I was trying to implement it like this and it's almost works perfect, but when i am adding another point to the list when the previous point was empty, it should leave the list but instead it is adding another empty point and i dont know how to fix this.
editor.editing.view.document.on('keydown', (evt, data) => {
if (data.shiftKey && data.keyCode === 13) { //shift + enter
editor.execute('enter');
data.preventDefault();
evt.stop();
};
});
Example:
It looks like this
It should be like this
Related
I need to implement functionality where child row will slide and open on the top of the parent row instead of bottom. Could anyone please help.
// Add event listener for opening and closing details
$('#example tbody').on('click', 'td.details-control', function () {
var tr = $(this).closest('tr');
var row = table.row( tr );
if ( row.child.isShown() ) {
// This row is already open - close it
$('div.slider', row.child()).slideUp( function () {
row.child.hide();
tr.removeClass('shown');
} );
}
else {
// Open this row
row.child( format(row.data()), 'no-padding' ).show();
tr.addClass('shown');
$('div.slider', row.child()).slideDown();
}
} );
https://jsfiddle.net/nnb97rh9/3/
The problem is that HTML shows a nested table below the row it's nested in. The datatables routine that you're using sets up a nested table when you push the green button, so you're coming up against an HTML limitation.
The only way that you could maybe do this is very messy: on clicking a green button, go to the row prior to the current one, and call the format function on it. (Of course, you'd have to find a way to pass row.data from the current row rather than the previous one, after moving to the previous one. And there would be other messiness that I'm not going to contemplate.)
That begs the question of how to handle the first row, since there isn't one prior to it; you'd probably have to come up with a different function for that. That's all counter-intuitive and illogical: you don't really want to nest a table inside a row with data that's unrelated to it.
Which brings us to why you want to do this in the first place. You're almost certainly going to confuse your users: you're basically doing this differently from 99.99999% of the rest of the world, thereby depriving your users of their previous experience and making your UX counter-intuitive. As a comparison, what if you wanted a "dropup" list instead of the more usual dropdown list? Wouldn't that confuse most users?
My suggestion is to consider abandoning this idea. Take a few steps back and rethink what you want to accomplish, and then see if you can do things in a manner that's closer to established UI behavior. Users prefer to work with UIs that leverage their past experience working with UIs, so they don't have to put in extra time to learn a new way of doing things. Don't ask them to find new ways to do things they already know how to do, or they won't use your application.
https://react.semantic-ui.com/modules/search
Below is images of how the semantic react ui search widget looks like. In the second image, I was wondering how you can put a prompt message to indicate to the user a message on what the search bar is meant for. In this case, it's "search". When the user types in, it erases the Search and starts reflecting what the user is typing. I thought it would be defaultValue, but it seems that you can't have value and defaultValue set at the same time. I still want to be able to read what the set value is when the user types into the box.
Thanks,
Derek
You can use defaultValue as initial value in component, no problem.
Then read the user input value in event (onBlur for instance) like this:
onBlur(e) {
e.preventDefault();
console.log(e.target.name, e.target.value);
}
If you want to read value each new character pressed you can use in onSearchChange event:
onSearchChange(e) {
e.preventDefault();
console.log(e.target.name, e.target.value);
}
EDIT: included accepted answer in comment below:
Worked:
placeholder={"text"}
for Semantic React UI Search
I am trying to set the default style applied to the P elements that are automatically created when a user enters the blank editing area. I've spent many hours searching for an answer but have not found anything that works. The requirements are:
Style has to be inline, no stylesheet
No user interaction, no format/style plugin to click
When the user clicks in the editing area and starts typing, I want the style to be applied and visible automatically. Surely there is a way to accomplish this?
The closest I have gotten is by using the htmlFilter, like this :
p_rule = {
elements : {
p : function(element) {
if (element.attributes.style === undefined) {
element.attributes.style = "color: #0000ff;";
}
}
}
};
ev.editor.dataProcessor.htmlFilter.addRules(p_rule);
But the new style is not automatically visible.
It does become visible if the user goes into source editing mode and back to WYSIWYG but I want it to be automatic.
I tried using updateElement() in the filter function, but it does not work and creates infinite recursion:
p_rule = {
elements : {
p : function(element) {
if (element.attributes.style === undefined) {
element.attributes.style = "color: #0000ff;";
CKEDITOR.instances['editor1'].updateElement();
}
}
}
};
ev.editor.dataProcessor.htmlFilter.addRules(p_rule);
(I guess updateElement() triggers the filter)
If I use setData(getData()) from an event I can strangely get the textarea to update with the changes the filter applied, for example:
CKEDITOR.instances['editor1'].on('blur', function() {
CKEDITOR.instances['editor1'].setData(CKEDITOR.instances['editor1'].getData());
});
But that too requires user interaction. Using the "change" event creates recursion.
I am new at CKEditor and obviously I'm missing something on how the filter works in relation to what is currently being displayed in the textarea.
Any CKEditor guru out there? Help!
Thanks
I really advise not to go this way. You'll find yourself fighting with countless issues, like what if you copy&paste, what if you change format to h1 and then back, what if you create a list item and then convert that into a paragraph, etc. etc. There are really dozens of those. You'd need to rewrite half of the editor.
The way to handle this in CKEditor 4 is to rethink this:
Style has to be inline, no stylesheet
Inside CKEditor you clearly need to use a stylesheet. I presume though that you want the inline styles in the output. So what I would propose is to:
Write htmlFilter rule which adds this style to every paragraph.
Write dataFilter rule which removes this style from every paragraph.
The second rule is needed so if you save the data and then load it back to the editor, the styles do not pollute it.
PS. CKEditor 5 will separate data model from rendering (the view) so you'll be able to render paragraph as you wish without affecting how other features interact with it. Read more about CKEditor 5 in this article.
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);
});
I inherited a web app that uses Dojo 1.5 and the template toolkit. I am enjoying learning dojo but it's at a slow pace.
Initially when bringing up our web form, we'll have a list of files on the right side of the page like so....
AAA_text
BBB_text_1
BBB_text_2
CCC_text
....
....
On the left side we have a search box that asks for the subset of file to use. Normally we would just type in "AAA" and then the div on the right side would find those files that match and display them after you press the "Search" key below the box.
What we are looking to do is to eliminate the "Search box" and have the list of files matching "AAA" to come up in the right side div as "AAA" is being typed, (or "BBB" or "CCC", etc).
I suppose in a nutshell it's the equivalent having the "Search" button pressed after every key is typed in the Search box.
Does this sound like a realistic goal or even possible? The code itself uses a ton of Template Tookit so I'm not looking to do any major rewrite.
If I am not making myself clear, let me know. I can elaborate for clarity. Many many thanks! Janie
EDIT: OK, I have solved a good deal of my problem so far and as it turns out, as so many of these things have a propensity to do, that what I am really needing is to get clear on how to make autocomplete work. Which is to say that I have a data source for my text box but not really sure how to tie it to the text box. I have a dojo.xhrPost routine that can handle grabbing the values.
It looks like this....
dijit.byId('files_matching').getValue(),
Googling dojo autocomplete examples gives me a zillion links and none of which are proving helpful. So I suppose my questions have transitioned to....
1. Can you even use autocomplete on a mere text box (I've seen links that say that you can only use it on combo boxes)
2. Is there a link out there somewhere that describes/shows in detail how to tie a dojo text box to a data source using dojo.xhrPost.
I am so close to solving this and I still seem to have a gaping chasm in front of me.
It's difficult to say for sure without seeing your code but if you don't have one already, I would recommend to create an ItemFileReadStore or something similar to start with. That way you can query that store locally on the client without having server requests after every key stroke.
It could look something like this:
var file_store = new dojo.data.ItemFileReadStore({ data: {
items: [{ name:"AAA_text" },
{ name:"AAA_text_1" },
{ name:"BBB_text_2" }]
}});
When you have that in place you can call a function from your text input's onChange event:
<input type="text" onchange="query_store(this.value);" />
And then you handle to actual query from the function called from the onchange event:
var query_store = function(search_for) {
var my_query = { name: search_for+"*" }; // * for wildcard match
completed = function(items, result){
for(var i = 0; i < items.length; i++){
var value = file_store.getValue(items[i], "name");
alert(value); // Instead of alert, you can save the values to your div.
}
};
file_store.fetch({ query: my_query, onComplete: completed });
}
A lot of good information about this can be found here
Hope this is at least a little helpful.