[Ruby on Rails] Tích hợp bộ soạn thảo TinyMCE và trình quản lý file elFinder


Tiếp tục series bài viết về Ruby On Rails, hôm nay vinasupport.com sẽ hướng dẫn các bạn tích hợp bộ soạn thảo TinyMCE 4.x và trình quản lý file elFinder 2.x trong Rails 5.

Bộ soạn thảo TinyMCE

Trong một project, nếu bạn muốn quản lý nội dung, description của 1 sản phẩm hay 1 bài viết thì các bạn cần 1 bộ soạn thảo để mang lại nội dung trực quan hơn cho người đọc. TinyMCE là một bộ soạn thảo nội dung như thế (WYSIWYG editor).

Bộ soạn thảo TinyMCE

Trình quản lý file elFinder

elFinder là một trình quản lý file và thư mục rất mạnh với các chức năng về upload file, cắt file, giải nén file… Đặc biệt bạn có thể tích hợp nó vào bộ soạn thảo TinyMCE, vì bộ quản lý file đi kèm với TinyMCE để sử dụng thì các bạn phải trả tiền. Vì vậy giải pháp sử dụng elFinder là hoàn toàn miễn phí.

Tích hợp TinyMCE và elFinder trong Rails 5

1. Cài đặt TinyMCE Editor và elFilder

– Sửa file Gemfile trong project của Rails 5, thêm dòng sau:

gem 'tinymce-rails'
gem 'el_finder', '1.1.12'

Chạy command bundle để Rails cài đặt  2 gem này. Kết quả sau khi cài đặt:

– Download elFinder ở đây: https://studio-42.github.io/elFinder/

Sau đó giải nén, và copy vào thư mục public/ của project

2. Tích hợp TinyMCE vào Rails 5

– Tạo một controller mới có tên là Media, chạy command sau:

rails g controller Media index

– Sửa file config/routes.rb

# Media route
get     '/admin/media'  => 'media#index', as: :media_management
match   'elfinder'      => 'media#elfinder', via: [:get, :post]

– Update nội dung cho file app/controllers/media_controller.rb

class MediaController < ApplicationController
  skip_before_action :verify_authenticity_token, :only => ['elfinder']

  def index
    render :layout => false
  end

  def elfinder
    rootpath = File.join(Rails.public_path, 'uploads')
    rooturl = '/uploads'

    h, r = ElFinder::Connector.new(
      :root => rootpath,
      :url => rooturl,
      :perms => {
         /^(Welcome|README)$/ => {:read => true, :write => false, :rm => false},
         '.' => {:read => true, :write => true, :rm => true}, # '.' is the proper way to specify the home/root directory.
      },
      :extractors => {
         'application/zip' => ['unzip', '-qq', '-o'], # Each argument will be shellescaped (also true for archivers)
         'application/x-gzip' => ['tar', '-xzf'],
      },
      :archivers => {
         'application/zip' => ['.zip', 'zip', '-qr9'], # Note first argument is archive extension
         'application/x-gzip' => ['.tgz', 'tar', '-czf'],
      },
      :thumbs => true
    ).run(params)

    headers.merge!(h)

    if r.empty?
      (render :nothing => true) and return
    end

    render :json => r, :layout => false
  end
end

Ởfunction elfinder của controller Class MediaController, để trả về dữ liệu cho elFinder.

  • Thư mục quản lý file sẽ đặt ở thư mục public/uploads của project
  • Gem ‘el_finder’ để xứ lý backend cho phần quản lý file. (https://github.com/phallstrom/el_finder)

– Sửa file app/views/media/index.html.rb

<!DOCTYPE html>
<html>
<head>
  <title>File Manager</title>
  <link rel="stylesheet" type="text/css" media="screen" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/smoothness/jquery-ui.css">
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js"></script>
  <script type="text/javascript" src="/elfinder/js/elfinder.min.js"></script>
  <script src="/elfinder/js/proxy/elFinderSupportVer1.js" type="text/javascript" charset="utf-8"></script>
  <script type="text/javascript" src="/elfinder/js/i18n/elfinder.de.js"></script><!-- optional -->
  <link rel="stylesheet" type="text/css" media="screen" href="/elfinder/css/elfinder.min.css">
  <link rel="stylesheet" type="text/css" media="screen" href="/elfinder/css/theme.css">
</head>
<body>


<div id="elfinder"></div>

<script type="text/javascript">
  var FileBrowserDialogue = {
    init: function() {
      // Here goes your code for setting your custom things onLoad.
    },
    mySubmit: function (URL) {
      // pass selected file path to TinyMCE
      parent.tinymce.activeEditor.windowManager.getParams().setUrl(URL);
      // close popup window
      parent.tinymce.activeEditor.windowManager.close();
    }
  }

  $().ready(function() {
    var elf = $('#elfinder').elfinder({
      // set your elFinder options here
      url: '/elfinder',  // connector URL
      transport : new elFinderSupportVer1(),

      getFileCallback: function(file) { // editor callback
        // file.url - commandsOptions.getfile.onlyURL = false (default)
        // file     - commandsOptions.getfile.onlyURL = true
        FileBrowserDialogue.mySubmit(file); // pass selected file path to TinyMCE
      }
    }).elfinder('instance');
  });
</script>

</body>
</html>

– Sửa file app/assets/application.js với nội dung như sau:

//= require jquery-3.3.1.slim.min
//= require rails-ujs
//= require tinymce
//= require activestorage
//= require turbolinks
//= require_tree .

$(document).ready(function(){

  tinymce.init({
    selector: "textarea.tinymce",
    plugins: [
        "advlist autolink lists link image charmap print preview anchor",
        "searchreplace visualblocks code fullscreen",
        "insertdatetime media table contextmenu paste"
    ],
    toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image",
    file_browser_callback : elFinderBrowser
  });

  function elFinderBrowser (field_name, url, type, win) {
    tinymce.activeEditor.windowManager.open({
      file: '/admin/media', // use an absolute path!
      title: 'elFinder 2.0',
      width: 900,
      height: 450,
      resizable: 'yes'
    }, {
      setUrl: function (obj) {
        win.document.getElementById(field_name).value = obj.url;
      }
    });
    return false;
  }  
})

– Cuối cùng là đặt TinyMCE ở vị trí thích hợp trong project

<%= f.text_area :post_content, id: 'form-post_content' , class: 'form-control tinymce', rows: 5  %>

Kết quả sau khi tích hợp thành công:

Nguồn: vinasupport.com

             
SHARE

Bài viết liên quan

mode_edit Bình luận của bạn

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

account_circle
web