此次項目中須要用到編輯器插件,因而上網查了一下。因爲須要的編輯器功能比較簡單,不須要太多複雜功能,因此選擇了一款特別輕量的summernote插件,並且後臺操做也很簡單。
官網:http://summernote.org/
github地址:https://github.com/summernote...css
先來看一下官網的截圖html
麻雀雖小五臟俱全。徹底能夠知足編輯器的須要。java
按照官網連接下載下來的是git
咱們須要使用的是在dist文件夾內github
其中font主要是編輯器內的圖標顯示,lang是各類語言,css則是樣式。咱們主要來看一下summernote.js。ajax
$.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(); });
$('.summernote').summernote({ placeholder:'請輸入文章內容', ... });
$('.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
連接部分進行了修改。
效果以下:
首先,咱們先看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>'; } }
能夠看到,點擊連接按鈕出現的彈框樣式就在LinkDialog
的initialize
方法中的body
,因此我在中間添加了一個input
上傳附件的部分。
'<div class="form-group">' + '<label>' + lang.link.attachment + '</label>' + '<input class="note-link-attachment form-control" type="file" />' + '</div>' +
那麼,咱們須要在lang.link
屬性中,新增一個attachment
附件屬性。
除此以外,在中文的轉換部分summernote-zh-CN.min.js中,添加link
的attachment: '添加附件'
好了,那麼咱們接下來須要處理的問題是上傳文件後的處理。
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...