Saturday, 6 February 2021

How to insert a placeholder element in Summernote?

I'm developing a plugin for Summernote WYSIWYG editor (version 0.8.1) to insert iframe elements into the code.

Working with the samples provided, I managed to get the plugin button in the menu, which opens a dialog where I can enter an URL and a title. It's no problem to add an iframe Tag to the source, but this is not what I want.

I want to insert a placeholder into the code, with a markup like (or similar to) this:

<div class="ext-iframe-subst" data-src="http://www.test.example" data-title="iframe title"><span>iframe URL: http://www.test.example</span></div>

Now, summernote lets me edit the contents of the span, but I'd like to have a placeholder instead, that can't be modified in the editor.

How can I insert a placeholder into the editor, that has the following properties:

  • It is editable as a single block (can be deleted with a single delete)
  • On click, I can open a popover similar to the link or image popover to adjust size f.i.
  • The inner content is not modifyable

This is what I have so far:

// Extends plugins for adding iframes.
//  - plugin is external module for customizing.
$.extend($.summernote.plugins, {
  /**
   * @param {Object} context - context object has status of editor.
   */
  'iframe': function (context) {
    var self = this;

    // ui has renders to build ui elements.
    //  - you can create a button with `ui.button`
    var ui = $.summernote.ui;

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

    // add context menu button
    context.memo('button.iframe', function () {
      return ui.button({
        contents: '<i class="fa fa-newspaper-o"/>',
        tooltip: lang.iframe.iframe,
        click: context.createInvokeHandler('iframe.show')
      }).render();
    });


    // This events will be attached when editor is initialized.
    this.events = {
      // This will be called after modules are initialized.
      'summernote.init': function (we, e) {
        console.log('IFRAME initialized', we, e);
      },
      // This will be called when user releases a key on editable.
      'summernote.keyup': function (we, e) {
        console.log('IFRAME keyup', we, e);
      }
    };

    // This method will be called when editor is initialized by $('..').summernote();
    // You can create elements for plugin
    this.initialize = function () {
      var $container = options.dialogsInBody ? $(document.body) : $editor;

      var body = '<div class="form-group row-fluid">' +
          '<label>' + lang.iframe.url + '</label>' +
          '<input class="ext-iframe-url form-control" type="text" />' +
          '<label>' + lang.iframe.title + '</label>' +
          '<input class="ext-iframe-title form-control" type="text" />' +
          '<label>' + lang.iframe.alt + '</label>' +
          '<textarea class="ext-iframe-alt form-control" placeholder="' + lang.iframe.alttext + '" rows=""10""></textarea>' +
          '</div>';
      var footer = '<button href="#" class="btn btn-primary ext-iframe-btn disabled" disabled>' + lang.iframe.insert + '</button>';

      this.$dialog = ui.dialog({
        title: lang.iframe.insert,
        fade: options.dialogsFade,
        body: body,
        footer: footer
      }).render().appendTo($container);
    };

    // This methods will be called when editor is destroyed by $('..').summernote('destroy');
    // You should remove elements on `initialize`.
    this.destroy = function () {
      this.$dialog.remove();
      this.$dialog = null;
    };


    this.bindEnterKey = function ($input, $btn) {
      $input.on('keypress', function (event) {
        if (event.keyCode === 13) { //key.code.ENTER) {
          $btn.trigger('click');
        }
      });
    };



    this.createIframeNode = function (data) {
      var $iframeSubst = $('<div class="ext-iframe-subst"><span>' + lang.iframe.iframe + '</span></div>');

      $iframeSubst.attr("data-src", data.url).attr("data-title", data.title);

      return $iframeSubst[0];
    };


    this.show = function () {
      var text = context.invoke('editor.getSelectedText');
      context.invoke('editor.saveRange');

      console.log("iframe.getInfo: " + text);

      this
        .showIframeDialog(text)
        .then(function (data) {
          // [workaround] hide dialog before restore range for IE range focus
          ui.hideDialog(self.$dialog);
          context.invoke('editor.restoreRange');

          // build node
          var $node = self.createIframeNode(data);

          if ($node) {
            // insert iframe node
            context.invoke('editor.insertNode', $node);
          }
        })
        .fail(function () {
          context.invoke('editor.restoreRange');
        });

    };

    this.showIframeDialog = function (text) {
      return $.Deferred(function (deferred) {
        var $iframeUrl = self.$dialog.find('.ext-iframe-url');
        var $iframeTitle = self.$dialog.find('.ext-iframe-title');
        var $iframeBtn = self.$dialog.find('.ext-iframe-btn');

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

          $iframeUrl.val(text).on('input', function () {
            ui.toggleBtn($iframeBtn, $iframeUrl.val());
          }).trigger('focus');

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

            deferred.resolve({ url: $iframeUrl.val(), title: $iframeTitle.val() });
          });

          self.bindEnterKey($iframeUrl, $iframeBtn);
        });

        ui.onDialogHidden(self.$dialog, function () {
          $iframeUrl.off('input');
          $iframeBtn.off('click');

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

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


  }
});

// add localization texts
$.extend($.summernote.lang['en-US'], {
    iframe: {
      iframe: 'iframe',
      url: 'iframe URL',
      title: 'title',
      insert: 'insert iframe',
      alt: 'Text alternative',
      alttext: 'you should provide a text alternative for the content in this iframe.',
      test: 'Test'
    }
});


from How to insert a placeholder element in Summernote?

No comments:

Post a Comment