Friday, February 24, 2017

How to create simple local web server for APEX static files

Today I've run into a problem that happens to me quite often. I've started a new project at the new client and one of the first things that I've had to do is to modify Universal Theme to meet their corporate design. They had simple APEX architecture with the EPG and without any custom CSS or JS in their apps.

At first, I thought that I would have to do some minor changes in CSS so I've started to use Custom CSS property in Theme Roller. It's great tool, but as I had to do more and more changes it was just too slow.

So I've asked them to provide me with some Web repository where I can easily put and change my files. Because this is a quite big company (actually a bank) with very strict security policies I knew that this would take a too looooong time. So I've started to look for an alternative.

Off course, my first thought was a great tool named APEX Front End Boost (if you don't know it, check it out), but again, because strict security policies, I wasn't been able to install it on the PC that I was working on. The good thing was that I had Node.js already installed there.

So I've googled around for other solutions, but almost every solution was starting like this:
npm install ...
and it was a bummer because I couldn't install anything from npm.

So I've decided to build my own solution. I thought, I'm not a Node.js developer but I know JavaScript so it shouldn't be too hard...and it wasn't.

I've found one simple server script and added some additional stuff like Access-Control-Allow-Origin and Content-Type headers:
var fs = require('fs');  
var path = require('path');  
var http = require('http');
var staticBasePath = '.';

var staticServe = function(req, res) {  
    var fileLoc = path.resolve(staticBasePath);
    fileLoc = path.join(fileLoc, req.url);

    fs.readFile(fileLoc, function(err, data) {
        if (err) {
            res.writeHead(404, 'Not Found');
            res.write('404: File Not Found!');
            return res.end();
        }
  
  var vExt = req.url.split('.').pop(), vContType;
  switch(vExt) {
   case 'css':
    vContType = 'text/css';
    break;
   case 'js':
    vContType = 'text/javascript';
    break;
   case 'png':
    vContType = 'image/png';
    break;    
   default:
    vContType = 'text/plain';
  } 

  res.setHeader('Content-Type', vContType);
  // Chrome Fix
  res.setHeader('Access-Control-Allow-Origin', '*');
        res.statusCode = 200;
        res.write(data);
        return res.end();
    });
};

var httpServer = http.createServer(staticServe);

httpServer.listen(8085); 
...started it:
node node_server.js
..and voila! I had my static file server running on localhost:8085 (change the port number if you already have something running on 8085) and I could access files through URL like this http://localhost:8085/custom_theme/custom.css (where custom_theme is directory where node_server.js is located).

The next goal was that other developers don't have any problems with the application runtime while I'm doing my CSS changes. So at first, I've created one application item F_THEME_PATH



and application computation (after authentication) to populate it in developement environment (with build option included for developement only)


and the other application computation to populate it on production and test environments which always returns path to workspace images (also defined by build option):

return '&WORKSPACE_IMAGES.custom_theme/';

The idea is - if I'm logged in take files from my local server and for other users take files from APEX workspace files. On test and production evnironments always take files from APEX workspace files.

Because there's a great feature to upload zip file with directory structure to APEX workspace files it was really easy to refresh new version of my files when I was sattisfied with my modifications.  

The last thing was to add reference to my files. You can do this in several places in APEX. I've decided to do it in user interface properties:





Enjoy!

Tested on APEX 5.1.0.00.45 and Node 5.2.0

Tuesday, February 7, 2017

APEX 5.1: Translate HTML5 Client-Side Validation Messages

You may know that in APEX 5.1 there are some new functionalities regarding client-side messaging - for example, the capability to display success or error messages without a full page reload or new JS API for handling client-side messages. There are also enabled HTML5 Form Validations, so you may saw something like this in your apps:



The problem that I had is that the user wanted to translate those messages to the other language (in my case Croatian). I thought - no problem. I'll find those messages in the APEX messages dictionary and translate them to the Croatian. After some exploring I found out that those messages are actually browser depended and you can't translate them (the only option is to install browser in different language).

Fortunately, the APEX development team has thought about this and you can override those messages by defining custom attribute named data-valid-message under the item's Custom Attributes property:



And now the form should look like this:


If you don't want to do this for each and every item in your app you can create On Load Dynamic Action on Global Page (page 0) that looks like this:


which will add this attribute to all required fields.

You can read more about the data-valid-message attribute in apex.item documentation.

Enjoy!

Tested on APEX 5.1.0.00.45