summernote編輯器插件使用筆記

此次項目中須要用到編輯器插件,因而上網查了一下。因爲須要的編輯器功能比較簡單,不須要太多複雜功能,因此選擇了一款特別輕量的summernote插件,並且後臺操做也很簡單。
官網:http://summernote.org/
github地址:https://github.com/summernote...css

先來看一下官網的截圖html

clipboard.png

麻雀雖小五臟俱全。徹底能夠知足編輯器的須要。java

按照官網連接下載下來的是git

clipboard.png

咱們須要使用的是在dist文件夾內github

clipboard.png

其中font主要是編輯器內的圖標顯示,lang是各類語言,css則是樣式。咱們主要來看一下summernote.js。ajax

summernote.js

定義

$.fn.extend({
    summernote: function () {
      var type = $.type(list.head(arguments));
      var isExternalAPICalled = type === 'string';
      var hasInitOptions = type === 'object';

      var options = hasInitOptions ? list.head(arguments) : {};

      options = $.extend({}, $.summernote.options, options);
      options.langInfo = $.extend(true, {}, $.summernote.lang['en-US'], $.summernote.lang[options.lang]);

      this.each(function (idx, note) {
        var $note = $(note);
        if (!$note.data('summernote')) {
          var context = new Context($note, options);
          $note.data('summernote', context);
          $note.data('summernote').triggerEvent('init', context.layoutInfo);
        }
      });

      var $note = this.first();
      if ($note.length) {
        var context = $note.data('summernote');
        if (isExternalAPICalled) {
          return context.invoke.apply(context, list.from(arguments));
        } else if (options.focus) {
          context.invoke('editor.focus');
        }
      }

      return this;
    }
  });

這就是初始化summernote時執行的函數。spring

$.extend(object) 能夠理解爲JQuery 添加一個靜態方法。
$.fn.extend(object) 能夠理解爲JQuery實例添加一個方法。

默認的options以下數據庫

options: {
  modules: {
    'editor': Editor,
    'clipboard': Clipboard,
    'dropzone': Dropzone,
    'codeview': Codeview,
    'statusbar': Statusbar,
    'fullscreen': Fullscreen,
    'handle': Handle,
    // FIXME: HintPopover must be front of autolink
    //  - Script error about range when Enter key is pressed on hint popover
    'hintPopover': HintPopover,
    'autoLink': AutoLink,
    'autoSync': AutoSync,
    'placeholder': Placeholder,
    'buttons': Buttons,
    'toolbar': Toolbar,
    'linkDialog': LinkDialog,
    'linkPopover': LinkPopover,
    'imageDialog': ImageDialog,
    'imagePopover': ImagePopover,
    'videoDialog': VideoDialog,
    'helpDialog': HelpDialog,
    'airPopover': AirPopover
  },

  buttons: {},
  
  lang: 'zh-CN',

  // toolbar工具欄默認
  toolbar: [
    ['style', ['style']],
    ['font', ['bold', 'underline', 'clear']],
    ['fontname', ['fontname']],
    ['color', ['color']],
    ['para', ['ul', 'ol', 'paragraph']],
    ['table', ['table']],
    ['insert', ['link', 'picture', 'video']],
    ['view', ['fullscreen', 'codeview', 'help']]
  ],

  // popover
  popover: {
    image: [
      ['imagesize', ['imageSize100', 'imageSize50', 'imageSize25']],
      ['float', ['floatLeft', 'floatRight', 'floatNone']],
      ['remove', ['removeMedia']]
    ],
    link: [
      ['link', ['linkDialogShow', 'unlink']]
    ],
    air: [
      ['color', ['color']],
      ['font', ['bold', 'underline', 'clear']],
      ['para', ['ul', 'paragraph']],
      ['table', ['table']],
      ['insert', ['link', 'picture']]
    ]
  },

  // air mode: inline editor
  airMode: false,

  width: null,
  height: null,

  focus: false,
  tabSize: 4,
  styleWithSpan: false,
  shortcuts: true,
  textareaAutoSync: true,
  direction: null,

  styleTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],

  fontNames: [
    'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New',
    'Helvetica Neue', 'Helvetica', 'Impact', 'Lucida Grande',
    'Tahoma', 'Times New Roman', 'Verdana'
  ],

  fontSizes: ['8', '9', '10', '11', '12', '14', '18', '24', '36'],

  // pallete colors(n x n)
  colors: [
    ['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF'],
    ['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'],
    ['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'],
    ['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'],
    ['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'],
    ['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'],
    ['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'],
    ['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031']
  ],

  lineHeights: ['1.0', '1.2', '1.4', '1.5', '1.6', '1.8', '2.0', '3.0'],

  tableClassName: 'table table-bordered',

  insertTableMaxSize: {
    col: 10,
    row: 10
  },

  dialogsInBody: false,
  dialogsFade: false,

  maximumImageFileSize: null,

  callbacks: {
    onInit: null,//初始化回調函數
    onFocus: null,//彙集
    onBlur: null,//失去焦點
    onEnter: null,//回車鍵的回調函數
    onKeyup: null,
    onKeydown: null,
    onSubmit: null,//提交時回調函數
    onImageUpload: null,//這就是上傳圖片的回調函數
    onImageUploadError: null//上傳圖片出錯
  },

  codemirror: {
    mode: 'text/html',
    htmlMode: true,
    lineNumbers: true
  },

  keyMap: {
    pc: {
      'ENTER': 'insertParagraph',
      'CTRL+Z': 'undo',
      'CTRL+Y': 'redo',
      'TAB': 'tab',
      'SHIFT+TAB': 'untab',
      'CTRL+B': 'bold',
      'CTRL+I': 'italic',
      'CTRL+U': 'underline',
      'CTRL+SHIFT+S': 'strikethrough',
      'CTRL+BACKSLASH': 'removeFormat',
      'CTRL+SHIFT+L': 'justifyLeft',
      'CTRL+SHIFT+E': 'justifyCenter',
      'CTRL+SHIFT+R': 'justifyRight',
      'CTRL+SHIFT+J': 'justifyFull',
      'CTRL+SHIFT+NUM7': 'insertUnorderedList',
      'CTRL+SHIFT+NUM8': 'insertOrderedList',
      'CTRL+LEFTBRACKET': 'outdent',
      'CTRL+RIGHTBRACKET': 'indent',
      'CTRL+NUM0': 'formatPara',
      'CTRL+NUM1': 'formatH1',
      'CTRL+NUM2': 'formatH2',
      'CTRL+NUM3': 'formatH3',
      'CTRL+NUM4': 'formatH4',
      'CTRL+NUM5': 'formatH5',
      'CTRL+NUM6': 'formatH6',
      'CTRL+ENTER': 'insertHorizontalRule',
      'CTRL+K': 'linkDialog.show'
    },

    mac: {
      'ENTER': 'insertParagraph',
      'CMD+Z': 'undo',
      'CMD+SHIFT+Z': 'redo',
      'TAB': 'tab',
      'SHIFT+TAB': 'untab',
      'CMD+B': 'bold',
      'CMD+I': 'italic',
      'CMD+U': 'underline',
      'CMD+SHIFT+S': 'strikethrough',
      'CMD+BACKSLASH': 'removeFormat',
      'CMD+SHIFT+L': 'justifyLeft',
      'CMD+SHIFT+E': 'justifyCenter',
      'CMD+SHIFT+R': 'justifyRight',
      'CMD+SHIFT+J': 'justifyFull',
      'CMD+SHIFT+NUM7': 'insertUnorderedList',
      'CMD+SHIFT+NUM8': 'insertOrderedList',
      'CMD+LEFTBRACKET': 'outdent',
      'CMD+RIGHTBRACKET': 'indent',
      'CMD+NUM0': 'formatPara',
      'CMD+NUM1': 'formatH1',
      'CMD+NUM2': 'formatH2',
      'CMD+NUM3': 'formatH3',
      'CMD+NUM4': 'formatH4',
      'CMD+NUM5': 'formatH5',
      'CMD+NUM6': 'formatH6',
      'CMD+ENTER': 'insertHorizontalRule',
      'CMD+K': 'linkDialog.show'
    }
  },
  icons: {
    'align': 'icon-align',
    'alignCenter': 'icon-align-center',
    'alignJustify': 'icon-align-justify',
    'alignLeft': 'icon-align-left',
    'alignRight': 'icon-align-right',
    'indent': 'icon-indent-right',
    'outdent': 'icon-indent-left',
    'arrowsAlt': 'icon-resize-full',
    'bold': 'icon-bold',
    'caret': 'icon-caret-down',
    'circle': 'icon-circle',
    'close': 'icon-close',
    'code': 'icon-code',
    'eraser': 'icon-eraser',
    'font': 'icon-font',
    'frame': 'icon-frame',
    'italic': 'icon-italic',
    'link': 'icon-link',
    'unlink': 'icon-chain-broken',
    'magic': 'icon-magic',
    'menuCheck': 'icon-check',
    'minus': 'icon-minus',
    'orderedlist': 'icon-list-ol',
    'pencil': 'icon-pencil',
    'picture': 'icon-picture',
    'question': 'icon-question',
    'redo': 'icon-redo',
    'square': 'icon-square',
    'strikethrough': 'icon-strikethrough',
    'subscript': 'icon-subscript',
    'superscript': 'icon-superscript',
    'table': 'icon-table',
    'textHeight': 'icon-text-height',
    'trash': 'icon-trash',
    'underline': 'icon-underline',
    'undo': 'icon-undo',
    'unorderedlist': 'icon-list-ul',
    'video': 'icon-facetime-video'
  }
}

關於編輯器須要的工具欄toolbar具體屬性可查看官網summernote-toolbar屬性json

更改工具欄圖標

因爲項目中我是直接使用fontawesome,因此我沒有再引入summernote.font,直接在options中的icons中修改。但比較麻煩,不知道有什麼更好的方法,求指導。app

關於圖片上傳、提交、按鍵等回調函數也是在options中,詳見callbacks部分

初始化一個編輯器很簡單。只須要定義

<div class="summernote" id="myid"></div>

 $(function () {
    $('.summernote').summernote();
    //或者
    $('#myid').summernote();
});

設置placeholder:

$('.summernote').summernote({
        placeholder:'請輸入文章內容',
        ...
    });

設置toolbar,

$('.summernote').summernote({
        toolbar:[
            ['style',['bold','italic','underline','clear']],
            ['fontsize',['fontsize']],
            ['para',['ul','ol','paragraph']],
            ['color',['color']]
        ],
        ...

    });

更改圖片上傳的方式

須要說起的是,summernote默認的圖片上傳方式爲base64方式。若須要修改,看如下代碼。
【必定要注意:onImageUpload方法修改時要放在callbacks內配置,不然沒用】

$('#myid').summernote({
    callbacks:{
        onImageUpload: function(files, editor, $editable) {
            UploadFiles(files,insertImg);
        }
    },
    ...
});

function insertImg(){
    for(i in imageUrl){
        $('.summernote').summernote('editor.insertImage',imageUrl[i]);
    }
}


function UploadFiles(files,func){
//這裏files是由於我設置了可上傳多張圖片,因此須要依次添加到formData中
    var formData = new FormData();
    for(f in files){
        formData.append("file", files[f]);
    }

    $.ajax({
        data: formData,
        type: "POST",
        url: "/uploadMultipleFile",
        cache: false,
        contentType: false,
        processData: false,
        success: function(imageUrl) {
            func(imageUrl);
     
        },
        error: function() {
            console.log("uploadError");
        }
    })
}

咱們項目的後臺是用spring+springMVC實現的。後臺圖片上傳代碼以下:

@RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST, produces = "application/json;charset=utf8")
@ResponseBody
public String uploadMultipleFileHandler(@RequestParam("file") MultipartFile[] files, HttpServletRequest request) throws IOException {
    return     UploadUtil.uploadImage(request.getServletContext().getRealPath("/"), files);
}


//UploadUtil.java中uploadImage方法以下
 public static String uploadImage(String serverPath, MultipartFile[] files) {
    try {
        String uploadPath = serverPath + getImageRelativePath();
        String images = "{}";
        //若是不存在目錄,建立一個目錄
        isDirectory(uploadPath);
        if (files != null && files.length > 0) {
            for (int i = 0; i < files.length; i++) {
                MultipartFile file = files[i];
                //save file
                if (!file.isEmpty()) {
                    String savePath = getImageRelativePath() + file.getOriginalFilename();//數據庫保存的圖片路徑
                    images = JSONUtil.addProperty(images, String.valueOf(i), savePath);
                    save(file, uploadPath);
                }
            }
        }
        return images;
    } catch (Exception e) {
        e.printStackTrace();
        return "{}";
    }
}

設置編輯器中的值:

$('#myid').summernote('code',content);

須要注意的是,content是html代碼,可能存在引號嵌套的問題致使報錯,記得將引號進行轉義。
後臺處理-java代碼:

content = content.replaceAll("'","\\\\'");
content = content.replaceAll("\"", "\\\\\"");

獲取編輯器中的值:

var content = $('.summernote').summernote('code');

上傳附件

此次項目須要使用附件,但發現summernote貌似沒有附件功能,因而本身研究了一下代碼,根據項目的需求,在link連接部分進行了修改。
效果以下:

clipboard.png

首先,咱們先看link按鈕所綁定的事件。

context.memo('button.link', function () {
        return ui.button({
          contents: ui.icon(options.icons.link),
          tooltip: lang.link.link,
          click: context.createInvokeHandler('linkDialog.show')
        }).render();
      });

由上面的代碼能夠發現click事件爲:linkDialog.show,那麼咱們再來看一下linkDialog

var LinkDialog = function (context) {
    ...
    this.initialize = function () {//初始化
        ...
        var body = '<div class="form-group">' +
               '<label>' + lang.link.textToDisplay + '</label>' +
               '<input class="note-link-text form-control" type="text" />' +
             '</div>' +
              '<div class="form-group">' +
              '<label>' + lang.link.attachment + '</label>' +
              '<input class="note-link-attachment form-control" type="file" />' +
              '</div>' +
             '<div class="form-group">' +
               '<label>' + lang.link.url + '</label>' +
               '<input class="note-link-url form-control" type="text" value="http://" />' +
             '</div>' +
             (!options.disableLinkTarget ?
               '<div class="checkbox">' +
                 '<label>' + '<input type="checkbox" checked> ' + lang.link.openInNewWindow + '</label>' +
               '</div>' : ''
             );
        var footer = '<button href="#" class="btn btn-primary note-link-btn disabled" disabled>' + lang.link.insert + '</button>';
      
    }
}

能夠看到,點擊連接按鈕出現的彈框樣式就在LinkDialoginitialize方法中的body,因此我在中間添加了一個input上傳附件的部分。

'<div class="form-group">' +
'<label>' + lang.link.attachment + '</label>' +
'<input class="note-link-attachment form-control" type="file" />' +
'</div>' +

那麼,咱們須要在lang.link屬性中,新增一個attachment附件屬性。

clipboard.png

除此以外,在中文的轉換部分summernote-zh-CN.min.js中,添加linkattachment: '添加附件'

好了,那麼咱們接下來須要處理的問題是上傳文件後的處理。

this.showLinkDialog = function (linkInfo) {
    return $.Deferred(function (deferred) {
        ...
        //上傳文件的輸入框
        $linkAttachment = self.$dialog.find('.note-link-attachment'),
        
        ui.onDialogShown(self.$dialog, function () {
            ...
            //對於輸入框的事件綁定
            $linkAttachment.on('change', function() {
                UploadFiles($linkAttachment.val(),function(url){
                    $linkUrl.val(url);//將上傳後的URL賦值到linkUrl的輸入框中
                });
            });
        }
    }
}

UploadFiles與上述修改上傳圖片的形式同樣。

若是這篇文章對您有幫助,歡迎點贊。若是有疏漏,歡迎指正。
本文地址:http://lsxj615.com/2016/08/10...

相關文章
相關標籤/搜索