Thursday, 19 June 2014

Javascript window resize listeners force you to double check your code

Working to my NextCharts HTML5 library made me to think more defensive when writing Javascript code. NextCharts library is used by NextReports Server inside its Dashboards section. Here, any dashboard can contain a number of charts and widgets.

Any chart / widget has a resize event defined in its code , like :

window.addEventListener('resize', resize, false); 

So, when the browser is resized, all charts and widgets are also resized.

The problems may start to appear when we change between dashboards. Visually I saw, sometimes , that the animation is not working. Looking for Javascript errors, I saw that in some place my canvas element was null. How can it be? I was just doing:

var canvas = document.getElementById(id);

Why is not the element id found?

And then it struck me: The resize event is registered for some charts/widgets and when we change the dashboard those listeners are still active, the browser notifies them about the event, but the components are not found inside the page anymore, so the canvas is null for them.

Because we do not know when to remove the resize listener for a specific component inside dashboard, the solution is to check for canvas null values in our javascript functions:

if (canvas == null) {
      return;
}
This is something you cannot think until you use your Javascript code under a big umbrella.

Friday, 14 February 2014

Get JSON with JQuery as UTF-8

This is how I used JQuery, to read JSON from a url:

$.getJSON('data-html5.json').then( 
    function(data){  
        console.log(data);
        nextChart(data, 'canvas', 'tip');
    },
    function(jqXHR, textStatus, errorThrown) {
        alert("Error: " + textStatus + " errorThrown: " + errorThrown);
    } 
);

But this method does not interpret UTF-8 characters, making your UTF-8 text to look scrambled. The workaround is to use the following:

$.ajax({
    type: "POST",
    url: "data-html5.json",
    contentType: "application/json; charset=utf-8",
    dataType: "json",    
    success: function(data) {
        console.log(data);
        nextChart(data, 'canvas', 'tip');
    },
    error: function(jqXHR, textStatus, errorThrown) {
        alert("Error: " + textStatus + " errorThrown: " + errorThrown);
    }
});  

Thursday, 14 November 2013

HTML Multiple select and Android incompatibilities

Do you have a multiple select on your web site? Then you should see how ugly it looks on Android platform. Not only it looks different, but it also behaves differently.

In Wicket there is a Palette component (two multiple selects) which allows to select some options from a list to another list. You can add / remove selected options using two buttons ">" and "<".


I extended this component with some new buttons ">>" and "<<" to add all and remove all elements.

On Android platform:
  • the multiple select looks like a simple select without any option in it
  • select does not even has an arrow to indicate you are looking at a list
  • even if you make its height bigger you cannot see all the possible options inside a multiple select; (it is just an empty big space!)
  • when you click on it you can select what options you want
  • after selection you can see only the first selected option
Because all of these, there is also no need for "add all" and "remove all" buttons (even if it does the operation, not being able to see what are all options makes it unusable).

When I first re-sized the browser to become with less than 480 px width, I saw the result ok . I just hid "add all" and "remove all" buttons.


But when I looked on Android emulator I saw another story.


First I modified the css to show the two buttons inline.  The re-sized browser looks like:


And then I added the arrow icon by myself (it will have impact only on Android):

.paletteContainer table.palette td.pane select,
.paletteContainer table.palette td.pane select[size="0"],
.paletteContainer table.palette td.pane select[size="1"] {
    background-image: url(data:image/png;base64,R0lGODlhDQAEAIAAAAAAAP8A
/yH5BAEHAAEALAAAAAANAAQAAAILhA+hG5jMDpxvhgIAOw==);
    background-repeat: no-repeat;
    background-position: right center;
    padding-right: 1.8em;
  }

The result was much better:


When you click on select you see Android selection dialog:


After selecting, the first selected option is seen:


Making a Wicket web site to look good on Android phone

I wanted my Wicket application to look good on an Android phone. Delving into this task I found two important things:

In many cases you will not be able to show all the information. For me, it was ok to use css media query to have a different css for Android phone. I had to tweak with fonts size and hide some markups.

Inside my html I added the viewport metadata:

<meta name="viewport" content="width=device-width,initial-scale=1"/>  

and I entered my two style sheets:

<!-- for all screens -->
<link rel="stylesheet" href="css/styles.css" type="text/css" media="screen" />

<!--  for Android phone 480px wide or less -->
<link rel="stylesheet" href="css/min-styles.css" type="text/css" 
      media="only screen and (max-width: 480px)"/>    

All the tweaks were added to min-styles.css file.

Modal Windows are a big pain to use. I had to make them show near the top with fixed position like:
 
 .wicket-modal {
        position: fixed !important;
        top:5% !important;
}

Without this, on Webkit browser if you scroll down to click some link which opens a modal, you even won't be able to see the modal (depends on how much scrolling you need). A modal cannot be dragged independently on screen.  So I guess, if you can avoid modals, then do it. If you cannot avoid them, then keep them as small as possible.

Thursday, 31 October 2013

Take care about your comments format

These days I was tangling with some media query to allow using a different css file in mobile platforms than in desktop ones.

After I set inside my base page the viewport like:
<meta name="viewport" content="width=device-width,initial-scale=1"/>
and adding the two css files:
<link rel="stylesheet" href="css/styles.css" type="text/css" 
      media="screen"/> 
<link rel="stylesheet" href="css/min-styles.css" type="text/css" 
      media="only screen and (max-width: 480px)"/>
I just noticed that my css class  for second file (I had just one class at first for testing) is not loaded.

I put some other classes inside css file and use them inside different places, and they work! But the first did not. I saw that all other classes where used inside basic html pages, while the first was used inside a modal window, and I thought that there is a problem with the modal window and media queries ...

After some time I realized that the problem was generated by a wrong comment inside css file. It was something like:
<!--  phone in portrait mode, or PCs w/Browser windows reduces to 
      480px wide or less -->
And this is a comment format used inside XML files , not CSS! After I used the right format:
/*  phone in portrait mode, or PCs w/Browser windows reduces to 
    480px wide or less */
my first class was loaded.

The lesson learned from this is that always take care about your comments! If you copy them from somewhere else, be sure that the comment tags are suited for your specific file!

Wednesday, 16 October 2013

Eclipse & EGit Frustrations

Sometimes any developer has his moments when a feeling of frustration becomes overwhelming. This just happened to me when trying to create with Eclipse a new project from GitHub and using EGit plugin for synchronization with remote repository.

To create a project from GitHub sources you just have to do the following:
  1. Select "File -> Import"  menu and from there go inside the tree structure to  "Git -> Projects from Git"
  2. Then you have to enter the URI like https://github.com/nextreports/nextreports-engine . Here the first problem arose. I  could not go further because I received an error:
 

I knew I was behind a proxy and that I had it set. So I started to look for what people had to say. I found that you should add .git at the end of the url to work. I tried, but another error:


 I found that other people where successful by using http protocol instead of https. So, using a url like http://github.com/nextreports/nextreports-engine.git showed me the master branch. Hurray, I said!

Wizard from eclipse, after sources download, asked me to create the project. Because I entered a custom path, now I got another error (the following picture was taken from another project, so do not look at the name):


So the wizard is also buggy! OK. I closed the wizard and I created the project from scratch from downloaded sources. After setting build path and making it compile, I tried to use EGit plugin to synchronize with repository. A new error popped-up:

This told me that I could synchronize only with my local repository, but not with the remote git repository because fetch failed. Why? It didn't say.

I felt so frustrated after looking around for hours. Because I really needed to do some work and not just configurations, I gave up and I started to use git commands from command prompt to pull and push my work.

When I had time to investigate further, I started to look again because frustration grew bigger. Project had an Ivy dependency management and Ivy Resolving or Refreshing where not working from Eclipse, letting me no choice just to use ant commands from command prompt. Eclipse started to look just as a simple editor ...  Everything I needed to do requested using command prompt commands.

Looking inside Ivy console, helped me to see a "Connection timeout" for a specific library. This was just our engine library added to maven central repository through sonatype. Library could be accessed with no problem from browser. After another searching time, I just realized the big picture:

Our maven library had an url with https! So retrieving libraries through https did not work, only through http. This made me return to proxy settings and saw that proxy was indeed set, but only for http. So I edited the HTTPS entry and I added the proxy to it:


After that everything started to work:
- creating git project using link with  https
- Eclipse ivy resolving / refreshing
- EGit synchronization with remote git repository

And as a bonus, sometimes a plugin from eclipse could not be installed on my computer. This forced me to add the proxy settings directly to eclipse.ini file (-Dhttp.proxyPort=... -Dhttp.proxyHost=...) I realized that those plugins with https inside their URI were the culprit.

So, just a proxy setting caused so much trouble in so many places inside Eclipse.  Sometimes, solving a problem can take just a second, but only after hours or days of frustration.

Monday, 14 October 2013

Android Issue

Inside any AndroidManifest.xml  file it is possible to add useful meta-data for applications. I could put here basic information like author name, application version and so on.
<meta-data android:name="author" android:value="John Doe" />
<meta-data android:name="serverMinVersion" android:value="6.1.1" />
Inside my application about activity I want to show this info.
ApplicationInfo aInfo = getPackageManager().getApplicationInfo(
                 getPackageName(), PackageManager.GET_META_DATA);
String authorName = aInfo.metaData.getString("author");
String serverMinVersion = aInfo.metaData.getString("serverMinVersion");
// show this info
But something happened after I changed the version through an upgrade.
<meta-data android:name="serverMinVersion" android:value="6.2" />
Suddenly, the version shown inside about info was null.

At first I thought I made a mistype , then that I changed something. But, after a while, I realized that it's not my problem, but an Android bug. I saw that a value like 6.2a is working without a problem. Looking for similarities I found this bug, which tells that getString() method on metaData for something with only numeric values returns always null.

Before finding this bug, it wasn't obvious for me that there is a difference between 6.1.1 and 6.2 . 6.1.1 cannot be considered a number, while 6.2 it is one.

Solution, as told inside the bug link, was to get the value like this:
String serverMinVersion = aInfo.metaData.get("serverMinVersion").toString();
This is just a small bug inside Android beast and by telling that there are three years from reporting it and no one did anything, I can just give a thumb down to Android.