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.

6/05/2014

[JS] Get Parameters in a JavaScript Script Tag

In google-code-prettify, you can specify the code language and skin just in one line. No extra configuration is necessary since the parameters is already appended to the URL.
<script src="svn/loader/run_prettify.js?lang=css&skin=sunburst"></script>
So how does the JS file know the parameters appended to its URL? You can just call the function getScriptParams(..) to get the parameters in JS object format.
This will get JS object:
console.log(getScriptParams('run_prettify.js')); 
Here is implementation of getScriptParams(..).
function getScriptParams(scriptFileName) {
   // Get all script tag
  var scripts = document.getElementsByTagName('script');
  var result = {};
  for(var i = 0; i < scripts.length; ++i) {
     // Check if the file name is the same as scriptFileName
    if(scripts[i].src.indexOf(scriptFileName) !== -1) {    
      // Get the parameters string     
      var urls = scripts[i].src.split('?');
      if(urls.length == 2) {
        var parameters = urls[1].split('&');        
        for(var j=0; j< parameters.length; ++j) {
          var pair = parameters[j].split('=');
          result[pair[0]] = pair[1];
        }
      }
      break;
    }
  }
  return result;
}

5/28/2014

[Sublime] Code Formatter (Reindent) Shortcut in Sublime

Preference -> Key Bindings-User:
[
  { "keys": ["ctrl+shift+r"], "command": "reindent", "args": { "single_line": false } }
]
This will reindent entire file in Sublime.

5/25/2014

[ExtJS] Close Window if Click Anywhere Other Than The Window Itself

Some web application shows a window for presenting more detail information. It allows user to close the window not only via clicking the close button but also via clicking anywhere other than the window itself.


Click to Close Ext JS Window on Focus Out
If you'd like to have this behavior for a window in ExtJS, you can add the following code to your application.
Ext.define('TonyTuan.window.Window', {
    override: 'Ext.window.Window',
    closeOnFocusOut: false,
    initComponent: function() {
        var me = this;
        if (me.closeOnFocusOut === true) {
            me.mon(Ext.getBody(), 'click', function(el, e) {
                me.close(me.closeAction);
            }, me, {
                delegate: '.x-mask'
            });
        }
        me.callParent(arguments);
    }
});
And set closeOnFocusOut:true for the window you want.
Ext.widget('window', {
    closeOnFocusOut: true,
    title: 'Hello',
    height: 200,
    width: 400,
    layout: 'fit',
    items: {       
        html: 'hello world'
    }
}).show();

Please note that this kind of behavior is not suitable for a window with a input form, since user may click somewhere other than the window incautiously, leading to the loss of input data.

5/23/2014

[ExtJS] RowExpander doesn't show a whole long word

I have a RowExpander grid with a summary field which may contains a very long word. If there's no space between this word, RowExpander cannot show full word. For example, the summery field is '11111 222222 33333344444444444....555555555555'. But the number "5555.." doesn't present.

If a word is too long, I'd like to let the row expander break it a new line instead of hiding it.


Live Example
: RowExpander doesn't show a whole long word

To solve this issue, we can just add a attribute word-wrap:break-word; to x-grid-rowbody class like:

.x-grid-rowbody p {
 word-wrap: break-word;
}
Result:

Force a Long Line of Word (without spaces) to Line Break in ExtJS RowExpander

The solution is verified in ExtJS 4.1.1, 4.2, and 5.0.

5/21/2014

[CSS] Force a Long Line of Word (without spaces) to Line Break

Suppose you have a very long word in DIV as below, the word will not break by default.
<div id="veryLongWord">VeryLongWordVeryLongWordVeryLongWord</div>
<style>    
  #veryLongWord{
    border-style:double;
    width: 250px;
  }    
</style>
Result:
VeryLongWordVeryLongWordVeryLongWord

If you'd like to make a long word have Line Breaks, just add word-wrap:break-word; to your css like:

<div id="breakWord">VeryLongWordVeryLongWordVeryLongWord</div>
<style>    
  #breakWord{
    border-style:double;
    width: 250px;
    word-wrap:break-word;
  }    
</style>
Result:
VeryLongWordVeryLongWordVeryLongWord

4/29/2014

Auto login in WinSCP cmd

Create a script named "scp.script" with the following content.

option batch on
option confirm off
open sftp://MyAccount:MyPass@serverIP:22 -hostkey="ssh-rsa 1024 42:9e:c7:f4:7f:8b:50:10:6a:06:04:b1:d4:f2:04:6d"
dir
exit

Then run the script:

"C:\Program Files\WinSCP\WinSCP.com" /script:"scp.script"     
Here comes result:
batch           on
confirm         off
Searching for host...
Connecting to host...
Authenticating...
Using username "root".
Authenticating with pre-entered password.
Authenticated.
Starting the session...
Reading remote directory...
Session started.
Active session: [1] root@10.0.0.1
-rw-------   1 root     root         14376 Apr 11 14:30:29 2014 .mysql_history
-rw-r--r--   1 root     root           107 Apr 23 17:13:12 2013 .gtk-bookmarks

3/28/2014

[ExtJS] Cancel Duplicate Store Loading Request Automatically

In the previous article, we mentioned how to abort a store request manually. It's used when programmer want to cancel a store loading request manually.


"Refresh" button in grid

Image there's a "Refresh" button in your grid, the user may press the button quickly multiple times. This behavior make store send multiple requests at a short period of time. So it's better to abort the previous requests for performance and data correctness issue.


Cancel Duplicate Store Loading Request Automatically

The following code overrides ExtJS store behavior, making all of stores in web application abort duplicated store loading request automatically. Just put it to somewhere your application initialized.

Ext JS 4.1.1a:

Ext.define('Tonytuan.data.Store', {
  override: 'Ext.data.Store',
  abort: function () {
    var me = this;
    if (me.loading && me.lastOperation) {
      var requests = Ext.Ajax.requests;
      for (id in requests) {
        if (requests.hasOwnProperty(id) && requests[id].options == me.lastOperation.request) {
          Ext.Ajax.abort(requests[id]);
          delete requests[id];
          break;
        }
      }
    }
  },
  constructor: function (config) {
    var me = this;
    me.callParent([config]);
    me.on({
      'beforeload': function (store, operation) {
        // Abort previous request if it has not been completed.
        if (me.loading) {
          me.abort();
        }
        store.lastOperation = operation;
      }
    });
  }
});

Ext JS 5.0.1:

Ext.define('Ext.enhance.data.Store', {
  override: 'Ext.data.Store',
  abort: function() {
    var me = this;
    if (me.isLoading() && me.lastOperation) {
      var requests = Ext.Ajax.requests;
      for (id in requests) {
        if (requests.hasOwnProperty(id) && requests[id].options.url == me.lastOperation.request._url) {
          Ext.Ajax.abort(requests[id]);
          delete requests[id];
          break;
        }
      }
    }
  },
  constructor: function(config) {
    var me = this;
    me.callParent([config]);
    me.on({
      'beforeload': function(store, operation) {
        // abort previous request
        if (me.isLoading()) {
          me.abort();        }
        store.lastOperation = operation;
      }
    });
  }
});

3/27/2014

[ExtJS] Capture All Events Fired by a Component

If you want to capture all events fired by a component, just call Ext.util.Observable.capture after the component is created.

Ext.util.Observable.capture(grid, function(eventName, signature) {
    console.log('Event:', eventName, signature);
});

Capture All Events Fired by a Component in ExtJS

Online Demo on Sencha Fiddle

3/05/2014

[ExtJS] RowEditing: Save Data to Server Immediately When Clicking Update Button.

The RowEditiing in ExtJS doesn’t send a request after a user click Update button. The records in grid will become dirty state after user click. But it doesn’t not mean that records in remote DB are changed. Even you call grid.store.commitChanges(), this would not send a request to server as well. The method commitChanges() only clear dirty state in store.

How to send a request whenever the grid is edited?
Let’s explain by giving an simple user management example. Here is User model with fake data. The model is binding with a REST proxy which is used for building request to server.
Ext.define('TonyTuan.User', {
    extend : 'Ext.data.Store',
    fields : [ 'id', 'name', 'role' ],
    data : [ {
        id : '1',
        name : 'Tony',
        role : 'Programmer'
    }, {
        id : '2',
        name : 'Steve',
        role : 'Programmer'
    }, {
        id : '3',
        name : 'Alice',
        role : 'Manager'
    } ],
    proxy : {
        type : 'rest',
        url : 'rest/users',
        reader : {
            type : 'json'
        }
    }
});
The Role store for combobox.
Ext.define('TonyTuan.Role', {
    extend : 'Ext.data.Store',
    fields : [ 'display', 'value' ],
    // fake data
    data : [ {
        display : 'Programmer',
        value : 'Programmer'
    }, {
        display : 'Designer',
        value : 'Designer'
    }, {
        display : 'Project Manager',
        value : 'Manager'
    } ]
});
The user grid with a rowEditing plugin listens on an edit event which is fired whenever records in grid are changed. Therefore, we can send a http PUT request by calling record.save() in the edit event handler.
Ext.define('TonyTuan.UserGrid', {
    extend : 'Ext.grid.Panel',
    width : 300,
    store : Ext.create('TonyTuan.User'),
    selType : 'rowmodel',
    plugins : [ {
        ptype : 'rowediting' // enable row editing
    } ],
    initComponent : function() {
        var me = this;

        me.columns = [ {
            header : 'id',
            dataIndex : 'id'
       
        }, {
            header : 'name',
            dataIndex : 'name'
        }, {
            header : 'Role',
            dataIndex : 'role',       
            editor : { 
                // for editable field, set a proper field xtype for it
                xtype : 'combobox',
                store : Ext.create('TonyTuan.Role'),
                queryMode : 'local',
                editable : false,
                displayField : 'display',
                valueField : 'value',
                allowBlank : false
            }
        } ];

        // Listen on the edit event to send a request to server
        me.on('edit', function(editor, e) {
            e.record.save({
                success : function(record, operation) {
                    // (show successful message here)
                    me.store.load();
                },
                failure : function(record, operation) {
                    // (show error message here)

                    // clear the dirty state and rollback the records
                    me.store.rejectChanges(); 
                }
            });
        });
        me.callParent(arguments);
    }
});
Ext.create('TonyTuan.UserGrid', {
    renderTo : Ext.getBody()
}); 
Online Demo on Sehcna Fiddle

[ExtJS] Remote Validator for Form Field (Server Side Validator)

ExtJS usually validates form field locally. For example, In register form, you may like to check if the password has more than 8 characters. This could be done easily.

{
 fieldLabel : 'Password',
 name : 'password',
 allowBlank : false,
 validFlag : true,
 validator : function(value) {
    if (value != '' && value.length < 8) {
      return 'Password should has more than 8 characters';
    }
    return true; 
 }
}

However, in some situation, you have to validate the input values in server side. For instance, the username in a website should be unique. Thus, you can let the field validator return true by default, but whenever the inputs has be changed, make the listener trigger an AJAX request to check if the value is valid and validate the field explicitly in the callback function.

{
 fieldLabel : 'Username',
 name : 'username',
 allowBlank : false,
 validFlag : true,
 validator : function() {
  return this.validFlag;
 },
 listeners : {
  'change' : function(textfield, newValue, oldValue) {
   var me = this;
   Ext.Ajax.request({
    url : 'rest/users?action=validate&username=' + newValue,
    success : function(response) {
     // Ausuming responseText is {"valid" : true}
     me.validFlag = Ext.decode(response.responseText).valid ? true : 'The username is duplicated!';
     me.validate();
    }
   });
  }
 }
}

[ExtJS] Get Server Response in Model.save() or Model.destroy() Failure Callback Function

Many people have the same question: How to get server response in model's failure function? It's easy to get response from server when operation success. But it's a little bit tricky to get response when operation fails. I saw a solution which add a listener to store's proxy to listen on exception event. But I found a easier way below.

model.save({
    success: function (record, operation) {
        // json response from server         
        console.log(operation.response);                  
    },
    failure: function (record, operation) {
        // undefined
        console.log(operation.response); 
        // json response from server
        console.log(operation.request.scope.reader.jsonData);
    }
});

[ExtJS] Abort Store Request / Connection / Loading

It's kind of intuitive to abort a Ext.Ajax.request.

var req = Ext.Ajax.request({
    url: 'page.aspx'
});
Ext.Ajax.abort(req);

However, aborting store's request isn't easy since store doesn't return request object when loading. Thus, we need to keep request object on beforeload event. Then cancel the store's request later on.

Let's just override the store's constructor to make every store keep their request object before sending request and implement a method call abort() in store.

Ext.define('Ext.enhance.data.Store', {
    override: 'Ext.data.Store',
    constructor: function(config) {
        var me = this;
        me.callParent([config]);
        me.on({
            'beforeload': function(store, operation) {
                // keep the operation which has request object
                store.lastOperation = operation;
            }
        });
    },
    abort: function() {
        var me = this;
        if (me.loading && me.lastOperation) {
            var requests = Ext.Ajax.requests;
            for (id in requests) {
                if (requests.hasOwnProperty(id) && requests[id].options == me.lastOperation.request) {
                    Ext.Ajax.abort(requests[id]);
                    delete requests[id];
                    break;
                }
            }
        }
    }

});

Then we are able to abort a store request easily.

grid.store.abort();

Reference: http://stackoverflow.com/questions/13251440/selectively-aborting-an-ajax-request-sent-via-extjs-direct-proxy