You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Wagtail富文本编辑器Pre标签按钮:实现选中文本包裹/解包裹功能求助

解决Wagtail富文本编辑器
标签切换按钮的问题 

我刚帮你排查了代码里的问题,核心是你对getSelection()返回的原生Selection对象处理不对,还有切换逻辑的判断方式有问题。咱们一步步改,让按钮像粗体/斜体那样支持添加/移除

标签:

问题分析

  1. lastSelection = widget.options.editable.getSelection()拿到的是原生Selection对象,不是DOM元素,所以直接用$(lastSelection)会失效,这也是你看到lastSelection相关报错的原因。
  2. 判断选中文本是否包含
    的逻辑不对,应该检查选区的内容是否已经被
    标签包裹,而不是直接查找选区里的
    。
  3. 直接拼接<pre>和Selection对象的方式错误,应该用Range API来操作选区内容。

修改后的完整代码

(function() {
  (function($) {
    return $.widget("IKS.prebutton", {
      options: {
        uuid: '',
        editable: null
      },
      populateToolbar: function(toolbar) {
        var button, widget;
        widget = this;
        button = $('<span></span>');
        button.hallobutton({
          uuid: this.options.uuid,
          editable: this.options.editable,
          label: 'Pre Tag',
          icon: 'fa fa-backward',
          command: null
        });
        toolbar.append(button);
        
        return button.on("click", function(event) {
          event.preventDefault();
          var selection = widget.options.editable.getSelection();
          
          // 确保有选中内容
          if (selection.rangeCount === 0) return;
          
          var range = selection.getRangeAt(0);
          var selectedContent = range.extractContents();
          var preElement = null;
          
          // 检查选区是否在<pre>标签内
          var currentNode = range.commonAncestorContainer;
          // 从文本节点往上找元素节点
          while (currentNode && currentNode.nodeType !== 1) {
            currentNode = currentNode.parentNode;
          }
          preElement = $(currentNode).closest('pre')[0];
          
          if (preElement) {
            // 如果已经在<pre>里,移除标签,放回内容
            var parent = preElement.parentNode;
            parent.insertBefore(selectedContent, preElement);
            parent.removeChild(preElement);
          } else {
            // 如果没有<pre>,创建新标签包裹内容
            var pre = document.createElement('pre');
            pre.appendChild(selectedContent);
            range.insertNode(pre);
          }
          
          // 触发编辑器变化事件,让Wagtail保存修改
          widget.options.editable.element.trigger('change');
          
          // 重新选中处理后的内容(可选,提升用户体验)
          var newRange = document.createRange();
          newRange.selectNodeContents(preElement ? parent : pre);
          selection.removeAllRanges();
          selection.addRange(newRange);
        });
      }
    });
  })(jQuery);
}).call(this);

关键修改点说明

  • 正确处理Selection和Range:用selection.getRangeAt(0)获取选区的Range对象,通过Range API来提取、插入内容,这是操作富文本选区的标准方式。
  • 检查
    存在性:从选区的共同祖先节点往上查找,判断是否已经在
    标签内,避免误判。
  • 切换逻辑实现:
    • 如果已经有
      :把
      标签移除,将里面的内容放回原来的位置。
    • 如果没有
      :创建新的
      标签,把选中的内容包裹后插入选区。
  • 触发change事件:确保Wagtail能感知到编辑器内容的变化,正常保存修改。
  • 可选的选区恢复:处理完后重新选中内容,让用户直观看到操作效果。

记得把这段代码替换你原来的按钮点击事件部分,同时确保你的页面已经正确引入了jQuery和jQuery UI(你提供的外部脚本没问题)。

内容的提问来源于stack exchange,提问作者JaredOzzy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:17:03