Wednesday, April 2, 2014

Integrating Ext JS 4 and the TinyMCE 4 Rich Text WYSIWYG Editor

TinyMCE is generally considered to be one of the best WYSIWYG browser-based editors that’s currently available. Not only does it have a ton of native features, but it also has an extensible plugin architecture that enables developers to add additional functionality with relative. One of it’s best features is the ability for a user to expand the editor to full-screen, thereby enabling a much better user experience. It also has a copy/paste plugin that can filter out nasty extraneous Microsoft Word markup.

TinyMCE is open-source and has LGPL and Commercial licenses available.

Making the class a lot more developer-friendly by adding config attributes to load plugins and automatically instantiate associated buttons

Added ICE version control plugin support (depicted above)

Automatically load TinyMCE from the CDN if not present

Added autoFocus param to prevent automatic focus on instantiation

Added dynamic show/hide of header & footer on focus / blur

We also created a custom a Sencha Architect user extension to support it, as well as bundled all of the source code into an Ext JS 4 “package” for easy deployment to your Sencha Cmd-based apps.

A few geeky technical points:

In order for a Sencha Architect user extension to operate properly, the Ext class must not be reliant on external javascripts. Therefore, we threw a little kludge into our codebase that “tricks” Architect into thinking that we’re instantiating a simple textarea:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

// architect design canvas runs pages with

// a url starting with "ionp"

if(location.href.indexOf('ionp') == 0) {

// kludge for sencha architect canvas

Ext.define('Ext.ux.form.TinyMceTextArea', {

extend: 'Ext.form.field.TextArea',

alias: 'widget.tinymce'

});

} else{

// actually load the class

Ext.define('Ext.ux.form.TinyMceTextArea', {

extend: 'Ext.form.field.TextArea',

alias: 'widget.tinymce'

// define the "guts" of the class here

});

}

In order to make the component more “developer-friendly”, we used Ext.loader.loadScript() to load the TinyMCE and ice plugin scripts automatically. Note that ICE requires jQuery (for now):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

if(!window['tinymce']) {

Ext.Loader.loadScript({

url: '//tinymce.cachefly.net/4.0/tinymce.min.js',

onLoad: function() {

if(window.loadIce) {

Ext.Loader.loadScript({

url: '//code.jquery.com/jquery-1.9.1.min.js',

onLoad: function() {

Ext.Loader.loadScript({

url: '//code.jquery.com/jquery-migrate-1.0.0.js'

});

}

});

Ext.Loader.loadScript({

url: 'packages/TinyMCE/resources/ice/ice-master.min.js'

});

Ext.Loader.loadScript({

url: 'packages/TinyMCE/resources/tinymce/plugins/ice/plugin.js'

});

}

},

scope: this

});

}

And finally, we packaged everything (including the Sencha Architect plugin) into a Sencha package, which enables you to combine your component’s source code, related design assets, and (optionally) Sencha Architect plugin into neatly organized folder structure. Note that in the following screenshot, you can configure the TinyMCE editor plugins and other attributes by filling out a simple configuration form.