【问题标题】:Tridion RTF text selectionTridion RTF 文本选择
【发布时间】:2012-09-22 05:17:17
【问题描述】:

我正在编写一个 GUI 扩展,它本质上将选定的文本包装在特定的 DIV 中。我用 DIV 封装了文本,但遇到了一些障碍......

当用户没有选择一段特定的文本时,我假设意图是包装最近的 HTML 元素

htmlSelectedNode = target.editor.getSelectedHTMLElement()

这一切似乎工作正常,我将 HTML 元素传递到我的扩展程序中。经过一些操作后,我应用了 HTML,但它在前一个元素中注入了新的 HTML - 而不是替换它......

是否可以“选择”HTML 元素 - 我可以看到 .focus().setCapture(),但这些似乎不起作用 - 我想理想的情况是使用与应用相同的功能从功能区栏上的“当前元素”下拉列表中选择一个元素时,但我没有成功找到与此下拉列表关联的 onclick/select 方法。

只是为了澄清......举个例子......

如果文本是

    <div class="notrelevant"><p>test1</p><p>this is an example</p></div>

并且用户在“is”中的 i 和 s 之间插入了光标,我希望 GUI 预先选择最近的 HTML 元素 - 在这种情况下,最终结果将是......

    <div class="notrelevant"><p>test1</p><div class="INJECTED_CORRECTLY"><p>this is an example</p></div></div>

编辑: 为了完整起见,我已经包含了提交事件,用于(重新)将 HTML 注入到 RTF 中(尽管我认为此时操作选择没有意义,并且更愿意“选择”文本以上使用更“标准”的现有 Tridion 功能...)

   $evt.addEventHandler(popup, "submit",
        function DateHighlighter$execute$onPopupSubmitted(event) {

            var el = event.data.html;
            if (el) {
                if (htmlSelectedNode != null) {
                    var lDocument = htmlSelectedNode.ownerDocument;
                    var lTempContainer = lDocument.createElement("span");

                    try {
                        lTempContainer.innerHTML = el || "";
                    }
                    catch (err) {
                        //assigning a value to innerHTML can be sensitive to browser but the error is fine to be ignored
                    }

                    var parentNode = htmlSelectedNode.parentNode;
                    parentNode.replaceChild(lTempContainer, htmlSelectedNode);

                    //Move to the new element
                    var lTextRange = $dom.createTextRange(lTempContainer);
                    $dom.moveRangeToElement(lTextRange, lTempContainer);
                    //Select and remove the temporary element
                    $dom.selectRange(lTextRange, $dom.getSelection(lDocument));
                    $dom.removeNode(lTempContainer, false);

                }
                else {
                    // Insert new created element (DIV)
                    target.editor.applyHTML(el);
                }

            }
            else {
                //TODO: test this - it's likely not required
                if (htmlSelectedNode.attributes["class"] != null)
                    htmlSelectedNode.removeAttribute("class");

                //TODO: test this - it's likely not required
                if (htmlSelectedNode.attributes["ondblclick"] != null)
                    htmlSelectedNode.removeAttribute("ondblclick");

                //TODO: the node isn't removed - leaves the empty <div>... 
                // - delete the node and then apply the node2.outerHTML? - or follow parentnode pattern above!
                var htmlSelectedNode2 = htmlSelectedNode.innerHTML;
                htmlSelectedNode = htmlSelectedNode2;
            }

            //Refreshes the Design view
            target.editor.setCurrentView("Source");
            target.editor.setCurrentView("RichText");
            target.item.closeActivePopup();
        });
    $evt.addEventHandler(popup, "unload", DateHighlighter$execute$onPopupCanceled);

【问题讨论】:

    标签: tridion tridion-2011


    【解决方案1】:

    所以我找到了CurrentElement 选择并看到了明显的setSelectedHTMLElement。不知道我是如何错过它的,但唉,下面是...作为 cmets 注释 - 确保该方法可用(如果用户选择了不直接等同于 HTMLElement 的文本字符串,setSelectedHTMLElement 方法将失败并删除我们的用户选择(因此意味着 GUI 扩展 .aspx 不能(重新)注入新的 HTML...

    //if there's no tagname then the setSelected will fail and remove the (non-element based) select the user has done
    if (htmlSelectedNode.nodeName && htmlSelectedNode.nodeName != '#text') { 
        //unlikely to get #text here as it's the htmlSelectedNode.commonAncestorContainer.nodeName
        $log.message(logt + 'selecting the htmlSelectedNode.nodeName:' + htmlSelectedNode.nodeName);
        target.editor.setSelectedHTMLElement(htmlSelectedNode);
    }
    else {
        $log.message(logt + 'no htmlSelectedNode.nodeName - user probably selected incomplete element:');
    }
    

    【讨论】:

      【解决方案2】:

      这是一个棘手的问题。您将需要检查所有可能的情况。回到一年前,我们不得不将自定义的“超链接”功能实现为 GUI 扩展。问题是一样的:“我怎么知道选择了什么?”,“如果用户选择一个文本和一个 html 节点的一半怎么办?” “如果选择只是文本怎么办?”基本上与您面临的问题相同。

      如果我理解正确,您想用给定的(自定义)div 包装选定的文本,对吗?您还需要考虑的事情(如果您还没有考虑的话)是:“如果用户选择了一个已经用您的自定义 div 包装的文本会发生什么?”、“如果他选择一个用您的自定义 div 包装的文本会怎样?是在 div 之后还是之前的一大段文字?”

      嗯,正如我之前提到的,这并不容易,或者至少,不是直截了当。以下是我们所做的一些提示,在我们的例子中,我们必须使用超链接标签而不是 div 来包装文本,但从“获取/设置选定的 html”的角度来看,它应该会有所帮助:

      1st:初始化一个元素节点,获取选中的html:

      var element = null;
      var htmlSelectedNode = target.editor.getSelectedHTMLElement() || {};
      

      第二个:检查到底是什么:

          if (htmlSelectedNode != null && htmlSelectedNode.tagName != null && htmlSelectedNode.tagName == "A") { //In your case you might wanna check if it is a div, instead
          ...
          ...
      
      }
      

      注意:在我们的例子中,我们还必须检查图像和跨度标签,因为锚元素会有点不同,因为我们需要从中获取一些信息。

      3rd:如果选择的文本是一个元素,则设置元素变量(没有选择额外的文本)

      element = htmlSelectedNode;
      
      
      var selectedText = "";
          // Chrome & Firefox
                  if (htmlSelectedNode != null && htmlSelectedNode.startContainer != null && htmlSelectedNode.startOffset != null) {
      
                      selectedText = htmlSelectedNode.toString();
      
                  }
                  // IE Range
                  else if (htmlSelectedNode != null && htmlSelectedNode.htmlText != null && htmlSelectedNode.text != null) {
                      selectedText = htmlSelectedNode.text;
                  }
                  // IE DIV
                  else if (htmlSelectedNode != null && (htmlSelectedNode.tagName == "DIV" || htmlSelectedNode.tagName == "P") && htmlSelectedNode.innerText != null) {
                      selectedText = htmlSelectedNode.innerText;
                  }
      

      4rd:如果 htmlSelectedNode 在之前或之后包含一个节点和原始文本,我们使用范围(进一步阅读),考虑到不同的浏览器行为:

      好吧,这里的示例并不能真正解决您的问题,但我希望它们能给您一些关于如何检查 xhtml 内容的提示。基本上,您需要注意使选择成为有效的 xhtml 元素。

      这里有更多关于当元素已经包含链接标签时我们如何处理 xhtml 的示例:

      // If there is a link, delete it
      if (htmlSelectedNode != null) {
          var lDocument = htmlSelectedNode.ownerDocument;
          var lTempContainer = lDocument.createElement("span");
      
          try {
              lTempContainer.innerHTML = el || "";
          }
          catch (err) {
              //assigning a value to innerHTML might fail -> ignore it then
          }
      
          var parentNode = htmlSelectedNode.parentNode;
          parentNode.replaceChild(lTempContainer, htmlSelectedNode);
      
          //move to new element
          var lTextRange = $dom.createTextRange(lTempContainer);
          $dom.moveRangeToElement(lTextRange, lTempContainer);
          //select and remove temp element
          $dom.selectRange(lTextRange, $dom.getSelection(lDocument));
          $dom.removeNode(lTempContainer, false);
      
      }
      

      如何将 HTML 设置回 RTF 并刷新 Source/Design 选项卡:

      // Insert new created link
      target.editor.applyHTML(el); //el == element
      
      
      //Refreshes the Design view
      target.editor.setCurrentView("Source");
      target.editor.setCurrentView("RichText");
      

      再说一次,我知道这不能解决您的问题,但我认为您可以使用一些示例来尝试新方法。如果您需要进一步的帮助,请分享整个 JS 文件,或者至少分享 _execute() 方法(我假设您有代码,对吧?)

      问候,

      【讨论】:

      • 嗨 Jamie ...感谢您的回复。我一直在研究许多选项以及它们对包含的和周围的 HTML 元素的不同影响。目前,通过与客户一起审查,DIV 看起来很受欢迎,因为所有选项都有 +/- 的!示例非常好,感谢分享。
      猜你喜欢
      • 2017-07-05
      • 2012-12-16
      • 1970-01-01
      • 1970-01-01
      • 2012-02-19
      • 2014-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多