gpt4 book ai didi

javascript - 如何在 Summernote 中插入占位符元素?

转载 作者:行者123 更新时间:2023-12-03 22:34:08 27 4
gpt4 key购买 nike

我正在为 Summernote 所见即所得编辑器(版本 0.8.1)开发一个插件,以将 iframe 元素插入代码中。

使用提供的示例,我设法在菜单中获得了插件按钮,它打开了一个对话框,我可以在其中输入 URL 和标题。给源码加个iframe Tag是没问题的,但这不是我想要的。

我想在代码中插入一个占位符,其标记类似于(或类似于):

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

现在,summernote 允许我编辑跨度的内容,但我想要一个占位符,它不能在编辑器中修改。

如何在具有以下属性的编辑器中插入占位符:
  • 它可以作为单个 block 进行编辑(可以通过单个删除来删除)
  • 单击时,我可以打开类似于链接或图像弹出框的弹出框来调整大小 f.i。
  • 内部内容不可修改

  • 这是我到目前为止所拥有的:
    // 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'
    }
    });

    最佳答案

    您可以使用 contenteditable 您的 span 上的属性元素,它将工作并保持 iframe编辑器中的插件 HTML,当按下 Del 或 Backspace 键时,它将删除整个 block 。
    Github repository 中有一些演示插件并且有一个演示了对话框和弹出框编辑的用法,您可以检查逻辑和代码here .
    createIframeNode我们创建元素并设置数据属性

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

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

    return $iframeSubst[0];
    };
    我们还创建了 currentEditing变量以在弹出菜单弹出时保存光标下的元素,因此 opoup 对话框将知道我们正在编辑一个元素而不是创建一个新元素。
    updateIframeNode我们正在使用 currentEditing要更新的元素
    这里我们只重新创建 span元素,因为 currentEditing是实际的 div.ext-iframe-subst然后我们更新数据属性:
    this.updateIframeNode = function (data) {
    $(currentEditing).html(
    '<span contenteditable="false">' +
    lang.iframe.url + ': ' + data.url +
    '</span>'
    )

    $(currentEditing)
    .attr("data-src", data.url)
    .attr("data-title", data.title);
    }
    完整的工作插件
    运行代码片段并尝试使用带有方形图标的按钮插入 iframe。您可以编辑现有的 iFrame 元素,并且 block 会一起删除。

    /**
    * @param {Object} context - context object has status of editor.
    */
    var iframePlugin = 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 dom = $.summernote.dom;

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

    // add context menu button
    context.memo('button.iframe', function () {
    return ui.button({
    contents: '<i class="note-icon-frame"/>',
    tooltip: lang.iframe.iframe,
    click: (event) => {
    currentEditing = null;
    context.createInvokeHandler('iframe.show')(event);
    }
    }).render();
    });

    context.memo('button.iframeDialog', function () {
    return ui.button({
    contents: '<i class="note-icon-frame"/>',
    tooltip: lang.iframe.iframe,
    click: (event) => {
    context.createInvokeHandler('iframe.show')(event);
    // currentEditing
    }
    }).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) {
    $('data.ext-iframe', e.editable).each(function() { self.setContent($(this)); });
    },
    // This will be called when user releases a key on editable.
    'summernote.keyup summernote.mouseup summernote.change summernote.scroll': function() {
    self.update();
    },
    'summernote.dialog.shown': function() {
    self.hidePopover();
    },
    };

    // 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.insertOrUpdate + '</button>';

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

    // create popover
    this.$popover = ui.popover({
    className: 'ext-iframe-popover',
    }).render().appendTo('body');
    var $content = self.$popover.find('.popover-content');

    context.invoke('buttons.build', $content, options.popover.iframe);
    };

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


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

    self.update = function() {
    // Prevent focusing on editable when invoke('code') is executed
    if (!context.invoke('editor.hasFocus')) {
    self.hidePopover();
    return;
    }

    var rng = context.invoke('editor.createRange');
    var visible = false;
    var $data = $(rng.sc).closest('div.ext-iframe-subst');

    if ($data.length) {
    currentEditing = $data[0];
    var pos = dom.posFromPlaceholder(currentEditing);
    const containerOffset = $(options.container).offset();
    pos.top -= containerOffset.top;
    pos.left -= containerOffset.left;

    self.$popover.css({
    display: 'block',
    left: pos.left,
    top: pos.top,
    });

    // save editor target to let size buttons resize the container
    context.invoke('editor.saveTarget', currentEditing);

    visible = true;
    }

    // hide if not visible
    if (!visible) {
    self.hidePopover();
    }
    };

    self.hidePopover = function() {
    self.$popover.hide();
    };

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

    $iframeSubst.attr("data-src", data.url).attr("data-title", data.title);
    return $iframeSubst[0];
    };

    this.updateIframeNode = function (data) {
    $(currentEditing).html(
    '<span contenteditable="false">' +
    lang.iframe.url + ': ' + data.url +
    '</span>'
    )

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

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

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

    if (currentEditing) {
    self.updateIframeNode(data);
    } else {
    // 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');

    var dataSrc = currentEditing ? $(currentEditing).attr('data-src') : '';
    var dataTitle = currentEditing ? $(currentEditing).attr('data-title') : '';

    $iframeTitle.val(dataTitle);
    $iframeUrl.val(dataSrc).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);
    });
    };
    }

    // Extends plugins for adding iframes.
    // - plugin is external module for customizing.
    $.extend(true, $.summernote, {
    plugins: {
    iframe: iframePlugin,
    },
    options: {
    popover: {
    iframe: [
    ['iframe', ['iframeDialog']],
    ],
    },
    },
    lang: {
    'en-US': {
    iframe: {
    iframe: 'iframe',
    url: 'iframe URL',
    title: 'title',
    insertOrUpdate: 'insert/update iframe',
    alt: 'Text alternative',
    alttext: 'you should provide a text alternative for the content in this iframe.',
    test: 'Test',
    },
    },
    },
    });

    $(document).ready(function() {
    $('#editor').summernote({
    height: 200,
    toolbar: [
    ['operation', ['undo', 'redo']],
    ['style', ['bold', 'italic', 'underline']],
    ['color', ['color']],
    ['insert', ['iframe', 'link','picture', 'hr']],
    ['view', ['codeview']],
    ],
    });
    });
    <!-- 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="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.js"></script>

    <div id="editor">Hello Summernote</div>

    关于javascript - 如何在 Summernote 中插入占位符元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35895445/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com