Monday 26 December 2016

New icons in Apex 5.1

Apex 5.1 ships with a large set of icons. These are contained in a font called Font Apex.
This font contains 1000+ icons. Part of the icons are Font Awesome V4.7 based, others are specifically designed for Apex. The Font Awesome based icons are less bold, as you can see in the menu icons below. Original Font Awesome to the left, Font Apex to the right.


Scaleability

Because the icons are less bold they are more suitable for enlargement. Font Awesome icons look a bit bulky after enlargement, the largest one is 3em:



while Font Apex stays elegant :


Applying Font Apex

You can activate Font Apex in the properties of the theme ( Shared Components > Theme > Specific Theme > Icons ):



The HTML to use Font Apex is exactly the same as with Font Awesome. Font Apex also has the classes .fa and .fa-nameBecause Font Apex is a superset of Font Awesome v4.7 you can toggle between the two font as long as you do not use Font Apex icons.

List of icons

You can find a list of available Icons on this page

There are three categories of icons: 
- Font Awesome based: icons based on Font Awesome 4.7 with the same name
- Apex icons: mostly technical icons
- Emoji's: emoji icons




Friday 23 December 2016

Using APEX_MAIL outside of Apex

Update: This post applies to Oracle schema's that are not assigned to an Apex workspace. When assigned you can use the solution setting the Apex security ID. 

To send mail from your application you can use the package APEX_MAIL. I had created a package to send daily status mails and everything worked fine when called from within the application. So I thought I was almost ready... Then I tried to call the package from SQL Developer :

Error in Send daily mail: ORA-20001: This procedure must be invoked from within an application session.

A Google search quickly revealed the solution. The Apex workspace ID should be set.
Alas, this did not work ( anymore? ).
Update: This solution did not work because the Oracle schema was not asssigned to an Apex workspace.

I did not want to rewrite the logic so I had to figure out a way to call the package from within the Apex context.
It can be done using a public Apex page sending the mail. This page is called from PL/SQL using UTL_HTTP. The use of the page is restricted by using a secret parameter.
Read on to see how it works in detail.

Database

In the database we have a package mail_pck to send the mails. We add the following code to this package:

create or replace package body mail_pck is

  -- autorisation code 
  -- NB do not use special characters for URL's like '?', '&' etc.
  g_aut_code      varchar2(100) := 'secret_string';  
                                  
...

  procedure send_mails_using_apex_mail is
...

  -- return the autorisation code
  function get_aut_code  return varchar2 is
  begin
    return ( g_aut_code ); 
  end;

  -- check the autorisation code
  function check_aut_code ( p_code in varchar2) return boolean is
  begin
    return ( nvl(p_code,'x') = g_aut_code ); 
  end;

  -- calls Apex page from which mail is sent
  procedure batch_send_mails is
    l_url       varchar2(1000) := null;
    l_result    varchar2(4000) := null;
  begin
    l_url    := alg_pck.get_parameter('SERVER_URL')||'/ords/f?p='
                ||alg_pck.get_parameter('APP_ID')
                ||':9000:0::::P9000_CODE:'||get_aut_code;
    l_result := utl_http.request(l_url);
  end;

end mail_pck;


The schema for this package should be granted to execute utl_http.
An ACL should be created to access the Apex server. This ACL should be granted to the schema.

Apex

Create a page in Apex with
Page Number : 9000 ( for this example )
Authentication : Page is public

Create a page item
Name : P9000_CODE
Type: Hidden

Create a branch
This branch fires a redirect when the code is not correct
Name: To login page when code is not valid
Process Point: Before header
Type: Page or URL (Redirect )
Target page: LOGIN_DESKTOP
Condition Type: PL/SQL Expression
PL/SQL Expression: not mail_pck.check_aut_code(:P9000_CODE)


Create a PL/SQL region
This PL/SQL region performs the sending of the mails
Name: Send daily mail
Code:
begin
  mail_pck.send_mails_using_apex_mail;
  sys.htp.p('Mails sent.');
end;
Condition Type: PL/SQL Expression
PL/SQL Expression: mail_pck.check_aut_code(:P9000_CODE)


Happy Apexing!

Thursday 8 December 2016

Automatic resizing of modal dialogs

The modal dialogs are a very nice feature, easy to use and well integrated in the Apex framework. One thing that annoys me is the vertical sizing of the dialog window.
Normally I will create a page as a Modal dialog. When running it I notice that the window is way too high or not high enough. I go back to the builder and enter a number of pixels for the height and look what the result is. I repeat this process a few times until I am satisfied.



When the page is changed this may  change the height of the page, so... :-(.
This is typically one of these boring jobs I like to automate. So I examined the structure of the Apex modal dialog.
One thing that is counter intuitive is that the header of the modal dialog is part of the calling page. Only the red part is generated from the modal dialog page.


The height of the modal window is defined in the calling page. This is the reason why you have to refresh the calling page when you change the height of the modal dialog.

Inside the red square the height is determined by three div elements: dialog header, dialog body and dialog footer.
The JavaScript code below determines the total height of the dialog and sets the height of the determining element on the calling page to this value.

function resize_dialog()
{
  var header  = $('.t-Dialog-header');
  var height  = parseInt($(header).height());  
    
  var body    = $('.t-Dialog-body');
  var padding = parseInt($(body).css('padding-top')) + parseInt($(body).css('padding-bottom'));
  height += padding;
    
  var container = $(body).children().first();
  height   += parseInt($(container).height());  
    
  var footer    = $('.t-Dialog-footer');
  height   += parseInt($(footer).height());  
  console.log('total height = '+ height );

  parent_container = window.parent.$('.ui-dialog-content');
  $(parent_container).height(height);
}


This code can be called in the On page load section of the dialog page.


It is also possible to call the function in a Dynamic Action that changes the height of the dialog content. Two examples of this behavior can be seen in the example page here. You can change the number of rows or number of items and the dialog is resized automatically.

Happy Apexing!