Table, Overlay and Event

Think big, Act small! Yep, It’s typical me. I was conceiving of some fancy app like Google Doc, whereas I ended up with a tiny piece like the following.

 

How to play with it? Well, clicking on one table cell starts drawing the overlay. Moving the cursor around moves and expands the overlay. Clicking once again ends the drawing process. The final overlay is a large rectangle which covers an area formed by the starting cell and the ending cell. Actually, the starting table cell and the ending table cells form two corners of the overlay. What I have learned from making this little app?

  • How to layout overlay?

Apparently, it should be positioned absolutely. And the stack order of it must be large enough so that it’s displayed in the front.

  • How to detect the table cell under mouse?

If the center of a table cell is clicked, the target or srcElement of the event is exactly the cell element under mouse. However, if the border is clicked, the cell under mouse have to be calculated out via the mouse position.

 

  • How to forward mouse event through layers?

The key-point of forwarding the mouse event from the overlay to the underline table is to re-dispatch the mouse event on the table. At re-dispatching, the location of the mouse cursor must be preserved, so that this location could be used later on to calculate the table cell under mouse.

Be Careful with Prototype Property

Today, I have spent nearly half a day wrestling with a bug. Eventually, it turned out that the root cause is the misuse of prototype property. Prototype property is like a pitfall for someone like me who comes from the object-oriented world. In Java, for instance, it’s quite normal to define a common property in the base class, so that all the derived classes contain this property. Hence, it’s no surprise I wrote down some silly codes like below:

Everything looks fine! ChildModel is a constructor function. Its prototype is a BaseModel object, which owns a property map. In the beginning, an instance of ChildModel is created and assigned to child. It inserts a key-value pair ‘salary : 2000’ into map. Subsequently, it restores map to an empty object. And then, another instance of ChildModel is created and assigned to child. I assumed that the map property of this newly created instance is clean. Isn’t it?

Oh, no. It still holds the key-value pair ‘salary : 2000’. Haven’t I already cleaned it? The pity is I didn’t. Let’s take a closer look at insert and teardown function and find out why. In the insert function, child manipulates the prototype property map directly. Hence, the key-value pair ‘salary : 2000’ is stored in the prototype property map.

However, in the teardown function, child restores map to a clean object. Doesn’t it? What, it doesn’t touch the prototype property map, instead, in creates a new property map on itself. And the newly added property overrides the prototype property.

Oh, I see. So the second created instance of ChildModel still inherits from prototype object. And the prototype object still contains the key-value pair ‘salary : 2000’.

JSLint: Errors and Solutions

JSLint is cool! It helps us identify a number of hidden bugs in our codes. However, JSLint only represents a type of coding style, which you may not totally agree with. For example, JSLint doesn’t expect a function name to start with uppercase; it prefers dot notation to subscript notation. In summary, there are times you would like to suppress JSLint warnings. Following is a guidance of JSLint warnings and possible solutions.

[E] Missing ‘use strict’ statement.

[S] “use strict”;  

Enable strict mode by placing “use strict”; at the top of a script. To learn more about script mode, please read http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/.

[E] ‘$’ was used before it was defined.

[S] /*global $: false */   

The JavaScript file is dependent on global variables defined elsewhere. For instance, it depends on the jQuery functions defined in the jquery.js. To tell JSLint that variables used in this file are defined in other files, use /*global */ directive. Separate the global variable names by comma.

[E] ‘window’ was used before it was defined.

[S] /*jslint browser: true */   

To use the global properties provided by web browser, such as window and document, add the browser directive.

[E] A constructor name ‘XXX’ should start with an uppercase letter.

      Missing ‘new’.

[S] /*jslint newcap: true */

JSLint enforces that the constructor function names be started with uppercase, while the normal function names be started with lowercase. To ignore this convention, add the newcap directive.

[E] ‘[XXX]’ is better written in dot notation.

[S] /*jslint sub: true */

JSLint prefers dot notation to subscript notation, i.e. user.name is better than user[‘name’]. To allow subscript notation, add the sub directive.

[E] Expected exactly one space between ‘function’ and ‘(‘.

[S] /*jslint white: true */

As far as anonymous function is concerned, JSLint prefers one space between keyword function and the parameter bracket. To mute this warning, add the white directive.

[E] Move the invocation into the parens that contain the function.

[S] }());

End the self-executing anonymous function as (function(){…}()); instead of (function(){…})();.

[E] Weird assignment.

[S] Convert the subscript notation to dot notation.

No specific directive could be used to suppress this warning. My experience is simply converting the subscript notation on the line to dot notation. In this way, the warning is gone.

JSONP : Cross-Domain Ajax Request

  • What’s JSONP

JSONP is JSON with padding. It’s an artful means to bypass the same origin policy restriction, which is imposed by web browsers. Web browser prohibits scripts running on a domain requesting data from a server in a different domain. However, an exception is the HTML <script> element. Hence, JSONP makes use of it and dynamically injects a script element into HTML DOM. P actually stands for a callback function which is executed at response time.

  • JSONP via jQuery

jQuery allows cross-domain Ajax request via JSONP. An example is shown below:

What is done after launching this request? Firstly, the complete request URL looks like “url?_callback=XXX“. The url, of course, is the url specified in the url property. The query parameter “?_callback=XXX“, however, is appended by jQuery. Actually, the appendix reveals the nature of JSONP request, JSON with padding. JSONP response looks like below, a function wraps the JSON data:

However, if the server actually doesn’t support JSONP, probably, a JSON is sent back directly. In this case, the browser throws an exception “Uncaught SyntaxError: Unexpected token:“, warning that it’s invalid JavaScript:

Talking about the callback function, what does the callback look like in jQuery? Well, it’s not what we specify in the success or error property. It’s actually dynamically created by jQuery. The callback function is installed on window and its responsibility is simple: extracting the JSON data.

As what I have mentioned before, to launch a cross-domain Ajax request, a script element is dynamically injected into HTML DOM. How does jQuery do it? Firstly, jQuery creates a script element, the src property of which links to the complete URL “url?_callback=XXX“.

And then the script element is injected in to head. At meantime, the script’s onload event is listened. After script is entirely loaded, the loaded JavaScript is evaluated and executed, which basically invokes the callback function.

And we already know that the callback function extracts the JSON data. And then, the JSON data is really passed to the success callback function, which we specify in the success property.

After we know the life cycle of JSONP request via jQuery, let’s take a closer look at the ajax parameters. Firstly, dataType is jsonp, indicating it’s a cross-domain Ajax request. Then, you either explicitly set crossDomain to true or ignore this property. If you ignore it, jQuery does the work for you. It checks the Ajax request url, if it is in another domain, jQuery set crossDomain to true. However, DO NOT set crossDomain to false. See how jQuery checks request url to determine whether it’s a cross-domain request.

Out of security concerns, jQuery only allows cross-domain GET request. GET request ensures user doesn’t post malicious data to the server. Once again, you don’t have to explicitly set it because jQuery changes the type to GET on a cross-domain Ajax request.

Cross-domain Ajax request must be asynchronous whether async is set true or false. By default, jQuery append a query parameter “?callback=XXX” to the end of the URL to specify the callback. However, you are able to change the parameter name to whatever by specifying jsonp property. In my example, the appendix looks like “?_callback=XXX“.

JavaScript Private Methods

People share some consensus on what’s the best way in defining a public method for a JavaScript Class, that is:

The biggest advantage of defining methods via prototype rather than straight inside the constructor is that a single function object is shared among all the class instances. 

By contrast, there is no such rule of thumb on how to define private methods. A simple and probably most prevalent way is declaring the private functions using var inside constructor, for example:

However, a major drawback of this solution is that the public methods which make use of the private methods must be defined in the same scope as that of private methods. That is these public methods have to be defined inside constructor too. As a result, each class instance has a respective copy of these function objects. 

How to avoid the redundancy? Self-executing anonymous function comes to help.

Self-executing anonymous function creates a function-level scope, which is a perfect place to wrap private methods:

See it! By defining privateMethod inside the self-executing anonymous function, we are able to isolate it from global scope. That is privateMethod is not accessible outside the function. Yet, it’s exposed to publicMethod because publicMethod is defined in the same function-level scope. Additionally, publicMethod is defined via prototype which ensures that all the instances of TestClass share a single function object.

Minify JavaScript via UglifyJS

UglifyJS is a JavaScript minifying tool, which runs on NodeJS. Compared with other popular JavaScript minifiers, such as YUI Compressor and Google Closure, a remarkable advantage of using UglifyJS is that it’s available as a native command. To utilize UglifyJS, we need to install NodeJS first and then the UglifyJS module.

Here is the guideline on installing NodeJS https://github.com/joyent/node/wiki/Installation. After successful installation, node server starts running.

Then, install UglifyJS module https://github.com/mishoo/UglifyJS#Install on the node server. After adding the UglifyJS path into PATH, we are able to use it via command prompt:

$ uglifyjs -nc -o [output js] [input js]

Extremely easy, isn’t it? Following is a small test comparing the compressing efficiency of different minifiers:

 

Original

Uglify

Closure

YUI Compressor

size

193.5 KB

62.3 KB

61.3 KB

64.4 KB

 

Enable vs Disable – jQuery Mobile

How to enable and disable various components in jQuery Mobile? Following are my tips.

  • Button

To disable a button, simply add the ‘disabled‘ attribute to it:

Or you’d like to manipulate the button component via Javascript:

The same applies to a submit button. Adding the ‘disabled‘ attribute to the submit button disables it.

Or we’re able to manipulate the submit button via Javascript:

As far as link button is concerned, since anchors don’t natively have any disabled state, jQuery Mobile group decides not to support disable and enable anchors like buttons. Therefore, we have to apply ‘ui-disabled’ class to the anchor to achieve the same effect.

Here’s how to do via Javascript:

  • Form 

It’s extremely easy to disable form components by just adding ‘disabled‘ attribute to them.

The display looks like below:

To implement it via Javascript:

Or we’re able to disable the entire form by adding ‘ui-disabled‘ class to it:

Through this way, the labels inside the form are dimmed too.