Rails 4 and ckeditor - javascript

My app uses Rails 4, and I'm using the ckeditor gem and turbolinks.
In my form partial I call the ckeditor as so:
.form-group
= f.label :content, "Содержание", class: "col-sm-3 control-label"
.col-sm-8
= f.text_area :content, class: "form-control ckeditor", rows: 50
When I go to this page, I don't see ckeditor. Only after I update page does it appear. But why? What am I doing wrong? I think it's because of turbolinks. How do I solve this?

Using this gem: ckeditor
Gemfile for the last version
gem "ckeditor", :git => "https://github.com/galetahub/ckeditor.git"
Application.js
//= require ckeditor/init
In the views as the readme said:
<%= form_for #page do |form| -%>
...
<%= form.cktext_area :notes, :class => 'someclass', :ckeditor => {:language => 'uk'} %>
...
<%= form.cktext_area :content, :value => 'Default value', :id => 'sometext' %>
...
<%= cktext_area :page, :info, :cols => 40, :ckeditor => {:uiColor => '#AADC6E', :toolbar => 'mini'} %>
...
<% end -%>
Use cktext_area instead of text_area
for the rails 4 assets you need
//= require ckeditor/override
//= require ckeditor/init
And there's a trick for the compilation of assets, you need to look into the readme.
Hope it helps!

Related

Easy Auto-complet is not recognized

I would to use easy-autocomplete to add suggestions while my users are typing the pseudo of a player on my web-app.
But it doesn't work.
Here is the message I've got :
people.js:7 Uncaught TypeError: $input.easyAutocomplete is not a function
at HTMLDocument.<anonymous> (people.js:7)
at Object../node_modules/turbolinks/dist/turbolinks.js.e.dispatch (turbolinks.js:75)
at r.notifyApplicationAfterPageLoad (turbolinks.js:994)
at r.pageLoaded (turbolinks.js:948)
at turbolinks.js:872
Here is my code :
In app/javascript/packs/people.js
document.addEventListener("turbolinks:load", function() {
$input = $("[data-behavior='autocomplete']")
var options = {
getValue: "pseudo"
}
$input.easyAutocomplete(options)
});
console.log("custom js file loaded")
Here is my layout :
app/views/layouts/application.html.erb
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>
<%= javascript_pack_tag 'people', 'data-turbolinks-track': 'reload' %>
Of course in my layout, before and after this part there are script for OG facebook and twitter balises
Here is my environment.js :
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery'
})
)
module.exports = environment
I also tried this but it did not work as well :
const { environment } = require('#rails/webpacker')
const webpack = require('webpack');
// Preventing Babel from transpiling NodeModules packages
environment.loaders.delete('nodeModules');
// Bootstrap 4 has a dependency over jQuery & Popper.js:
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
Popper: ['popper.js', 'default']
})
);
module.exports = environment
If you need more information I'm ready to answer.
Thanks by advance
You are including the javascript file in wrong way.
As the helper method doc say:
# DO:
#
# <%= javascript_pack_tag 'calendar', 'map' %>
#
# DON'T:
#
# <%= javascript_pack_tag 'calendar' %>
# <%= javascript_pack_tag 'map' %>
https://github.com/rails/webpacker/blob/f1b06c7fd5bc4b7fc7128742d1078466b94af71f/lib/webpacker/helper.rb#L89-L97
In your case:
<%= javascript_pack_tag 'application', 'people', 'data-turbolinks-track': 'reload', defer: true %>

Rails 6.1.3, webpacler, select2, getting error: readyException.js:6 Uncaught TypeError: $(...).select2 is not a function

I am new with Rails 6 and webpacker. I have created a new app with rails and webpacker, got everything working but when I tried to utilize the select2 I ran into a problem where I get readyException.js:6 Uncaught TypeError: $(...).select2 is not a function errors and not am not able to submit the selected attribute to the database. I have reviewed and tried several suggestions presented on the web but didn't work. Not sure where I went wrong. Any help is much appreciated. By the way I am using simple_form and Slim.
app/assets/application.scss
#import 'bootstrap/scss/bootstrap';
app/javascript/stylesheets/application.scss
#import 'bootstrap/scss/bootstrap';
app/javascript/packs/application.js
import Rails from "#rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "#rails/activestorage"
import "channels"
import "jquery";
import "popper.js";
import "bootstrap";
import "../stylesheets/application"
import "#fortawesome/fontawesome-free/js/all"
import select2 from 'select2';
import 'select2/dist/css/select2.css';
require("#rails/activestorage").start()
require("channels")
require("jquery")
Rails.start()
Turbolinks.start()
ActiveStorage.start()
$(document).ready(function() {
$('.select').select2();
});
config/webpack/environment.js
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery'
})
)
module.exports = environment
the view form
views/users/_form.html.slim
= simple_form_for [:admin, #user] do |f|
= f.error_notification
= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present?
.form-inputs.form-group.center-block style="width:240px"
= f.input_field :first_name,
placeholder: 'First Name',
class: 'form-control',
autofocus: true,
required: true
.form-inputs.form-group.center-block style="width:240px"
= f.input_field :last_name,
placeholder: 'Last Name',
class: 'form-control',
autofocus: true,
required: true
.form-inputs.form-group.center-block style="width:240px"
= f.input_field :email,
placeholder: 'Email',
class: 'form-control',
autofocus: true,
required: true
.form-inputs.form-group.center-block style="width:240px"
= f.select :roles, Role.all.map { |role| role.name }, {include_blank: true, required: true,
include_hidden: false}, class: 'form-control', input_html: {class: 'select'}
.form-actions.form-group.center-block style="width:240px"
button.btn.btn-primary.space-above type="submit" Save
= link_to "Cancel", admin_users_path, class: 'btn btn-default space-left'
I think you may be causing issues by importing jquery twice.
Remove these lines:
require("#rails/activestorage").start()
require("channels")
require("jquery")
These are duplicating imports on lines above and (I think) the second require("jquery") could be clobbering the select2 plugin.
Also, you're not using the local select2 variable from the import. This should be sufficient:
import $ from 'jquery'
import 'select2'
$(document).ready(function() {
$(...).select2()
})
I have a branch in a demo repo that has a working example https://github.com/rossta/rails6-webpacker-demo/compare/example/select2

Code Mirror not rendering correctly on Heroku Rails 6 app

I recently added the code mirror editor to my rails 6 app. I was able to get everything working fine on my local environment (ubuntu 18.04), but when I deploy the app to heroku the code mirror editor renders the actual text editing area far below the div. It also seems to be filling it with x's. here is a screenshot of it. The x's near the top are actually part of the top editor not shown, and the lower x's are part of the main editor in the picture.
Here is my application.js file:
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
require("jquery")
import { autocompleteExport } from '../custom/autocomplete';
import { initialize } from '../custom/editor';
import { formatToc } from '../custom/page_display';
window.jQuery = $;
window.$ = $;
$(document).on("turbolinks:load", autocompleteExport.categories)
$(document).on("turbolinks:load", autocompleteExport.search)
$(document).on("turbolinks:load", autocompleteExport.admins)
$(document).on("turbolinks:load", initialize)
$(document).on("turbolinks:load", formatToc)
and here is the editor file that initializes the editors:
import CodeMirror from 'codemirror/lib/codemirror.js'
import 'codemirror/lib/codemirror.css'
import 'codemirror/mode/markdown/markdown.js'
function initialize(){
let textArea = document.getElementById('page_edit_content')
let editor = document.getElementById('content-editor')
if(textArea && !editor){
var contentEditor = CodeMirror.fromTextArea(textArea, {
lineWrapping: true,
mode: "markdown",
});
contentEditor.display.wrapper.id = "content-editor"
}
textArea = null
editor = null
textArea = document.getElementById('page_edit_summary')
editor = document.getElementById("summary-editor")
if(textArea && !editor){
var contentEditor = CodeMirror.fromTextArea(textArea, {
lineWrapping: true,
mode: "markdown",
});
contentEditor.display.wrapper.id = "summary-editor"
}
textArea = null
editor = null
textArea = document.getElementById('page_content')
editor = document.getElementById("new-content-editor")
if(textArea && !editor){
var contentEditor = CodeMirror.fromTextArea(textArea, {
lineWrapping: true,
mode: "markdown",
});
contentEditor.display.wrapper.id = "new-content-editor"
}
textArea = null
editor = null
textArea = document.getElementById('page_summary')
editor = document.getElementById("new-summary-editor")
if(textArea && !editor){
var contentEditor = CodeMirror.fromTextArea(textArea, {
lineWrapping: true,
mode: "markdown",
});
contentEditor.display.wrapper.id = "new-summary-editor"
}
}
export {initialize}
Lastly here is one of the views which is having the issue:
<% #page_title = "New Page" %>
<div class="container form-container">
<%= form_for #page, url: world_pages_path(params[:world_name]), html: {style: "width: 100%"} do |f| %>
<%= render 'shared/error_messages', errors: flash[:errors] %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, autofocus: true, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :summary %>
<%= f.text_area :summary, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :content %>
<%= f.text_area :content, class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit "Create!", class: "btn btn-primary" %>
</div>
<% if params[:category] %>
<%= hidden_field_tag :category, params[:category] %>
<% end %>
<% end %>
</div>
I'm pretty much at a loss for what could be causing this any help would be greatly appreciated.
edit:
After looking a bit through my browsers devtools, it is looking like the issue may be coming from the css not properly loading in my editor.js file, which is where I import the css files for code mirror.
edit-2:
When I remove the css import statement from the editor.js file, I get the same behavior in development, so I know for sure that that is the issue. If anyone knows the correct way to import styles from node modules that would be very helpful
If anyone runs into something like this in the future, I was able to find an answer.
The issue was stemming from my misunderstanding of webpack.
I was directly importing the css from the node module into the editor.js file. I am still not a webpack expert so I couldn't say why this worked locally, but it didn't properly set up the css files to be compiled by webpack in production.
The fix was to instead create an application.scss file in app/javascript/src. It was in this file I added #import 'codemirror/lib/codemirror.css';
After doing this I added import '../src/application.scss' to my application.js file so that webpack would know to compile the css.
Finally, I added <%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %> into my application.html.erb layout file which pulls in the css from the compiled files.

Rails 4 - Bootstrap-datepicker - Uncaught TypeError: $(...).datepicker is not a function

I installed the gem.
gem 'bootstrap-datepicker-rails'
Added this line to application.css
*= require bootstrap-datepicker3
Added this line to application.js
//= require bootstrap-datepicker
And put this into my form:
<div class="form-group">
<%= f.label :start_date %><br>
<%= f.text_field :start_date, data:{ provide:'datepicker' } %>
</div>
It works fine, however I would like to customize the date format, so I changed it to this:
<%= f.text_field(:start_date, {:class => 'datepicker' }) %>
<script type="text/javascript">
$(document).ready(function(){
$('.datepicker').datepicker({
format: 'yyyy-mm-dd'
});
});
</script>
This doesn't work and gives me the following error:
Uncaught TypeError: $(...).datepicker is not a function

Basecamp's Trix WYSIWYG editor gem not saving file attachment in Rails 4 app

I added the Trix editor gem to my Rails 4 app and followed the instructions on that page exactly. The text is displaying correctly after I save a post (bold/italic/strikethrough/paragraph spacing all good), BUT any images that I drag into the text editor disappear when I save the post. What am I doing wrong?
Thanks.
app/assets/stylesheets/application.scss:
/*
*= require_self
*= require trix
*/
#import "bootstrap";
#import "bootstrap-sprockets";
#import "font-awesome";
#import url(https://fonts.googleapis.com/css?family=Delius+Swash+Caps);
#import url(https://fonts.googleapis.com/css?family=Reenie+Beanie);
#import url(https://fonts.googleapis.com/css?family=Special+Elite);
#import url(https://fonts.googleapis.com/css?family=Londrina+Shadow);
app/assets/javascripts/application.js:
//= require jquery
//= require jquery_ujs
//= require bootstrap-sprockets
//= require bootstrap
//= require trix
//= require_tree .
_form.html.erb:
<%= form_for #article, html: {multipart: true} do |f| %>
<p>
<%= f.label :image %>
<%= f.file_field :image %>
</p>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :subtitle %>
<%= f.text_field :subtitle %>
</p>
<%= f.label :text %>
<%= f.trix_editor :text, class: 'trix-content' %>
<p>
<%= f.label :tags %>
<%= f.text_field :tag_list %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
new.html.erb
<div class="container">
<div class="jumbotron">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1>New article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
</div>
</div>
</div>
</div>
Gemfile:
gem 'rails', '4.2.2'
gem 'pg'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'jquery-rails'
gem 'bootstrap-sass', '~> 3.3', '>= 3.3.6'
gem 'devise', '~> 3.5', '>= 3.5.6'
gem "font-awesome-rails"
gem 'paperclip', '~> 4.2'
gem 'aws-sdk', '~> 1.66'
gem 'figaro', '~> 1.1', '>= 1.1.1'
gem 'simple_form'
gem 'mail_form'
gem 'acts-as-taggable-on', '~> 3.4'
gem 'fog'
gem 'rmagick', '~> 2.15', '>= 2.15.4'
gem 'carrierwave'
gem "fog-aws"
gem 'trix', '~> 0.9.0'
gem 'jbuilder', '~> 2.0'
gem 'sdoc', '~> 0.4.0', group: :doc
In this example, I've created a Image model and controller that has a GET and POST method to them. I used refile to handle the file uploads, but it would work similar with carrierwave. The idea is to listen on the event trix-attachment-add and send an XHR POST to your ImagesController. From here, you can send a JSON response back to your XHR Request and call JSON.parse to capture the response text. Trix expects a valid URL to be returned and the attributes set on the attachment. Until this is properly done, it will be in a pending state and not actually save the image and/or caption.
# ImagesController
def create
#image = Image.new(image_params)
#image.save
respond_to do |format|
format.json { render :json => { url: Refile.attachment_url(#image, :image)} }
end
end
# Some Javascript
(function() {
var host, uploadAttachment;
document.addEventListener("trix-attachment-add", function(event) {
var attachment;
attachment = event.attachment;
if (attachment.file) {
return uploadAttachment(attachment);
}
});
host = "/images";
uploadAttachment = function(attachment) {
var file, form, xhr;
file = attachment.file;
form = new FormData;
form.append("Content-Type", file.type);
form.append("image[image]", file);
xhr = new XMLHttpRequest;
xhr.open("POST", host, true);
xhr.upload.onprogress = function(event) {
var progress;
progress = event.loaded / event.total * 100;
return attachment.setUploadProgress(progress);
};
xhr.onload = function() {
var href, url;
url = href = JSON.parse(this.responseText).url;
return attachment.setAttributes({
url: url,
href: href
});
};
return xhr.send(form);
};
}).call(this);
As an alternative to #kobaltz response, you can use fetch like this:
uploadAttachment = function(attachment) {
var file, form, key, xhr;
file = attachment.file;
form = new FormData;
form.append("Content-Type", file.type);
form.append("image[picture]", file);
fetch(host, {
method: "POST",
body: form,
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
'X-Requested-With': 'XMLHttpRequest'
},
credentials: 'same-origin'
})
.then(function(response) {
if (response.ok) {
return response.json();
}
})
.then(function(json) {
var href, url;
url = href = json.url;
return attachment.setAttributes({
url: url,
href: href
});
})
};

Categories