在 summernote 编辑器中用插入替换选定的文本

Replace selected text with insertion in summernote editor

我正在尝试为 summernote v0.8.9 创建一个插件。

在下面找到我的最小可行示例:

$(document).ready(function() {
  $('.summernote').summernote({
    height: 300,
    tabsize: 2,
    toolbar: [
      ['insert', ['synonym', 'codeview']]
    ],
  });
});

(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($) {

  // minimal dialog plugin
  $.extend($.summernote.plugins, {
    'synonym': function(context) {
      var self = this;

      var ui = $.summernote.ui;

      var $editor = context.layoutInfo.editor;
      var options = context.options;

      // add context menu button
      context.memo('button.synonym', function() {
        return ui.button({
          contents: '<i class="fa fa-snowflake-o">',
          tooltip: 'Create Synonym',
          click: context.createInvokeHandler('synonym.showDialog')
        }).render();
      });

      self.initialize = function() {
        var $container = options.dialogsInBody ? $(document.body) : $editor;

        var body = '<div class="form-group">' +
          '<label>Element</label>' +
          '<input id="input-element" class="form-control" type="text"/>' +
          '</div>' +
          '<label>Synonym</label>' +
          '<input id="input-synonym" class="form-control" type="text" placeholder="Insert your synonym" />'
        var footer = '<button href="#" class="btn btn-primary ext-synonym-btn">OK</button>';

        self.$dialog = ui.dialog({
          title: 'minimal dialog title',
          fade: options.dialogsFade,
          body: body,
          footer: footer
        }).render().appendTo($container);
      };

      self.destroy = function() {
        self.$dialog.remove();
        self.$dialog = null;
      };

      self.showDialog = function() {
        self
          .openDialog()
          .then(function(data) {
            // [workaround] hide dialog before restore range for IE range focus
            ui.hideDialog(self.$dialog);
            context.invoke('editor.restoreRange');
            self.insertToEditor(data);
            // do something with dialogData
            console.log("dialog returned: ", data)
            // ...
          })
          .fail(function() {
            context.invoke('editor.restoreRange');
          });

      };

      self.openDialog = function() {
        return $.Deferred(function(deferred) {
          var $dialogBtn = self.$dialog.find('.ext-synonym-btn');
          var $elemInput = self.$dialog.find('#input-element')[0];
          var $synonymInput = self.$dialog.find('#input-synonym')[0];

          var selectedText = $.selection()
          $('#input-element').val(selectedText);
          console.log("show dialog: " + selectedText)

          ui.onDialogShown(self.$dialog, function() {
            context.triggerEvent('dialog.shown');

            $dialogBtn
              .click(function(event) {
                event.preventDefault();

                deferred.resolve({
                  element: $elemInput.value,
                  synonym: $synonymInput.value
                });
              });
          });

          ui.onDialogHidden(self.$dialog, function() {
            $dialogBtn.off('click');

            if (deferred.state() === 'pending') {
              deferred.reject();
            }
          });

          ui.showDialog(self.$dialog);
        });
      };

      //text that is written to the editor
      this.insertToEditor = function(data) {
        console.log("synonym: " + data.synonym)

        var $elem = $('<synonym>', {
          words: data.synonym
        });;

        $elem.text(data.element)

        context.invoke('editor.insertNode', $elem[0]);
      };
    }
  });
}));
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-pdapHxIh7EYuwy6K7iE41uXVxGCXY0sAjBzaElYGJUrzwodck3Lx6IE2lA0rFREo" crossorigin="anonymous">
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.10/summernote.css" />

<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.10/summernote.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.selection/1.0.1/jquery.selection.js"></script>

<div class="container">
  <div class="summernote">
    <p>Hello World!</p>
    This text should be replaced by the dialog. </div>
</div>

正如您在上面看到的,我正在使用 api function context.invoke('editor.insertNode', $elem[0]);,它基本上是在页面开头插入对话框 window 中的元素。

但是,我想用在对话框中创建的元素替换所选词。

有什么建议吗?

感谢您的回复!

你走在正确的轨道上。看来您必须通过以下方式保存选择:

context.invoke('editor.saveRange');   // note line 94 in the snippet

然后使用:

context.invoke('editor.insertText', data.element); // note line 133 in the snippet

我正在插入 data.element 但您显然可以将 synonym 或其他内容放在那里 :)

Their documentation 不是很好,但经过一些尝试和错误后它会起作用。

$(document).ready(function() {
  $('.summernote').summernote({
    height: 300,
    tabsize: 2,
    toolbar: [
      ['insert', ['synonym', 'codeview']]
    ],
  });
});

(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($) {

  // minimal dialog plugin
  $.extend($.summernote.plugins, {
    'synonym': function(context) {
      var self = this;

      var ui = $.summernote.ui;

      var $editor = context.layoutInfo.editor;
      var options = context.options;

      // add context menu button
      context.memo('button.synonym', function() {
        return ui.button({
          contents: '<i class="fa fa-snowflake-o">',
          tooltip: 'Create Synonym',
          click: context.createInvokeHandler('synonym.showDialog')
        }).render();
      });

      self.initialize = function() {
        var $container = options.dialogsInBody ? $(document.body) : $editor;

        var body = '<div class="form-group">' +
          '<label>Element</label>' +
          '<input id="input-element" class="form-control" type="text"/>' +
          '</div>' +
          '<label>Synonym</label>' +
          '<input id="input-synonym" class="form-control" type="text" placeholder="Insert your synonym" />'
        var footer = '<button href="#" class="btn btn-primary ext-synonym-btn">OK</button>';

        self.$dialog = ui.dialog({
          title: 'minimal dialog title',
          fade: options.dialogsFade,
          body: body,
          footer: footer
        }).render().appendTo($container);
      };

      self.destroy = function() {
        self.$dialog.remove();
        self.$dialog = null;
      };

      self.showDialog = function() {
        self
          .openDialog()
          .then(function(data) {
            // [workaround] hide dialog before restore range for IE range focus
            ui.hideDialog(self.$dialog);
            context.invoke('editor.restoreRange');
            self.insertToEditor(data);
            // do something with dialogData
            console.log("dialog returned: ", data)
            // ...
          })
          .fail(function() {
            context.invoke('editor.restoreRange');
          });

      };

      self.openDialog = function() {
        return $.Deferred(function(deferred) {
          var $dialogBtn = self.$dialog.find('.ext-synonym-btn');
          var $elemInput = self.$dialog.find('#input-element')[0];
          var $synonymInput = self.$dialog.find('#input-synonym')[0];

          var selectedText = $.selection()
          $('#input-element').val(selectedText);
          context.invoke('editor.saveRange');
          console.log("show dialog: " + selectedText)

          ui.onDialogShown(self.$dialog, function() {
            context.triggerEvent('dialog.shown');

            $dialogBtn
              .click(function(event) {
                event.preventDefault();

                deferred.resolve({
                  element: $elemInput.value,
                  synonym: $synonymInput.value
                });
              });
          });

          ui.onDialogHidden(self.$dialog, function() {
            $dialogBtn.off('click');

            if (deferred.state() === 'pending') {
              deferred.reject();
            }
          });

          ui.showDialog(self.$dialog);
        });
      };

      //text that is written to the editor
      this.insertToEditor = function(data) {
        console.log("synonym: " + data.synonym)

        var $elem = $('<synonym>', {
          words: data.synonym
        });;

        $elem.text(data.element)           

        context.invoke('editor.insertText', data.element);
      };
    }
  });
}));
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-pdapHxIh7EYuwy6K7iE41uXVxGCXY0sAjBzaElYGJUrzwodck3Lx6IE2lA0rFREo" crossorigin="anonymous">
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.10/summernote.css" />

<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.10/summernote.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.selection/1.0.1/jquery.selection.js"></script>

<div class="container">
  <div class="summernote">
    <p>Hello World!</p>
    This text should be replaced by the dialog. </div>
</div>