插件

本页面目前是一个进行中的工作,我们欢迎贡献者更新或添加说明。请通过创建一个问题,或一个拉取请求.

在开始构建自定义插件之前,请访问我们的官方仓库awesome-summernote。其中包含用户贡献的插件。这可能为您构建自己的插件节省大量时间,或者为您提供机会为已有的插件做出贡献,使其变得更好。

添加插件

将插件添加到Summernote页面与将Summernote添加到您希望Summernote出现的页面一样简单。

大多数脚本不需要您添加CSS文件,尽管一些依赖于脚本功能的插件可能需要您添加必要的样式,无论是内联在页面中,还是通过添加CSS文件链接来添加其所需的样式。一些插件还可能在初始化时动态地向DOM添加样式。

我们通常在加载Summernote脚本之后加载插件脚本。

大多数脚本添加在典型HTML页面的头部区域。

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- include libraries(jQuery, bootstrap) -->
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>

    <!-- include summernote css/js -->
    <link href="thirdparty/summernote.min.css" rel="stylesheet">
    <script src="thirdparty/summernote.min.js"></script>

    <!-- include plugin -->
    <script src="[folder where script is located]/[plugin script].js"></script>
  </head>
  <body>

可能需要与插件文件一起加载的其他东西可能是语言文件,它们应该在插件包含之后加载。

对于刚开始使用JavaScript的人来说,在加载主要的Summernote脚本之后加载插件,然后在需要时加载语言文件,是按照这种方式进行的,因为一些脚本设计为在加载时执行,并且需要按顺序执行,以便它们能够访问在前面脚本中可用的函数。这更常见的原因是一些脚本直到它们被放入一个允许它们正常工作的顺序中才无法正常工作。

添加交互模块。

将交互模块添加到Summernote与在初始化Summernote编辑器时调用Summernote中可用的选项一样简单。

为工具栏添加交互。

$(document).ready(function() {
  $('#summernote').summernote({
    toolbar:[

      // This is a Custom Button in a new Toolbar Area
      ['custom', ['examplePlugin']],

      // You can also add Interaction to an existing Toolbar Area
      ['style', ['style' ,'examplePlugin']]
    ]
  });
});

为弹出窗口添加交互

$(document).ready(function() {
  $('#summernote').summernote({
    popover: {
      image: [

        // This is a Custom Button in a new Toolbar Area
        ['custom', ['examplePlugin']],
        ['imagesize', ['imageSize100', 'imageSize50', 'imageSize25']],
        ['float', ['floatLeft', 'floatRight', 'floatNone']],
        ['remove', ['removeMedia']]
      ]
    }
  });
});

创建插件

对于那些不熟悉脚本样式的人来说,我们想指出的是,代码区域的内联注释(// This is a comment)描述了正在发生的事情,或者您可以在注释下方的代码区域中更改哪些选项。虽然这可能不总是别人的风格,但我们只是想确保在您阅读以下示例时,注释描述的部分没有混淆。

/**
 *
 * copyright [year] [your Business Name and/or Your Name].
 * email: your@email.com
 * license: Your chosen license, or link to a license file.
 *
 */
(function (factory) {
  /* Global define */
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof module === 'object' && module.exports) {
    // Node/CommonJS
    module.exports = factory(require('jquery'));
  } else {
    // Browser globals
    factory(window.jQuery);
  }
}(function ($) {
/**
 * @class plugin.examplePlugin
 *
 * example Plugin
*/

语言

如果您的插件包含文本内容,我们需要扩展Summernote脚本中的语言lang引用,以添加我们自己的语言引用。

要访问插件脚本中的语言翻译变量,您可以直接使用lang.examplePlugin.exampleText.

  $.extend(true,$.summernote.lang, {
    'en-US': { /* US English(Default Language) */
      examplePlugin: {
        exampleText: 'Example Text',
        dialogTitle: 'Example Plugin',
        okButton: 'OK'
      }
    }
  });

您也可以创建语言文件以链接到您的页面,就像将语言文件添加到Summernote本身一样,并使用与上述代码完全相同的格式。

插件选项

这允许我们向插件添加选项,以根据用户配置修改行为。

  $.extend($.summernote.options, {
    examplePlugin: {
      icon: '<i class="note-icon-pencil"/>',
      tooltip: 'Example Plugin Tooltip'
    }
  });

插件功能

这部分是插件的功能部分。

  $.extend($.summernote.plugins, {
    /**
     *  @param {Object} context - context object has status of editor.
     */
    'examplePlugin':function (context) {

以下变量并非全部需要,您需要什么取决于您试图通过插件实现什么。通常您需要self, ui, options,和lang.

      var self      = this,

         // ui has renders to build ui elements
         // for e.g. you can create a button with 'ui.button'
          ui        = $.summernote.ui,
          $note     = context.layoutInfo.note,

          // contentEditable element
          $editor   = context.layoutInfo.editor,
          $editable = context.layoutInfo.editable,
          $toolbar  = context.layoutInfo.toolbar,

          // options holds the Options Information from Summernote and what we extended above.
          options   = context.options,

          // lang holds the Language Information from Summernote and what we extended above.
          lang      = options.langInfo;

      context.memo('button.examplePlugin', function () {

        // Here we create a button
        var button = ui.button({

          // icon for button
          contents: options.examplePlugin.icon,

          // tooltip for button
          tooltip: lang.examplePlugin.tooltip,

          // Keep button from being disabled when in CodeView
          codeviewKeepButton: true,

          click:function (e) {
            context.invoke('examplePlugin.show');
          }
        });
        return button.render();
      });

这部分在插件首次初始化时执行功能。注意,这是插件加载时,而不是插件使用时。

      this.initialize = function() {

        // This is how we can add a Modal Dialog to allow users to interact with the Plugin.

        // get the correct container for the plugin how it's attached to the document DOM.
        // Using the current latest development branch, you can now use $.summernote.interface;
        // to return which Summernote is being used to be able to adjust the modal layout to suit.
        // using this.options.id will return a generated timestamp when Summernote was initiliased
        // on page to allow using unique ID's.
        var $container = options.dialogsInBody ? $(document.body) : $editor;

        // Build the Body HTML of the Dialog.
        var body = '<div class="form-group">' +
                   '</div>';

请参阅“模态标记”部分,以了解模态内部元素的标记选项。

        // Build the Footer HTML of the Dialog.
        var footer = '<button href="#" class="btn btn-primary note-examplePlugin-btn">' + lang.examplePlugin.okButton + '</button>'
      }
      this.$dialog = ui.dialog({

        // Set the title for the Dialog. Note: We don't need to build the markup for the Modal
        // Header, we only need to set the Title.
        title: lang.examplePlugin.dialogTitle,

        // Set the Body of the Dialog.
        body: body,

        // Set the Footer of the Dialog.
        footer: footer

      // This adds the Modal to the DOM.
      }).render().appendTo($container);
    };
    this.destroy = function () {
      ui.hideDialog(this.$dialog);
      this.$dialog.remove();
    };
    this.bindEnterKey = function ($input, $btn) {
      $input.on('keypress', function (event) {
        if (event.keyCode === 13) $btn.trigger('click');
      });
    };
    this.bindLabels = function () {
      self.$dialog.find('.form-control:first').focus().select();
      self.$dialog.find('label').on('click', function () {
        $(this).parent().find('.form-control:first').focus();
      });
    };
    this.show = function () {
      var $img = $($editable.data('target'));
      var editorInfo = {

      };
      this.showexamplePluginDialog(editorInfo).then(function (editorInfo) {
        ui.hideDialog(self.$dialog);
        $note.val(context.invoke('code'));
        $note.change();
      });
    };
    this.showexamplePluginDialog = function(editorInfo) {
      return $.Deferred(function (deferred) {
        ui.onDialogShown(self.$dialog, function () {
          context.triggerEvent('dialog.shown');
          $editBtn.click(function (e) {
            e.preventDefault();
            deferred.resolve({

            });
          });
          self.bindEnterKey($editBtn);
          self.bindLabels();
        });
        ui.onDialogHidden(self.$dialog, function () {
          $editBtn.off('click');
          if (deferred.state() === 'pending') deferred.reject();
        });
        ui.showDialog(self.$dialog);
      });
    };
  }
})));

这部分解释并展示了可以在模态内部使用的元素和类别的示例。

注意:您可以混合BS3、BS4(它们是相似的)和Lite版本的类,以便插件可以版本控制以适应Bootstrap或不是Bootstrap特定的,或者它们可以制作兼容所有(首选方法)。

在Summernote模态中使用标记元素的主要问题在于,当尝试使用这些元素以使其与所有版本的Bootstrap或Summernote的Lite版本兼容时,这个问题会变得明显。为了尽量减轻这个问题,有一个可以检查的设置变量interface,在插件中检查此设置将返回BS3, BS4Lite,这将允许添加逻辑控制以确定插件需要使用哪种标记或行为以实现兼容性,或者您可以只是使用标准的元素布局,并添加适当的类来覆盖所有版本(首选)。

通常,您想要为它制作插件的Bootstrap版本的元素和类别可以使用该版本的Bootstrap元素,我们已经尝试,即使使用Lite版本,也尽量保持这些元素尽可能接近。

我们在下面包含了一些示例,以帮助您更快地构建模态。

任何以note-开头的类主要是Summernote类,以尽量减少与其他您可能用于其他目的的DOM类冲突。然而,大多数模态使用Bootstrap类作为其主要样式,除了在Summernote的Lite版本中,它依赖于note-*类来标记元素。

表单布局

var body = '<div class="form-group note-form-group">' +
              '<div class="help-block note-help-block">Helpful text block</div>' +
            '</div>' +
            '<div class="form-group note-form-group">' +
              '<label for="note-input-1" class="control-label note-form-label">Input Label 1</label>' +
              '<div class="input-group note-input-group">' +
                '<input type="text" id="note-input-1" class="form-contro note-input">' +
              '</div>' +
            '</div>';

标签面板布局

var body = '<ul class="nav note-nav nav-tabs note-nav-tabs">' +
              '<li class="nav-item note-nav-item active">' +
                '<a class="nav-link note-nav-link active" href="#note-pane-1" data-toggle="tab">Pane 1</a>' +
              '</li>' +
              '<li class="nav-item note-nav-item active">' +
                '<a class="nav-link note-nav-link active" href="#note-pane-2" data-toggle="tab">Pane 2</a>' +
              '</li>' +
              '<li class="nav-item note-nav-item active">' +
                '<a class="nav-link note-nav-link active" href="#note-pane-3" data-toggle="tab">Pane 3</a>' +
              '</li>' +
            '</ul>' +

// Pane 2
            '<div class="tab-content note-tabe-content" id="note-pane-2">' +
            '</div>';

// Pane 3
            '<div class="tab-content note-tabe-content" id="note-pane-3">' +
            '</div>';

// Pane 1, is added last due to how the Styling works to make this Panel active and visible.
            '<div class="tab-content note-tabe-content active" id="note-pane-1">' +
            '</div>';