Making tinyMCE and Garlic.js work together - javascript

I'm trying to make Garlic.js and tinyMCE work together in my Rails app without success. I've integrated Garlic in my asset pipeline and for tinyMCE I'm using tinymce-rails gem.
Both work great separately but when I put them together Garlic stops working.
I've recently tried micschk's potential solution posted in Garlic's github repository https://github.com/guillaumepotier/Garlic.js/issues/87 which involves initialising tinymce with the following code:
views/layouts/application.html (following script inside head tag)
<script>
tinyMCE.init({
selector: 'textarea.tinymce',
setup : function(editor) {
editor.on("change keyup", function(e){
console.log('saving');
tinyMCE.triggerSave(); // updates all instances
// editor.save(); // updates this instance's textarea
$(editor.getElement()).trigger('change'); // for garlic to detect change
});
}
});
</script>
the code does initialise tinymce and runs the code after 'setup' but it does not seem to make Garlic work.
Here's my view code for reference
<%= simple_form_for(#open_ender, remote: true, html: {"data-persist" => 'garlic', id:'open_ender_form' }) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :answer_id, :required => true, :as => :hidden, :autofocus => true, input_html: {value: #answer.id } %>
<%= f.input :content, :input_html => { :class => 'tinymce' }, :label => false, :required => true, :autofocus => true %>
<%= button_tag(type: 'submit', id: "save-btn", style:'background:transparent' ) do %>
<i class="fa fa-floppy-o" aria-hidden="true" title="save"; data-toggle="tooltip"; data-placement="right"></i>
<% end %>
</div>
<% end %>
I would really appreciate if someone could point me to the right solution.

I've finally decided to use the tinyMCE autosave plug-in instead of using Garlic.js although the functionality is not exactly the same it serves the purpose of protecting users from losing their data.
https://www.tinymce.com/docs/plugins/autosave/

Related

How to add Label inside correct "form group" in Ruby on Rails form?

I'm using Rails 5.2 and have this simple rails form and a field for the IP address that looks like this:
<%= bootstrap_form_for(#asset,
:url => asset_path(#asset.id),
:as => :asset,
:method => :patch,
:layout => :horizontal,
:label_col => "col-md-3",
:control_col => "col-md-4") do |f| %>
<%= f.label :ip_address_locator, 'My NEW label', data: { "toggle"=> "tooltip", "placement"=>"bottom", :title => "This is a tooltip text" } %>
<%= f.text_field :ip_address_locator %>
<% end %>
I want to update the default label for:
My NEW label
but for some reason the default and new labels show up at the same time.
and when I inspect the labels they seem to be in different divs.
How to only show 'My NEW label' and not both labels?
I still want to have my tooltip as show on the picture.
By the way I was also able to update my label like this:
<%= f.text_field :ip_address_locator, :label => {:text => 'My NEW label'} %>
But then I don't have access to my tooltip any more.
I want to be able to update my label text and be able to see my tooltip when hovering on the label just like I have it on my picture.
Because you're using bootstrap_form_for builder, f.text_field outputs a label by default. You can remove it with skip_label option. And use your custom label instead.
<%= f.label :ip_address_locator, 'My NEW label', data: { "toggle"=> "tooltip", "placement"=>"bottom", :title => "This is a tooltip text" } %>
<%= f.text_field :ip_address_locator, :skip_label => true %>
However the custom label is now outside of the form group wrapper. If you want to keep the layout unchanged you should explicitly wrap the label and the input:
<% f.form_group do %>
<%= f.label :ip_address_locator, 'My NEW label', data: { "toggle"=> "tooltip", "placement"=>"bottom", :title => "This is a tooltip text" } %>
<%= f.text_field :ip_address_locator, :skip_label => true, wrapper: false %>
<% end %>
As a side note, in an effort to spare you extra work. I'd prefer to have a hint that's always visible if a field requires extra context. Label already has text in it and a tooltip seems redundant. If used in one or two places, I think it's fine. But you would be missing all the benefits of the form builder as well; skipping wrapper and label. You would only get a .form-control class on your input from the form builder by doing this.
Update for bottstrap_form < 4.1.0. No wrapper: false option.
<style>
.form-group .form-group { margin-bottom: 0; }
</style>
<div class="form-group">
<%= f.label :ip_address_locator, 'My NEW label', class: "control-label col-md-3", data: { "toggle"=> "tooltip", "placement"=>"bottom", :title => "This is a tooltip text" } %>
<div class="col-md-4"
<%= f.text_field :ip_address_locator, layout: :none, :skip_label => true %>
</div>
</div>
Fastest way would be to add jQuery, that will initialize the tooltip.
$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});
This way tooltip will appear on hover.
jQueryUI documenation
Of course in order to use it you need jQuery gem or script tag inside of <head> </head>. But it's best to use the gem, you will need it a lot.

Rails reCAPTCHA with callback

I am trying to integrate a recaptcha into my website and I wanted to add some client side validation.
I chose to use a gem to include the recaptcha tags, but I wanted to trigger a function once the recaptcha is checked.
Looked through some google sites and found that a data-callback attribute with its value set to function name is all I need.
I used recaptcha_tags helper from the gem to set it up and then a jquery method to add this data-callback attribute as I have not seed an option to do this inside the gem.
$('.g-recaptcha').attr("data-callback", "myFunctionName");
After clicking the recaptcha the function is not called. Why?
I asume you have a form like this
app/views/contacts/contact.html.erb
<%= form_for #contact do |f| %>
<%= f.text_field :nombre, :placeholder => I18n.t("contacto_formulario_nombre"),:required => true %>
<%= f.text_field :apellido :placeholder => I18n.t("contacto_formulario_apellidos"), :required => true %>
<%= f.text_field :email, :placeholder => I18n.t("contacto_formulario_email"), :required => true %>
/** (....other tags ....) **/
<%= recaptcha_tags :display => 'clean' %>
<%= f.button I18n.t("contacto_formulario_continuar"), type: "submit" %>
<% end %>
app/assets/javascripts/contact.js
$(function() {
$('.g-recaptcha').attr("data-callback", "recaptcha");
})
function recaptcha()
{
console.log("captcha pulsado!");
/** the actions you want, i.e. activate submit button **/
}
The magic ocurrs in the attribute "data-callback"
Hope it helps.
Marino

Unresponsive javascript when using collection_select?

I have just started learning rails, html and javascript. I am using a collection_select to allow a user to select other users in the database:
<%= f.collection_select :id, Customer.where(business_id: current_customer.business_id), :id, :full_name, :prompt => 'Select', :html => { :id => "colleageselect", :onChange => "renderColCal(this)"} %>
<div id = colleaguecal> </div>
I have just been trying to test whether onChange works, by using the javascript:
<script type = "text/javascript">
function renderColCal(select){
alert('this is a test' + select.valueOf() );
document.getElementById("colleaguecal").innerHTML = "foo"
}
</script>
But changing the collection_select value when running the page doesn't do anything? Am I missing something here?
check the generated html if it is what you are expecting. I don't see any issues with the js although it would be better if it was unobstrusive. The only thing that may have caused your issue is that you didn't just passed a hash to the html options. Try
f.collection_select :id,
Customer.where(business_id: current_customer.business_id),
:id,
:full_name,
{ prompt: 'Select' },
{ id: "colleageselect", onChange: "renderColCal(this)" }

Rails Simple Form Bootstrap - Javascript if statement to reveal input

I have a rails 4 app with simple form and bootstrap.
I want to ask a question in my form which asks whether users need survey responses. If the answer to that is true, then I want to ask a follow up question. My two survey questions are:
<%= f.input :survey, :as => :boolean, :label => false, inline_label: 'Do you need survey responses?' %>
<br><br>
<%= f.input :survey_link, label: 'Where is your survey?', :label_html => { :class => 'question-data' }, placeholder: 'Include a link to your survey', :input_html => {:style=> 'width: 650px; margin-top: 20px', class: 'response-project'} %>
Is JS if statement the best way to approach this task? I want to hide the second question until the user answers true to the first question.
If so, I'm having trouble understanding how to make this JS work.
I have tried:
if (:survey is :true) {
:survey_link;
}
I can't find any resources to help explain how to do this. Help would be very much appreciated. Thank you.
Obviously the code below depends on what the name of your survey and survey_link inputs look like in actual HTML. So if in this example it is for #user:
<% simple_form_for #user do |f| %>
<%= f.input :survey, :as => :boolean, :label => false, inline_label: 'Do you need survey responses?' %>
<%= f.input :survey_link, label: 'Where is your survey?', :label_html => { :class => 'question-data' }, placeholder: 'Include a link to your survey', :input_html => {:style=> 'width: 650px; margin-top: 20px', class: 'response-project'} %>
<% end %>
Then the JQuery should look like (note the user part - you may have to change this):
<script>
$(function() {
// Hide the survey_link input
$('input[name="user[survey_link]"]').hide();
$('input[name="user[survey_link]"]').closest("label").hide();
// When the survey checkbox changes
$('input[name="user[survey]"]').change(function() {
$('input[name="user[survey_link]"]').closest("label").toggle(this.checked);
$('input[name="user[survey_link]"]').toggle(this.checked);
});
});
</script>

rails: accessing a non-instance variable in js.erb

I have a page that renders multiple forms. Currently, when the user submits any one of these forms, it updates (via ajax) a div on the same page with the content from the form that was just submitted.
I also want to remove() the form element that was just submitted after the ajax post request is completed. However, I need to be able to access that specific form ID within the js.erb file to do so.
Since my page has x number of forms rendered dynamically, I cannot simply access an instance variable in my js.erb.
Page:
<% for peer_review in #peer_reviews %>
<%= render :partial => 'form', :locals => { :peer_review => peer_review } %>
<% end %>
<div id="completed_peer_reviews">
<%= render 'completed_peer_reviews' %>
</div>
The #peer_reviews instance variable contains an array of new PeerReview objects already containing some data.
Form:
<div id="peer_review_form_<%= peer_review.reviewee_id %>">
<%= form_for peer_review, :html => { :method => "post" }, :remote => true do |f| %>
<%= f.error_messages %>
<p>
Peer Review for: <%= User.find(peer_review.reviewee_id).name %><br />
</p>
<p>
<%= f.label :rating %>:
<%= f.select :rating, [1, 2, 3, 4, 5], { :include_blank => 'None' } %>
</p>
<p>
<%= f.label :review %><br />
<%= f.text_area :review %>
</p>
<%= f.hidden_field :user_id, :value => peer_review.user_id %>
<%= f.hidden_field :reviewee_id, :value => peer_review.reviewee_id %>
<%= f.hidden_field :review_period_id, :value => peer_review.review_period_id %>
<p><%= f.submit "Submit" %></p>
<% end %>
</div>
js.erb:
$("#completed_peer_reviews").html("<%= escape_javascript(render('completed_peer_reviews')) %>");
I was hoping to just add another line to the js.erb file that removes the form element that just triggered the execution of the js.erb file like so:
$("#peer_review_form_<%= peer_review.reviewee_id %>").remove();
How should I actually be referencing peer_review.reviewee_id here? Or should I be taking a completely different approach?
This is one of the classic issues of RJS templates.
Quick answer:
If you simply want to solve the problem, you could pass along some temporary id to identify the form. e.g:
# in the index
<% #peer_reviews.each.with_index do |peer_review, i| %>
<%= render :partial => 'form',
:locals => { :peer_review => peer_review, :i => i } %>
<% end %>
# then in the form (note, you don't need to specify POST in a form_for)
<div id="peer_review_form_<%= i %>">
<%= form_for peer_review, :remote => true do |f| %>
<%= hidden_field_tag 'temp_id', i %>
# finally in the create js.erb
$("#peer_review_form_<%= params[:temp_id] %>").remove();
Longer Answer:
That being said, while RJS templates were "the Rails way" for a long time, they've since fallen out of favor.
The more modern method is typically client side JS templates with a JSON API, rather than running server generated JS templates (RJS). This has a lot of advantages, one being that the DOM binding issue you're having right now no longer exists.
This is an example of how you might do this with pure jQuery, but there are many templating options out there.
<script id="peer_review_tmpl" type="text/x-jquery-tmpl">
<div class="completed_peer_review">
<p>${review}</p>
...
</div>
</script>
Then you'd create a handler and bind it to a successful ajax response. This would require that your peer_reviews#create action responded to JSON:
$('form.new_peer_review').bind("ajax:success", function(data) {
// remove the form which triggered the creation
$(this).remove();
// then render the data into a template, and append it to the list
$("#peer_review_tmpl").tmpl(data).appendTo("#completed_peer_reviews");
});

Categories