0

I have a custom button added to TinyMCE visual editor. This button wraps any highlighted words in <em> tags with class tle. So, if you highlight term Pulp Fiction and click the button, you will get <em class="tle">Pulp Fiction</em>.

The JS code:

(function() {
    tinymce.PluginManager.add('custom_em', function( editor, url ) {

        editor.on('init', function(e) {
            this.formatter.register('reftitle', {
                inline : 'em',
                classes : 'tle'
            });
        });

        editor.addButton('custom_em', {
            text: 'Title (italic)',
            icon: false,
            onclick : function() {
                var contents = editor.selection.getContent(),
                tags = jQuery(contents).find('em.tle').andSelf();
                if (tags.length) {
                    editor.formatter.remove('reftitle');
                } else {
                    editor.formatter.apply('reftitle', {value: contents});
                }


            }
        });
    });
})(jQuery);

It works great, but it doesn't format any terms that contain any special characters. It only works with characters A-Z and 0-9.

For example, X-Men: Days of Future Past will not work because it contains :. In console, it gives error: Syntax error, unrecognized expression.

Why is it not working properly? Guessing it's an issue with my onclick function. Hoping there is a jQuery or TinyMCE guru here.

Henrik Petterson
  • 6,862
  • 20
  • 71
  • 155
  • Does the problem happen similarly with characters that are often implicitly url- or html-encoded? For example, does it happen with `Test-Movie` the same as `Test_Movie` and `Test & Movie`? I'm wondering if some encoding is happening on the selection which causes it to fail finding it again when trying to apply the formatting. Also, any errors in the console that would be relevant? – trnelson Oct 20 '14 at 14:55
  • @trnelson The button works with "Test-Movie", but not with "Test & Movie". And yes, console gives the following errors for "Test & Movie": Syntax error, unrecognized expression: Test & Movie... – Henrik Petterson Oct 20 '14 at 14:56
  • Oops, sorry, I mistakenly pressed the back button while typing and didn't think my previous comment was posted. It sounds like an html-encoding issue of some sort. You may be able to take advantage of JavaScript's `escape()` function to encode your query before trying to apply the formatting. I think that jQuery does a lot of encoding/decoding behind the scenes. – trnelson Oct 20 '14 at 14:58
  • @trnelson No worries, please delete your first comment. Can you please give me an example of how I can do this using my own code as a reference? – Henrik Petterson Oct 20 '14 at 14:59
  • Try replacing with `editor.formatter.apply('reftitle', {value: encodeURI(contents)});` – Apul Gupta Oct 20 '14 at 15:06
  • I'll try to take a stab at an answer but without a TinyMCE installation, I'd just be guessing. That said, I did want to drop this here. It's a helper function (Accepted Answer on SO) for encoding/decoding HTML the jQuery way: http://stackoverflow.com/a/1219983/638087. That may be of some use to you. – trnelson Oct 20 '14 at 15:10
  • @trnelson I understand. Please feel free to blast and answer and I can test it live. Thank you. – Henrik Petterson Oct 20 '14 at 15:15
  • @ApulGupta I just tried this and it did not work. – Henrik Petterson Oct 20 '14 at 15:18

1 Answers1

1

The issue is at jQuery(contents). This happens because of the dual nature of jQuery (the function itself, not the library):

1) You can pass it a string containing valid HTML and expect it to return a DOM node;

2) You can also pass it a selector ('#div.foo') and expect it to return a list of nodes matching it.

That means somewhere, before applying (1) or (2), this function has to decide what it's dealing with, so it checks if whatever you pass to it looks like a selector. Turns out 'foo: bar' does so it goes through with (2). What happens next is it tries to tokenize the selector and fails.

What you need to do to fix this issue is make sure you use (1), not (2), and you can do that using jQuery.parseHTML so your code should be

tags = jQuery(jQuery.parseHTML(contents)).find('em.tle').andSelf();

The logic after that is a different issue. The final solution is pretty simple actually. Turns out the Formatter class, besides apply and remove, has a toggle method that does exactly what you need, better:

onclick : function() {
    editor.formatter.toggle('reftitle');
}
Sergiu Paraschiv
  • 9,929
  • 5
  • 36
  • 47
  • 1
    Interesting! Just tested it. Replaced the "tags = jQuery..." line with the one you have outlined, it did not work with any terms. Console is not showing any errors either. Any ideas? Is there a typo in your code? Or a different approach to this? – Henrik Petterson Oct 20 '14 at 15:30
  • Thats the logic after. AndSelf will ensure the array has at least one element so the if condition will always be true. – Sergiu Paraschiv Oct 20 '14 at 15:41
  • Do I need to change anything else in my code in order to make it function properly? – Henrik Petterson Oct 20 '14 at 15:43