How to update content of an existing jodit editor in a function - wysiwyg

i use jodit in my website and wonder, how the content of an existing jodit editor can be updated within a function.
first i do....
$( document ).ready(function() {
var editor_adressblock = new Jodit('#adressblock', {
fullsize: false
});
});
and the editor is correctly created.
I have a function, which can be executed by the user and then should load content (via json-request) and then put the content into the existing jodit textarea.
Here is my try (for this example i have simplified the function) :
function takeover_adressblock(kunde_id, kunden_adresse_id) {
// get data by ajax.... not shown in this example
var data_by_ajax="test";
editor_adressblock.value=data_by_ajax; // this fails....
}
Means, i don't know how i can send data to the existing jodit texteditor...
I am a jquery beginner, so please don't be too hard ;-)
Best regards
Daniel

Per the documentation you seem to have the right format, so it would help to see the code for the ajax request you're making in case the issue is there.
Otherwise, I would suggest initializing the editor without jQuery in case it's a reference or scoping issue:
const editor = Jodit.make('#editor');
editor.value = '<p>start</p>';

Related

How to get user's input from WicketStuff's TinyMCE

Pretty straight-forward question, but I can't find this anywhere. I'm using WicketStuff's TinyMCE to make a Rich Text Editor in my application, and can't find anywhere how to get the input from the text area. For brevity's sake, the following is a simplified version of the code I'm using.
private String input;
...
TinyMCESettings settings = new TinyMCESettings(TinyMCESettings.Theme.simple);
TextArea<String> textArea = new TextArea<String>("editor", new PropertyModel<String>(this, "input"));
textArea.add(new TinyMceBehavior(settings));
form.add(textArea);
Using this, I would expect the usual manner to simply use my String 'input' since it's set as the model. This always results in null as the model isn't being updated.
I tried using the auto-save plugin in case it was expecting the save button to be clicked (which doesn't update the model either), and neither worked. The only thing I've been able to do to get the user's input is to add a HiddenField, with a new model, and make a JavaScript call like
document.getElementById('hiddenField').value = tinyMCE.get('editor').getContent();
but this has led to other problems with trying to call the JS in the desired place and to get it to work properly. I feel this shouldn't be necessary anyways, as surely someone must have implemented a method to get the contents of the text area being used.
Any help would be greatly appreciated.
Thanks to a blog post at Nevermind Solutions, the way to get the model updated is to add the following JavaScript to the form's submitting button:
onclick="tinyMCE.triggerSave(true,true);"
My text area is inside a panel with the button outside of the panel, so it doesn't directly work for me. The trick was to add the JavaScript call to the button's onSubmit, move the logic into the onAfterSubmit, and to make the button MultiPart so that it could call the save trigger before doing the other logic associated to the model.
Hope this might help some others in the future.
You have to add a modifier to the submit button so that the model can update.
AjaxButton btnSubmit = new AjaxButton("btnSubmit", new Model()) {
#Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
doSomething();
}
};
btnSubmit.add(new TinyMceAjaxSubmitModifier());
Have a look here for more info

What is the proper way to integrate dynamic content into the layout.ejs file in a Sails.JS application?

Say I wrote a blog app in Sails.js.
On every page in this app, there is a sidebar widget called "Recent Posts", where it lists the titles of the 5 most recent posts and clicking on them takes you to the post in question.
Because this sidebar widget is present on every page, it should be in layout.ejs. But, here we have a conflict - dynamic content is only supposed to be pulled from the database in the controller action for rendering a specific view.
This dynamic content isn't for a specific view, it's for the whole site (via layout.ejs).
By the conventions that I understand, I'd have to get that dynamic content data for the sidebar widget in every controller action that renders a view (otherwise I would get an undefined error when I attempt to call that local in my layout.ejs file).
Things I've tried / considered:
Load that dynamic content in every controller action that renders a view (this solution is very bad) and calling that dynamic content in layout.ejs as if it were a local for the specific view. This works fine, but goes against D.R.Y. principles and quite frankly is a pain in the ass to have to run the same query to the database in every controller action.
As per another similar stackoverflow question, create a new config (E.G. config/globals.js), load my dynamic content from my database into that config file as a variable, and then calling sails.config.globals.[variable_name] in my layout.ejs file. This also worked, since apparently config variables are available everywhere in the application -- but it 's a hacky solution that I'm not a fan of (the content I'm loading is simply the titles and slugs of 5 recent posts, not a "global config option", as the solution implies).
Run the query to get the dynamic content inside the .EJS file directly between some <% %> tags. I'm not sure if this would work, but even if it did, it goes against the separation of concerns MVC principle and I'd like to avoid doing this if at all possible (if it even works).
As per a lengthy IRC discussion # http://webchat.freenode.net/?channels=sailsjs, it was suggested to create a policy and map that policy to all my controllers. In that policy, query the database for the 5 most recent posts, and set them to the req.recentposts. The problem with this solution is that, while the recent posts data will be passed to every controller, I still have to pass that req.recentposts data to my view -- making it so I still have to modify every single res.view({}) in every action. I don't have to have the database query in every action, which is good, but I still have to add a line of code to every action that renders a view... this isn't D.R.Y. and I'm looking for a better solution.
So, what is the proper solution, without needing to load that dynamic content in every controller action (a solution that adheres to D.R.Y. is what I'm lookng for), to get some dynamic content available to my layout.ejs file?
In folder /config you should create a file express.js and add something like that:
module.exports.express = {
customMiddleware: function(app){
app.use(function(req, res, next){
// or whatever query you need
Posts.find().limit(5).exec(function(err, posts){
res.locals.recentPosts = posts;
// remember about next()
next();
});
});
}
}
Then just make some simple loop in your view:
<% for(var i=0; i<recentPosts.length; i++) { %>
<% recentPosts[i].title %>
<% } %>
Here are some links to proper places in documentation:
https://github.com/balderdashy/sails-docs/blob/0.9/reference/Configuration.md#express
and
https://github.com/balderdashy/sails-docs/blob/0.9/reference/Response.md#reslocals
I found out another way to do this. What I did was to create a service that could render .ejs files to plain html by simply taking advantage of the ejs library already in sails. This service could either be invoked by the controller, or even passed as a function in the locals, and executed from within the .ejs. The service called TopNavBarService would look like:
var ejs = require('ejs');
exports.render = function() {
/* database finds goes here */
var userInfo = {
'username' : 'Kallehopp',
'real_name' : 'Kalle Hoppson'
};
var html = null;
ejs.renderFile('./views/topNavBar.ejs', {'locals':userInfo}, function(err, result) { html = result; });
return html;
}
In the constroller it could look like:
module.exports = {
testAction: function (req, res) {
return res.view('testView', {
renderNavbar: TopNavBarService.render // service function as a local!
});
}
};
This way you can create your customized ejs-helper that could even take arguments (although not shown here). When invoked, the helper could access the database and render a part of the html.
<div>
<%- renderNavbar() %>
</div>

How to reference dynamically added element after DOM loaded without a need to act on any events?

I know there is .on and .live (deprecated) available from JQuery, but those assume you want to attach event handlers to one ore more events of the dynamically added element which I don't. I just need to reference it so I can access some of the attributes of it.
And to be more specific, there are multiple dynamic elements like this all with class="cluster" set and each with a different value for the: title attribute, top attribute, and left attribute.
None of these jquery options work:
var allClusters = $('.cluster');
var allClusters2 = $('#map').children('.cluster');
var allClusters3 = $('#map').find('.cluster');
Again, I don't want to attach any event handlers so .on doesn't seem like the right solution even if I were to hijack it, add a bogus event, a doNothing handler, and then just reference my attributes.
There's got to be a better solution. Any ideas?
UPDATE:
I mis-stated the title as I meant to say that the elements were dynamically added to the DOM, but not through JQuery. Title updated.
I figured it out. The elements weren't showing up because the DOM hadn't been updated yet.
I'm working with Google Maps and MarkerClustererPlus to give some more context, and when I add the map markers using markerclustererplus, they weren't available in the javascript code following the add.
Adding a google maps event listener to my google map fixed the problem:
google.maps.event.addListener(myMarkerClusterer, 'clusteringend', function () {
// access newly added DOM elements here
});
Once I add that listener, all the above JQuery selectors and/or methods work just fine:
var allClusters = $('.cluster');
var allClusters3 = $('#map').find('.cluster');
Although this one didn't, but that's because it only finds direct decendants of parent:
var allClusters2 = $('#map').children('.cluster');
Do what you need to do in the ajax callback:
$.ajax(...).done(function (html) {
//append here
allClusters = $('.cluster');
});
If you want them to be separate, you can always bind handlers after the fact, or use $.when:
jqxhr = $.ajax(...).done(function (html) { /* append html */ });
jqxhr.done(function () { allClusters = $('.cluster') });
$.when(jqxhr).done(function () { /* you get it */ });
If these are being appended without ajax changes, then just move the cluster-finding code to wherever the DOM changes take place.
If that's not an option, then I guess you would just have to check on an interval.

cakePHP form with YUI text editor, not working

I am trying to integrate yui editor in a cakephp form
the editor is attached to the textarea, I tried the handleSubmit option and it didn't work, so I went trying manual. so- I've attached a listener to the onsubmit, which is working.. or not.
Editor initialization ( a copy-paste from yui site, only element named changed):
(function() {
//Setup some private variables
var Dom = YAHOO.util.Dom,
Event = YAHOO.util.Event;
//The SimpleEditor config
var myConfig = {
height: '300px',
width: '99%',
focusAtStart: true
};
//Now let's load the SimpleEditor..
var myEditor = new YAHOO.widget.SimpleEditor('ArticleContent', myConfig);
myEditor.render();
})();
Initialization works fine (I assume) since the editor now holds the real content of that record field.
The onsubmit listener function:
function setTextArea()
{
alert('s');
var dd = myEditor.saveHTML();
alert('d');
return false;
}
The first alert is working, so the event is handled.
However, the second alert never happens. the form - somehow - is submitted before it.
and, the content is not saved.
further checks shows that ANY call to myEditor [even alert(myEditor)] is submitting the form...
anyone? help? i
just a guess, but is any code in the 'saveHTML' function calling something that clashes with cakephp functions?
if this is the problem, you may be able to get around it by modifying the yui code function names (hacky i know, but unless there is some way to use a custom namespace for it i think you'd be stuck with it)
The best solution was to use tinyMCE....

Test to see if you are in a specific content block in TinyMCE and not allow a plugin to add to that content block if in it

So I have a TinyMCE form on my page and it is pre-filled with "sections" (divs with specific class names).
I have a couple of plugins that will add to TinyMCE with more "sections".
I need it so when I push the plugin button it will test to make sure the cursor is not inside a "section" and paste a "section" inside another "section".
Not sure the direction I need to take to accomplish this. Any help would be great.
more info:
So below is an example of a plugin that adds a button that just inserts a simple dov into the editor at the selection/cursor.
ed.addButton('pluginbutton', {
title : 'MyPlugin',
image : 'img/test.png',
onclick : function() {
ed.selection.setContent('<div>test</div>');
}
});
I am currently thinking that onBeforeSetContent is the API event handler I need to set to process whether or not I am in another section and if so send a message to the screen. If not just do the setContent method. I am not sure exactly how to set that up though so I am still figuring that out. Any help here?
Since it seems like you have control over the plugin, here is how I would edit it to work.
Note: I am using the jQuery method closest. I figured since you are on the jQuery core team, you are probably using it for this project. If not, just refactor that line as needed. The important part is that selection.getNode() returns the DOM element that is the parent of both the start and end selection points.:
ed.addButton('pluginbutton', {
title : 'MyPlugin',
image : 'img/test.png',
onclick : function() {
if( !$(ed.selection.getNode()).closest('div.section').length ){
ed.selection.setContent('<div class="section">test</div>');
}
}
});
Additional thoughts
Also, to make your plugin aware enough so it won't put a div as the child of a p tag, you could do something like this:
Replace onclick above with this:
onclick: function(){
var $node = $(ed.selection.getNode());
if( !$node.closest('div.section').length ){
// Get highest element that is a direct child of the `body` tag:
var $parent = $node.closest('body > *');
// Wrap with our special section div
if($parent.length) $parent.wrap('<div class="section"></div>');
}
}
I don't know TinyMCE specifically, but it should be possible to extract the current DOM element from ed.selection. If that is possible (I'm sure it is using some sort of getter function or property), you should be able to do the following:
Mark a "forbidden" area using an id or class ("<div class='protected'> ")
traverse through the selection's ancestry (using the parentNode property of the element) and check whether one of the parent elements has the "protected" class or ID.
If the ID was found, do not execute setContent(); otherwise execute it.