Friday, December 08, 2017

How do I create a responsive Rich Text Editor in Oracle APEX?

I was in a video call this morning with a great customer from England (and by the way, this customer is in the process of transforming the healthcare industry across the UK).  They asked me a very simple question:

How do I create a responsive Rich Text Editor item on a page?

Simple question and answer, right?  Well, you'd be wrong.  While we pride ourselves on the responsive user interfaces that you can easily create with Oracle Application Express (APEX), unfortunately, the item type of Rich Text Editor is not responsive, out of the box.

So - I did what all smart people do, and I reached out to the Oracle APEX Development team, in this case, the ever-intelligent Carsten Czarski.  And in a few minutes, he showed me exactly what I needed to do.

  1. Open up Application Builder, and in Page Designer, edit the page with the Rich Text Editor item.  In my example, my Rich Text Editor page item name is P3_RESUME.
  2. Navigate to the attributes of the Rich Text Editor item, and in the Advanced section, enter the following code in the "JavaScript Initialization Code" attribute:
    function (o) {
        o.width = $("#P3_RESUME").closest(".t-Form-inputContainer").width() - 5;
        o.height = 300;  // Specify your desired item height, in pixels
        return o;
    }
    This code determines the width of the region container of the item, subtracts 5, and returns the object initialized to this size.  This will take care of the Rich Text Editor when the page is initially displayed. But it won't handle the case when the browser is resized. To handle that case, we'll need to add a dynamic action.
  3. Click the Dynamic Actions sub-tab in Page designer (the lightning bolt)
  4. Select Events in the upper-left, right-click your mouse and choose "Create Dynamic Action".
  5. In the attributes, enter "Resize" for Name, and select "Resize" for the Event.
  6. Select the True action of the dynamic action (it should be "Show").  Change the Action to "Execute JavaScript Code".
  7. In the Code attribute, enter the code:
    CKEDITOR.instances.P3_RESUME.resize( $("#P3_RESUME").closest(".t-Form-inputContainer").width() - 5, 300);
    
    This is an absolute reference to the Rich Text Editor item on the page, named P3_RESUME. And like the code before, this will determine what the width is of the container of the item, subtract 5 from it, and invoke the resize() method of the Rich Text Editor (CK Editor) element.
That's all there is to it!



Obviously, this item type (like all others) should be responsive, out of the box.  And Carsten is looking at this for the next version of APEX.  In the meantime, if you're using Universal Theme with Oracle APEX 5.1, all it takes is a tiny amount of JavaScript to get a responsive Rich Text Editor.

3 comments:

Steven Feuerstein said...

I put this to use right away, works great. And just for anyone else who is mostly copying-and-pasting (and doesn't really know much about JS), you can use that single dynamic action for multiple items, as in:

CKEDITOR.instances.P52_QUESTION.resize( $("#P52_QUESTION").closest(".t-Form-inputContainer").width() - 50, 100);
CKEDITOR.instances.P52_ANSWER.resize( $("#P52_ANSWER").closest(".t-Form-inputContainer").width() - 50, 100);

CKEDITOR.instances.P52_CHOICE_1.resize( $("#P52_CHOICE_1").closest(".t-Form-inputContainer").width() - 50, 100);
CKEDITOR.instances.P52_CHOICE_2.resize( $("#P52_CHOICE_2").closest(".t-Form-inputContainer").width() - 50, 100);
CKEDITOR.instances.P52_CHOICE_3.resize( $("#P52_CHOICE_3").closest(".t-Form-inputContainer").width() - 50, 100);
CKEDITOR.instances.P52_CHOICE_4.resize( $("#P52_CHOICE_4").closest(".t-Form-inputContainer").width() - 50, 100);
CKEDITOR.instances.P52_CHOICE_5.resize( $("#P52_CHOICE_5").closest(".t-Form-inputContainer").width() - 50, 100);

Maxime Tremblay said...

Hello Joel

I really like the idea! Couple thing I would add.
1. Check if the CKEDITOR library exists, just in case the rich text item is in read only. Otherwise the resize action would fail.
2. Replace the hardcoded item name.

Here's what I came up with.

//make sure that the object is defined (readonly CKEditor won't load the library)
if (CKEDITOR){
//for all CKEditor items
for (var i in CKEDITOR.instances) {
(function(i){
//current CKEditor item
var l_editor = CKEDITOR.instances[i],
l_container = $("#" + l_editor.name).closest(".t-Form-inputContainer");

//Set initial width/height
l_editor.on("instanceReady", function(event){
//console.log('instance ready: ' + l_editor.name);

var l_width = l_container.width() - 5,
l_height = 300;

l_editor.resize(l_width, l_height);
});

//Handle page resize
//not using apexwindowresized because of the delay/debounce
$( window ).resize(function() {
var l_width = l_container.width() - 5,
l_height = 300;

l_editor.resize(l_width, l_height);
});
})(i);
}
}


It could be copied in a Page Load dynamic action on page zero to affect all rich text items of an application or wrapped in a jQuery on document ready and included in the application as a file on it's own.

Stefan Dobre said...

If however you don't want to use any JS, here is my CSS hack:

Add 'stretch-CKE' to CSS Classes under Appearance to all editors you wish to be responsive,
and the following inline CSS to your page (or global stylesheet):

.stretch-CKE > div.t-Form-inputContainer > div.t-Form-itemWrapper > div{
width: 100%;
}

.stretch-CKE > div.t-Form-inputContainer > div.t-Form-itemWrapper > div > div{
width: initial !important;
}

-------------

or if you only want to change one editor and know its name:

#ITEMNAME_DISPLAY{
width: 100%;
}
#cke_ITEMNAME{
width: initial !important;
}