10/21/2014

[ExtJS] Remove Fake Path in File Field Across Browsers

Here's an example for file uploader with Ext JS. Whenever users pick a file, the file field will fire a change event with the arguments (field, value).
Ext.create('Ext.form.Panel', {
    title: 'Upload a Photo',
    width: 400,
    bodyPadding: 10,
    frame: true,
    renderTo: Ext.getBody(),
    items: [{
        xtype: 'filefield',
        listeners: {
            change: function(field, value) {
                console.log('value', value);
            }
        }
    }]
});
According to the document, the getValue method will return a value that is browser-dependent; some have just the file name, some have a full path, some use a fake path.
For example, in Chrome, the output in the snippet above is:
value C:\fakepath\myfile.txt 
The same code in Firefox will print:
value myfile.txt 
How if we just get want to get the file name instead of the fake path across browsers? That is, we intend to have the following output in all browsers.
value myfile.txt 
All you have to do is just override the filefield class with the following code.
In Ext JS 5,
Ext.define('Ext.enhance.form.field.File', {
    override: 'Ext.form.field.File',     
    onFileChange: function(button, e, value) {
        this.duringFileSelect = true;
        Ext.form.field.File.superclass.setValue.call(this, value.replace(/^.*(\\|\/|\:)/, ''));
        delete this.duringFileSelect;
    }   
});
In Ext JS 4,
Ext.define('Ext.enhance.form.field.File', {
    override: 'Ext.form.field.File',
    onFileChange: function() {
        this.lastValue = null;
        Ext.form.field.File.superclass.setValue.call(this, this.fileInputEl.dom.value.replace(/^.*(\\|\/|\:)/, ''));
   }
});
Please use Chrome to test this overriding in the fiddle.

10/19/2014

[JavaScript] function scope and block scope

In many languages such as C, C++, and Java, the scope is defined by a block. In the following Java example, the variable x in the inner scope is not accessible by outer scope.
for(int i=0;i<10;++i) {
    int x = 1;
}
System.out.println(x); // error
However, in Javascript, scope is defined by a function.
In the following sample, variable x is defined in the loop block which doesn't create a new scope while variable y is defined in a function which create a new scope. So, The foo function is in inner scope and global window is in outer scope.
Since variable x is in the outer scope, the function foo is able to access it. And variable y is in the inner scope, we can't access it in outer scope (window).
var i;
for(i = 0; i < 10; ++i) {
  var x = 1;
}

// function will create a new scope   
function foo() {
  var y = 1;
  x++;
}

console.log('x', x); // 1
foo();
console.log('x', x); // 2
console.log('y', y); // Uncaught ReferenceError: y is not defined

10/16/2014

[ExtJS 5] Migrate from ComponentColumn to WidgetColumn

In Ext 4, we use componentcolumn to render Ext component in a grid cell.
{
  dataIndex: 'age',
  xtype: 'componentcolumn',
  renderer: function(value, m, record) {
    if (value < 30) {
      return {
        xtype: 'myWidget1';
      };
    } else {
      return {
        xtype: 'myWidget2';
      };
    }
  }
}
In Ext 5, the built-in widgetcolumn have the same ability to do so. But the widgetcolumn have better rendering performance.
{
  xtype: 'widgetcolumn',
  widget: {
    xtype: 'container',
  },
  onWidgetAttach: function(widget, record) {
    var items = [];
    if (record.get('age') < 30) {
      items.push({
        xtype: 'myWidget1'
      })
    } else {
      items.push({
        xtype: 'myWidget2'
      })
    }  
    widget.removeAll();
    widget.add(items);
  }
}
Note that onWidgetAttach() is a public but not documented method.

10/10/2014

[Javascript] Event Bubbling and Capturing Propagating Order

Problem

We have three elements in the DOM shown below. When users click on the element3, all of elements' click handler will be executed. But what's the order of executing handler?
<div class="element1">element1
    <div class="element2">element2
        <div class="element3">element3</div>
    </div>     
</div>

The W3C Event Bubbling and Capturing Propagating Order

According to W3C standard, there are two major phases for propagating event object.
Capturing phase:
Firstly, The event object will propagate through the target's ancestors from the Window to the target's parent (Note that target in this case is element3.)
Bubbling phase:
Then event object propagates through the target's ancestors in reverse order, starting with the target's parent and ending with the Window.
Event Bubbling and Capturing Propagating Order
Event Bubbling and Capturing Propagating Order
So let's add some event listeners to print out the propagating order of event object. Before that, let's see the arguements of addEventListener.
/**
  * @param {String} type The event type
  * @param {Function} listener The event handler
  * @param {Boolean} useCapture If True, use capturing. Otherwise, use bubbling.
  */
  element.addEventListener(type, listener[, useCapture]);
The following code make all elements register a click event for both of bubbling and capturing. Note that registering an event for the same listener doesn't affect the order of event object propagating.
var element1 = document.getElementsByClassName('element1')[0],
    element2 = document.getElementsByClassName('element2')[0],
    element3 = document.getElementsByClassName('element3')[0],
    foo = function(e) { console.log(this.className); };

element1.addEventListener('click', foo); // bubbling
element1.addEventListener('click', foo, true); // capturing
element2.addEventListener('click', foo);
element2.addEventListener('click', foo, true);
element3.addEventListener('click', foo);
element3.addEventListener('click', foo, true);
When you click element3, it will show
element1
element2
element3
element3
element2
element1 
As we expected, the event object will first propagate in capturing phase (top-down) and  then bubbling phase (bottom-up).
By the way, you can stop the propagation by calling e.stopPropagation().
var stop = function(e) { 
    console.log('stop', this.className); 
    e.stopPropagation();
};

element1.addEventListener('click', foo);
element1.addEventListener('click', foo, true); 
element2.addEventListener('click', stop); // Change handler to "stop"
element2.addEventListener('click', foo, true);
element3.addEventListener('click', foo);
element3.addEventListener('click', foo, true);
The output
element1
element2
element3 
element3
stop element2 
The Playground in JS fiddle.

10/09/2014

[ExtJS] Add Custom CSS Class to Grid Cell

You can make Ext JS 5 gird cell more pretty by applying twitter bootstrap.css to grid cell. It look like:

All you have to do is override the renderer function which returns a span element with bootstrap's label css class.
{
  header: 'Status',
  dataIndex: 'status',
  width: 100,
  renderer: function(value, meta, record) {
    var cls;
    if (value === 'Success') {
      cls = 'label label-success';
    } else if (value === 'Failure') {
      cls = 'label label-important';
    } else if (value === 'Processing') {
      cls = 'label label-warning';
    }
    return Ext.String.format('<span class="{0}">{1}</span>', cls, value);
  }
}
The code above is tested with Ext JS 5.0.1.

9/28/2014

[gulp] Minify Javascript Files and Add License Notice at Head

Suppose we have source file named "myApp.js" like
var myApp = (function(){
   var x = 1;
})();
We'd like to add license notice and build time at the head of minified file (i.e., "myApp-1.0.min.js") like
/**
 * License Notice
 * Version: 1.0
 * Build: Sun, 28 Sep 2014 02:41:31 GMT
 */
 var myApp=(function(){var x=1;})();
In this situation, we can use gulp to automate the process of minifying Javascript files.
1) Create 'LICENSE' file in project. Note that version and build time are variables which will be replaced when we run gulp task.
/**
 * License Notice
 * Version: <%= version %> 
 * Build: <%= build %>
 */
2) Create 'VERSION' file in the project like
1.0
3) Create gulpfile.js in the project.
var gulp = require('gulp'),
    uglify = require("gulp-uglify"),
    rename = require("gulp-rename"),
    fs = require('fs'),
    header = require("gulp-header");

var getLicense = function() {
    return '' + fs.readFileSync('LICENSE');
};
var getVersion = function() {
    return fs.readFileSync('VERSION');
};

gulp.task('minify-js', function() {
    var version = getVersion(),
        proudctionName = 'myApp-' + version + '.min.js',
        dest = './dist',
        src = './myApp.js';

    gulp.src(src)
        .pipe(rename(proudctionName))
        .pipe(uglify())
        .pipe(header(getLicense(), {
            version: version,
            build: (new Date()).toUTCString()
        }))
        .pipe(gulp.dest(dest));
});

4) After running the gulp task, the minified file will be at ./dist/myApp-1.0.min.js
gulp minify-js
In case you haven't installed gulp, here is quick tips to setup.
1) Install nodeJS
2) Install gulp, the streaming build system.
$ npm install -g gulp
$ npm install —-save-dev gulp
3) Install gulp-uglify, gulp-rename, and gulp-header
$ npm install --save-dev gulp-uglify
$ npm install --save-dev gulp-rename
$ npm install --save-dev gulp-header
This tutorial is based on this github project https://github.com/cwtuan/Locale.js. You can fork it to test if your setup work.

6/06/2014

“javascript:void(0)” Fires window.onbeforeunload in IE

When Building a single page web application, we frequently provide a link as a trigger to run JavaScript.
 <a href = "javascript: void(0);" onclick = "alert('hello');" >Link</a>
When user clicks on the link, IE will  fires window.onbeforeunload event, although the link doesn't attempt to redirect to other page. This may make user annoyed. There are two solutions for this issue.
The first one is:
 <a href = "#" onclick = "alert('hello');" >Link</a>
The other one is :
 <a href = "javascript:;" onclick = "alert('hello'); return false;" >Link</a>

The  second one is preferred, since it will not append an anchor in URL.