12
votes

Here is the problem demonstration

You can try it here: http://fiddle.tinymce.com/SLcaab

This is TinyMCE default configuration

  • less all the plugins
  • with extended_valid_elements: "span"

1 - Open the Html Source Editor

2 - Paste this html into the Html Source Editor:

<p><span>Hello</span></p>
<p><a href="http://www.google.com">Google 1</a></p>
<p><a href="http://www.google.com">Google 2</a></p>

3 - Click update in the Html Source Editor to paste the html in the editor

4 - Remember there is a span around 'Hello'.

5 - Place your cursor just before Google 2 and press backspace (the two links should merge inside the same paragraph element).

6 - Look at the resulting html using the Html Source Editor.

Result (problem): No more span in the html document even though we added 'span' to the extended_valid_elements in the TinyMCE settings.

Note: I removed all the plugins to make sure the problem is at the core of TinyMCE.

Edit 1 - I also tried: valid_children : "+p[span]" - still does not work

Edit 2: Only reproduced on WebKit (OK on Firefox and IE)

9
works in this fiddle iwth content already set, maybe the span is getting lost when pastedThariama
@Thariama What do you mean "with content already set"? Pasting is not the problem since, if you reopen the Html Source Editor after clicking the update button inside the Html Source Editor (step 3), the span is still there.W3Max
contetn alread set means it works using afiddle with the content placed in the init textareaThariama
@Thariama I get it but, I'm pretty sure it only works because you tested it with a non WebKit browser, or not on Windows? See Edit 2. Thanks for your feedback.W3Max
yes, i tested this with a non-webkit browser/Windows 7Thariama

9 Answers

18
votes

Insert extended_valid_elements : 'span' into tinymce.init:

tinymce.init({
    selector: 'textarea.tinymce',
    extended_valid_elements: 'span',
    //other options
});
11
votes

I have the same problem and I find solutions. Tiny MCE deleted SPAN tag without any arrtibute. Try us span with class or another attrib. for example:

<h3><span class="emptyClass">text</span></h3>

In TinyMCE 4+ this method good work.

2
votes

Tinymce remove span tag without any attribute. We can use span with any attribute so that it is not removed.

e.g <span class="my-class">Mahen</span>
1
votes

Are you running the newest version of TinyMCE? I had the opposite problem - new versions of TinyMCE would add in unwanted span elements. Downgrading to v3.2.7 fixed the issue for me, that might also work for you if you are willing to use an old version.

Similar bugs have been reported, see the following link for bugs filtered on "span" element: http://www.tinymce.com/develop/bugtracker_bugs.php#!order=desc&column=number&filter=span&status=open,verified&type=bug

1
votes

Try this for 3.5.8:

  1. Replace cleanupStylesWhenDeleting in tiny_mce_src.js (line 1121) with this::

     function cleanupStylesWhenDeleting() {
            function removeMergedFormatSpans(isDelete) {
                    var rng, blockElm, wrapperElm, bookmark, container, offset, elm;
                    function isAtStartOrEndOfElm() {
                            if (container.nodeType == 3) {
                                    if (isDelete && offset == container.length) {
                                            return true;
                                    }
    
                                    if (!isDelete && offset === 0) {
                                            return true;
                                    }
                            }
                    }
    
                    rng = selection.getRng();
                    var tmpRng = [rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset];
    
                    if (!rng.collapsed) {
                            isDelete = true;
                    }
    
                    container = rng[(isDelete ? 'start' : 'end') + 'Container'];
                    offset = rng[(isDelete ? 'start' : 'end') + 'Offset'];
    
                    if (container.nodeType == 3) {
                            blockElm = dom.getParent(rng.startContainer, dom.isBlock);
    
                            // On delete clone the root span of the next block element
                            if (isDelete) {
                                    blockElm = dom.getNext(blockElm, dom.isBlock);
                            }
    
                            if (blockElm && (isAtStartOrEndOfElm() || !rng.collapsed)) {
                                    // Wrap children of block in a EM and let WebKit stick is
                                    // runtime styles junk into that EM
                                    wrapperElm = dom.create('em', {'id': '__mceDel'});
    
                                    each(tinymce.grep(blockElm.childNodes), function(node) {
                                            wrapperElm.appendChild(node);
                                    });
    
           blockElm.appendChild(wrapperElm);
                            }
                    }
    
                    // Do the backspace/delete action
                    rng = dom.createRng();
                    rng.setStart(tmpRng[0], tmpRng[1]);
                    rng.setEnd(tmpRng[2], tmpRng[3]);
                    selection.setRng(rng);
                    editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null);
    
                    // Remove temp wrapper element
                    if (wrapperElm) {
                            bookmark = selection.getBookmark();
    
                            while (elm = dom.get('__mceDel')) {
                                    dom.remove(elm, true);
                            }
    
                            selection.moveToBookmark(bookmark);
                    }
            }
    
    
                editor.onKeyDown.add(function(editor, e) {
                    var isDelete;
    
                    isDelete = e.keyCode == DELETE;
                    if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
                            e.preventDefault();
                            removeMergedFormatSpans(isDelete);
                    }
            });
    
            editor.addCommand('Delete', function() {removeMergedFormatSpans();});
    };
    
  2. put an external link to tiny_mce_src.js in your html below the tiny_mce.js

1
votes

It's possible to use the work around by writing it as a JavaScript script which prevents WYSIWIG from stripping empty tags. Here my issue was with including Font Awesome icons which use empty <i> or <span> tags.

<script>document.write('<a href="https://www.facebook.com" target="_blank"><i class="fa fa-facebook"></i></a>');</script>
1
votes

In the Tinymce plugin parameters enable: Use Joomla Text Filter.

Be sure your user group have set "No filtered" Option in global config > text filters.

1
votes

Came across this question and was not happy with all the provided answers.

We do need to update wordpress at some point so changing core files is not an option. Adding attributes to elements just to fix a tinyMCE behaviour also doesn't seem to be the right thing.

With the following hook in the functions.php file tinyMCE will no longer remove empty <span></span> tags.

function tinyMCEoptions($options) {
    // $options is the existing array of options for TinyMCE
    // We simply add a new array element where the name is the name
    // of the TinyMCE configuration setting.  The value of the array
    // object is the value to be used in the TinyMCE config.

    $options['extended_valid_elements'] = 'span';
    return $options;
}
add_filter('tiny_mce_before_init', 'tinyMCEoptions');
1
votes

I was having same issue. empty SPAN tags are being removed. The solution i found is

verify_html: false,