javascript - 如何阻止对 CKEDITOR textarea 中的某些内容进行编辑?

标签 javascript plugins configuration ckeditor backspace

我的 CKEDITOR 表单预填充了隐藏表,该表与用户输入的文本一起提交。这工作正常,但有时用户按退格键太多次并删除隐藏表。

有没有办法阻止在 ckeditor textarea 中的这个隐藏表上进行编辑?因此,当用户按下退格键时,隐藏表不会受到影响并保持不变。

一旦 CKEDITOR 实例准备就绪,这个源代码(如下所示)就被放入 CkEditor Textarea(使用 setData() 属性)并且用户只能看到返回的 <p></p>值(value)。在这种情况下它是 <p>I really think I can do this!</p> .这是对他个人资料的描述,他可以保留和编辑它。其余的是隐藏的,只有在提交表单时才会在电子邮件中可见。奇怪的是<p></p>位于顶部,但如果用户按几次退格键,表将被删除,因此不会提交。

    <span id="messageTemplate1" class="message">

<p>I really think I can do this!</p>

<table class="hide" style="font-size: 12px;">
    <tbody>
        <tr class="hide">
            <td>
            Application sent by <strong><a href="http://www.globalcastingcenter.com/talent/jack-bolton">Matt Faro</a></strong> for Audition: <a href="http://www.globalcastingcenter.com:80/CustomContentRetrieve.aspx?ID=4185493">Actors Needed</a>
            </td>
        </tr>
        <tr class="hide">
            <td>
            Reply to applicant directly: mantas@mantas.co or visit full profile: http://www.globalcastingcenter.com/talent/jack-bolton
            </td>
        </tr>
    </tbody>
</table>
<table class="hide" style="font-size: 12px;">
    <tbody>
        <tr class="hide">
            <td><strong>Short Profile Summary:</strong></td>
        </tr>
    </tbody>
</table>
<table class="hide" style="font-size: 12px;">
    <tbody>
        <tr class="hide">
            <td>
            <a href="http://www.globalcastingcenter.com/talent/jack-bolton"><img alt="" src="http://globalcastingcenter.com/talent_images/4164035_258551_foto.png?Action=thumbnail&amp;Width=144&amp;Height=215" /></a>
            </td>
        </tr>
    </tbody>
</table>
<table style="font-size: 12px;" class="hide">
    <tbody>
        <tr class="hide">
            <td><strong>Areas:</strong></td>
            <td>Actor,Extra</td>
        </tr>
        <tr class="hide">
            <td><strong>Country:</strong></td>
            <td>WORLDWIDE,Any</td>
        </tr>
        <tr class="hide">
            <td><strong>Age:</strong></td>
            <td>26</td>
        </tr>
    </tbody>
</table>
</span>

现在,当我加载您的插件时,我的 CKeditor 框消失了,请在测试页面上按“应用”http://gcc-july.themantas.co.uk/auditions/actors-needed请先登录才能访问消息框登录名:tiknius@gmail.com pssw:test

我的配置文件:

CKEDITOR.editorConfig = function( config )
{
    config.toolbar = 'MyToolbar';

    config.toolbar_MyToolbar =
    [

        { name: 'clipboard', items : [ 'Undo','Redo' ] },           
        { name: 'styles', items : ['FontSize' ] },
        { name: 'basicstyles', items : [ 'Bold','Italic'] },
        { name: 'paragraph', items : ['Outdent','Indent' ] },

    ];

    config.removePlugins = 'contextmenu';
    config.forcePasteAsPlainText = true;   
    config.pasteFromWordRemoveFontStyles = true;
    config.pasteFromWordRemoveStyles = true;
    config.extraPlugins = 'cwjdsjcsconfineselection';
    config.startupShowBorders = false;
    config.disableObjectResizing = true;

};

这是当我禁用你的插件时盒子的样子:http://screencast.com/t/Kc2bIOU8md2

我使用您建议的 HTML 结构。

最佳答案

我不得不花点时间让它工作。我在插件代码中添加了很多文档,如果您在阅读后有任何疑问,请告诉我。

我包含了您的内容 block 和插件代码块的更新版本。


这是您更新的内容 block 。当包裹在 <span> 中时它不工作标记,所以我将它包裹在一个表格中。

您可能不喜欢数据单元格周围出现的边框和调整大小的轮廓,如果是这种情况,请将这些设置添加到您的配置中:
config.startupShowBorders = false;
config.disableObjectResizing = true;

一些注意事项:
空的<td>在需要您的起始内容之前,它会阻止用户使用“Ctrl A”来选择允许他们删除隐藏表的所有内容。

我删除了 <p>来自起始内容的标记,因为它在此结构中表现得很时髦。

<td>包含隐藏表的有一个 &nbsp;字符,它会阻止用户使用“Ctrl A”来选择允许他们删除隐藏表的所有内容。如果删除光标右侧的所有内容,会导致光标丢失,但您可以点击内容重新开始编辑。

contenteditable="false"属性由 CkEditor 使用并且是必需的,但它并不能完成全部工作。您可以在不激活插件的情况下试用新的 HTML,看看它本身有什么效果。

插件代码中有关于我使用的类和 ID 的注释。

<!-- Begin Wrapper Table that Replaces <span> element -->
<table id="messageTemplate1" class="message cwjdsjcs_editable">
    <tbody>
        <tr>
            <td class="cwjdsjcs_not_editable" contenteditable="false">
            </td>
            <td id="cwjdsjcs_editable_id">
                I really think I can do this!
            </td>
        </tr>

        <tr class="cwjdsjcs_not_editable" contenteditable="false">
            <td colspan="2">
                &nbsp;

                <!-- Begin Original Content -->
                <table class="hide" style="font-size: 12px; display:none;">
                    <tbody>
                        <tr class="hide">
                            <td>
                            Application sent by <strong><a href="http://www.globalcastingcenter.com/talent/jack-bolton">Matt Faro</a></strong> for Audition: <a href="http://www.globalcastingcenter.com:80/CustomContentRetrieve.aspx?ID=4185493">Actors Needed</a>
                            </td>
                        </tr>
                        <tr class="hide">
                            <td>
                            Reply to applicant directly: mantas@mantas.co or visit full profile: http://www.globalcastingcenter.com/talent/jack-bolton
                            </td>
                        </tr>
                    </tbody>
                </table>
                <table class="hide" style="font-size: 12px; display:none;">
                    <tbody>
                        <tr class="hide">
                            <td><strong>Short Profile Summary:</strong></td>
                        </tr>
                    </tbody>
                </table>
                <table class="hide" style="font-size: 12px; display:none;">
                    <tbody>
                        <tr class="hide">
                            <td>
                            <a href="http://www.globalcastingcenter.com/talent/jack-bolton"><img alt="" src="http://globalcastingcenter.com/talent_images/4164035_258551_foto.png?Action=thumbnail&amp;Width=144&amp;Height=215" /></a>
                            </td>
                        </tr>
                    </tbody>
                </table>
                <table style="font-size: 12px; display:none;" class="hide">
                    <tbody>
                        <tr class="hide">
                            <td><strong>Areas:</strong></td>
                            <td>Actor,Extra</td>
                        </tr>
                        <tr class="hide">
                            <td><strong>Country:</strong></td>
                            <td>WORLDWIDE,Any</td>
                        </tr>
                        <tr class="hide">
                            <td><strong>Age:</strong></td>
                            <td>26</td>
                        </tr>
                    </tbody>
                </table>
                <!-- End Original Content -->

            </td>
        </tr>
    </tbody>
</table>
<!-- End Wrapper Table that Replaces <span> element -->

这是插件代码,叫做“cwjdsjcsconfineselection”。

添加插件:
在插件目录中创建一个名为“cwjdsjcsconfineselection”的文件夹:ckeditor/plugins/
在该目录中创建一个名为“plugins.js”的文件,并将下面的代码粘贴到该文件中。 我的错误:文件名为 plugin.js,而不是 plugin(s).js。

如果您已经有额外的插件,请将“cwjdsjcsconfineselection”添加到 extraPlugins 配置设置中,否则将此设置添加到您的配置中:
config.extraPlugins = 'cwjdsjcsconfineselection';

插件应该在您下次加载编辑器时工作。

对于我的情况,当用户在不可编辑的区域中单击时,我会出现一个对话框来解释为什么光标移回之前的选择。这对你的使用来说似乎不是必需的,所以我把它注释掉了。

/*
  Plugin that prevents editing of elements with the "non-editable" class as well as elements outside of blocks with "editable" class.
*/

//* **************************  NOTES  ***************************  NOTES  ****************************
/*
  The "lastSelectedElement" variable is used to store the last element selected.

  This plugin uses the "elementspath" plugin which shows all elements in the DOM
  parent tree relative to the current selection in the editing area.

  When the selection changes, "elementsPathUpdate" is fired,
  we key on this and loop through the elements in the tree checking the classes assigned to each element.

  Three outcomes are possible.

  1) The non-editable class is found:
  Looping stops, the current action is cancelled and the cursor is moved to the previous selection.
  The "selectionChange" hook is fired to set the reverted selection throughout the instance.

  2) The editable class is found during looping, the "in_editable_area" flag is set to true.

  3) Neither the editable or the non-editable classes are found (user clicked outside your main container).
  The "in_editable_area" flag remains set to false.

  If the "in_editable_area" flag is false, the current action is cancelled and the cursor is moved to the previous location.
  The "selectionChange" hook is fired to set the reverted selection throughout the instance.

  If the "in_editable_area" flag is true,
  the "lastSelectedElement" is updated to the currently selected element and the plugin returns true.

---------------
  If you don't want the elements path to be displayed at the bottom of the editor window,
  you can hide it with CSS rather than disabling the "elementspath" plugin.

  The elementspath plugin creates and is left active because we are keying on changes to the path in our plugin.
  #cke_path_content
  {
    visibility: hidden !important;
  }

---------------
  CSS Classes and ID that the plugin keys on. Use defaults or update variables to use your preferred classes and ID:

  var starting_element_id = ID of known editable element that always occurs in the instance.
  Don't use elements like <table>, <tr>, <br /> that don't contain HTML text.
  Default value = cwjdsjcs_editable_id

  var editable_class = class of editable containers.
  Should be applied to all top level elements that contain editable elements.
  Default = cwjdsjcs_editable

  var non_editable_class = class of non-editable elements within editable containers
  Apply to elements where all child elements are non-editable.
  Default = cwjdsjcs_not_editable

*/

//* **************************  END NOTES  ***************************  END NOTES  ****************************


// Register the plugin with the editor.
// http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.plugins.html
CKEDITOR.plugins.add( 'cwjdsjcsconfineselection',
{
  requires : [ 'elementspath' ],

  // The plugin initialization logic goes inside this method.
  // http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.pluginDefinition.html#init
  init: function( editor )
  {
    editor.on( 'instanceReady', function( instance_ready_data )
    {
      // Create variable that will hold the last allowed selection (for use when a non-editable selection is made)
      var lastSelectedElement;
      editor.cwjdsjcs_just_updated = false;

      // This section starts things off right by selecting a known editable element.
      // *** Enter the ID of the element that should have initial focus *** IMPORTANT *** IMPORTANT ***
      var starting_element_id = "cwjdsjcs_editable_id";

      var resInitialRange = new CKEDITOR.dom.range( editor.document );

      resInitialRange.selectNodeContents( editor.document.getById( starting_element_id ) );
      resInitialRange.collapse();

      var selectionObject = new CKEDITOR.dom.selection( editor.document );

      editor.document.focus();
      selectionObject.selectRanges( [ resInitialRange ] );

      var sel = editor.getSelection();
      var firstElement = sel.getStartElement();
      var currentPath = new CKEDITOR.dom.elementPath( firstElement );

      // Set path for known editable element, fire "selectionChange" hook to update selection throughout instance.
      editor._.selectionPreviousPath = currentPath;
      editor.fire( 'selectionChange', { selection : sel, path : currentPath, element : firstElement } );
    }); // *** END - editor.on( 'instanceReady', function( e )


    // When a new element is selected by the user, check if it's ok for them to edit it,
    // if not move cursor back to last know editable selection
    editor.on( 'elementsPathUpdate', function( resPath )
    {
      // When we fire the "selectionChange" hook at the end of this code block, the "elementsPathUpdate" hook fires.
      // No need to check because we just updated the selection, so bypass processing.
      if( editor.cwjdsjcs_just_updated == true )
      {
        editor.cwjdsjcs_just_updated = false;
        return true;
      }

      var elementsList = editor._.elementsPath.list;
      var in_editable_area = false;
      var non_editable_class = "cwjdsjcs_not_editable";
      var editable_class = "cwjdsjcs_editable";

      for(var w=0;w<elementsList.length;w++){
        var currentElement = elementsList[w];

        // Sometimes a non content element is selected, catch them and return selection to editable area.
        if(w == 0)
        {
          // Could change to switch.
          if( currentElement.getName() == "tbody" )
          {
            in_editable_area = false;
            break;
          }

          if( currentElement.getName() == "tr" )
          {
            in_editable_area = false;
            break;
          }
        }

        // If selection is inside a non-editable element, break from loop and reset selection.
        if( currentElement.hasClass(non_editable_class) )
        {
          in_editable_area = false;
          break;
        }

        if( currentElement.hasClass(editable_class) ) {
          in_editable_area = true;
        }
        console.log(currentElement);
        console.log(currentElement.getName());
      }

      // if selection is within an editable element, exit the plugin, otherwise reset selection.
      if( in_editable_area ) {
        lastSelectedElement = elementsList[0];
        return true;
      }

      var resRange = new CKEDITOR.dom.range( editor.document );

      resRange.selectNodeContents( lastSelectedElement );
      resRange.collapse();
      editor.getSelection().selectRanges( [ resRange ] );
      resRange.endContainer.$.scrollIntoView();

      // Open dialog window:
      // It tells user they selected a non-editable area and cursor has been returned to previous selection
//      currentEditorName = editor.name;
//      openResDefaultDialog(currentEditorName);

      try
      {
        var sel = editor.getSelection();
        var firstElement = sel.getStartElement();
        var currentPath = new CKEDITOR.dom.elementPath( firstElement );
        editor.cwjdsjcs_just_updated = true;

        editor._.selectionPreviousPath = currentPath;
        editor.fire( 'selectionChange', { selection : sel, path : currentPath, element : firstElement } );

      }
      catch (e)
      {}
    });
  } // *** END - init: function( editor )
}); // ************************************************************************************* END - CKEDITOR.plugins.add

要测试插件是否已加载,请在实例就绪触发器后添加警报:

    editor.on( 'instanceReady', function( instance_ready_data )
    {
      alert("instanceReady");

要测试选择更改时插件是否被触发,请在 elementsPathUpdate 触发器之后添加警报:

    editor.on( 'elementsPathUpdate', function( resPath )
    {
      alert("elementsPathUpdate");

关于javascript - 如何阻止对 CKEDITOR textarea 中的某些内容进行编辑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11328681/

相关文章:

javascript - 使用 JavaScript 刷新内部页面

javascript - 内容脚本样式表泄漏到页面中

java - ClassLoader类依赖(插件)

plugins - 为 Thunderbird 或 Zarafa 创建自己的插件?

c# 简单的非 xml 配置文件?

Java:可以在属性文件中换行吗?

javascript - 在 Redux-Form 上,我可以在验证之后、提交之前处理值吗?

javascript应用不触发传递给它的数组中的每个索引

plugins - Dynamics CRM 2011 插件检索和检索多个

configuration - 使用 Chef/Puppet 并管理手动更改