Back

ruby - 终于给我的个人博客增加了 粘贴图片的功能 paste image from clipboard to blog

发布时间: 2021-11-15 12:45:00

这个想法有了好几天了。 过去苦于增加图片的不方便,所以写博客的时候往往只能用纯文字,很不尽兴。

最近这个需求越发的旺盛,所以就想办法弄了一下。

核心的是使用了     http://siwei.me/blog/posts/javascript-html 

也就是 clipboardData 这个变量。

不过由于我的个人博客基于 refinery-cms, 一个体量很大的CMS,集成了WYMeditor,所以研究了小两天。

记录一下过程吧。

1. 搭建一个 ubuntu 16 vmware server.

因为只有 ubuntu16 才能很好的支持 ruby 1.9.3 ,  在ubuntu18上无法安装 (通过rbenv )

2. 在本地运行好项目 (这个图无任何意义,就是为了让自己爽爽....)

3. 修改核心文件(js):

app/assets/javascripts/wymeditor/prototypes.js.erb

WYMeditor.editor.prototype.intercept_paste = function(e) {
  console.info("===  hihihi, in intercept_paste")

  var pasteEvent = e.originalEvent
  var item = pasteEvent.clipboardData.items[0];
  var wym = window.wym
  // 仅仅处理粘贴图片,
  if (item.type.indexOf("image") === 0) {
    var blob = item.getAsFile();

    var reader = new FileReader();
    reader.onload = function(event) {
      image_content = event.target.result
      // 发现是图片的话,把它上传到CDN上。
      jQuery.post('/interface/blogs/upload_paste_image_to_cdn', {image_content: image_content}, function( data ) {
        if(window.wym){
          window.wym.paste("<img src='" + data.url + "'/>", false)
          var wym2 = WYMeditor.INSTANCES[0];   // 这句代码只是用于演示。如何获得 wym实例。
          console.info("==== wym get by title:", wym2)
        }else{
          alert("window.wym is undefined, refresh and try again")
        }
      });

    };

    reader.readAsDataURL(blob);

  }else{

    var wym = WYMeditor.INSTANCES[this.title];
    wym.format_block();
    wym.exec(WYMeditor.PASTE);
  }

然后,又要修改该文件下的paste方法:

// 这里的方法入口,需要有第二个参数: is_escape. 
// 用来把 CDN上的图片名称(我们刚刚上传上去的)合并到正文中。
WYMeditor.editor.prototype.paste = function(sData, is_escape = true) { wym = this; wym.format_block(); var sTmp; replaceable = $(wym._doc.body).find('#' + wym._current_unique_stamp); // replaceable doesn't actually get replaced here, it's just used as a marker for where the cursor was. container = replaceable.get(0) || this.selected(); //split the data, using double newlines as the separator var aP = sData if(is_escape){ console.info("=== is escape") aP = sData.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").split(wym._newLine + wym._newLine); }else{ console.info("=== NOT escape")
// 增加这一句。 非常关键。 aP = [aP] } var rExp = new RegExp(wym._newLine, "g");

4. 修改核心的ruby文件(增加上传图片到CDN的接口) blogs_controller

require 'base64'
require 'upyun'

class Interface::BlogsController < ActionController::Base
  def upload_paste_image_to_cdn
    bucket = Settings.upyun.bucket
    operator = Settings.upyun.operator
    password = Settings.upyun.password

    base_64_encoded_data = params[:image_content]

    unless base_64_encoded_data.include?("data:image/png;base64,")
      raise "It's not an png image"
      return
    end 

    local_file = 'temp.png'
    File.open(local_file, 'wb') do |f| 
      f.write(Base64.decode64(base_64_encoded_data.gsub("data:image/png;base64,", '')))
    end 
    upyun = Upyun::Rest.new(bucket, operator, password)
    remote_file = "/blog_images/from_paste_#{Time.now.strftime('%Y%m%d_%H%M%S')}.png"

    response = upyun.put remote_file, local_file
    render :json => {
      :response => response,
      :url => "https://files.sweetysoft.com#{remote_file}",
    }   
  end 

5. 增加ruby路由文件:

post '/interface/blogs/upload_paste_image_to_cdn', to: 'interface::blogs#upload_paste_image_to_cdn',

基本就可以了。

几个小插曲

1. ruby 1.9.3 实在是古老,但是我没有太多的时间去弄refinery-cms. 只好先这样了。

2. 修改Gemfile, 要使用node 作为js runtime, 不要使用遗留的execjs 等Gem .

(通过修改 config/environments/production.rb 来实现,注释掉下面的代码:

config.assets.compress = true

)否则你会遇到奇怪的问题,参考:  https://stackoverflow.com/questions/12574977/rake-assetsprecompile-gives-punc-error

3. 需要提前到upyun上做个申请。然后把内容记录在 config/settings.yml 中。

4. upyun 这个rubygem 对于1.9.3的ruby版本,不能使用最新的,要使用比较古老一些的版本。否则会报错。

另外上传文件的时候,直接使用本地文件名即可。否则使用File.read(file_name)的话会报错。(这个图片意义不大,只是为了炫耀哈哈)

Back