Yesterday, I was trying to install digikam on my Macbook Pro and I just followed the instruction to install.

Well, it was not that easy to install digikam on Mac. Anyway, here is the story:

I went to "Macports" to download the package to install the Macports and when Macports is installed then I type

# sudo port install digikam

to install the digikam and its dependencies (http://www.digikam.org/download?q=download/binary/).
As per instruction, it mentioned about "be prepared to wait hours for the compilation of digiKam and all its dependencies", so I was waiting and waiting for the installation to complete.

It took about an hour to complete and I was excited to open the application via Launchpad/MacPorts (Other)/digikam.app. Ooops, it throws an error:

"Run-time Qt4 SQLite or MySQL database plugin is not available - please install it.
Database plugins installed on your computer are listed below:
QSQLITE3
"


I googled and googled again and found a quick solution here by running:

# sudo port install qt4-mac-mysql5-plugin

The previous message didn't show up again but another message came up:

"error while opening the database.
digikam will try to automatically reconnect to the database
"



by Elvis Hsu 2 comments Read More

Recently, one of my clients needed to have a date/time field to update/create their records. So I googled a bit and found a great sample/extension for my existing project.

Yes, it is Ext.ux.form.field.DateTime. However the existing extension does not have validation function so I just made a few changes on it.


/**
* @auther Elvis Hsu
* @class Ext.ux.form.field.DateTime
* @extends Ext.form.FieldContainer  
* 
* inspired by http://www.sencha.com/forum/showthread.php?134345-Ext.ux.form.field.DateTime
* This class is used for user input 
*/
Ext.define('Ext.ux.form.field.DateTime', {
    extend:'Ext.form.FieldContainer',
    mixins: {
        field: 'Ext.form.field.Field'
    },
    alias: 'widget.datetimefield',
    layout: 'hbox',
    height: 22,
    /**
    * set combine errors to true for showing errors
    */
    combineErrors: true,
    /**
    * set msg target to side
    */
    msgTarget :'side',  
    /**
    * we want hbox layout
    */
    layout: 'hbox',
    /**
    * set readonly to false
    */
    readOnly: false,    
    /**
    * @cfg {String} dateFormat
    * Convenience config for specifying the format of the date portion.
    * This value is overridden if format is specified in the dateConfig.
    * The default is 'Y-m-d'
    */
    dateFormat: 'Y-m-d',
    /**
     * @cfg {String} timeFormat
     * Convenience config for specifying the format of the time portion.
     * This value is overridden if format is specified in the timeConfig. 
     * The default is 'H:i:s'
     */
    timeFormat: 'H:i:s',
    /**
    * the datefield configurations
    */
    dateConfig:{},
    /**
    * the time field configurations
    */
    timeConfig:{},
    /**
    * The actual date value
    */
    dateValue: null,
    /**
     * @property dateField
     * @type Ext.form.field.Date
     */
    dateField: null,
    /**
     * @property timeField
     * @type Ext.form.field.Time
     */
    timeField: null,    
    /**
    * initialising the components
    */
    initComponent: function() {
        var me = this,
            key,
            tab;
        // set default to no items
        me.items = me.items || [];
        
        me.dateField = Ext.create('Ext.form.field.Date', Ext.apply({
            format:me.dateFormat,
            flex:1,
            isFormField:false, //exclude from field query's
            submitValue:false
        }, me.dateConfig));
        me.items.push(me.dateField);
        
        me.timeField = Ext.create('Ext.form.field.Time', Ext.apply({
            format:me.timeFormat,
            flex:1,
            isFormField:false, //exclude from field query's
            submitValue:false
        }, me.timeConfig));
        me.items.push(me.timeField);
        
        for (var i = 0; i < me.items.length; i++) {
            me.items[i].on('focus', Ext.bind(me.onItemFocus, me));
            me.items[i].on('blur', Ext.bind(me.onItemBlur, me));
            me.items[i].on('specialkey', function(field, event){
                key = event.getKey();
                tab = (key == event.TAB);
                
                if (tab && me.focussedItem == me.dateField) {
                    event.stopEvent();
                    me.timeField.focus();
                    return;
                }
                
                me.fireEvent('specialkey', field, event);
            });
        }

        me.callParent();
        
        // this dummy is necessary because Ext.Editor will not check whether an inputEl is present or not
        me.inputEl = {
            dom:{},
            swallowEvent:function(){}
        };
        
        me.initField();
    },
    /**
     * Try to focus this component.
     * @param {Boolean} [selectText] If applicable, true to also select the text in this component
     * @param {Boolean/Number} [delay] Delay the focus this number of milliseconds (true for 10 milliseconds).
     * @return {Ext.Component} this
     */
    focus:function(){
        this.callParent();
        this.dateField.focus();
    },

    onItemFocus:function(item){
        if (this.blurTask){
            this.blurTask.cancel();
        }
        this.focussedItem = item;
    },
    
    onItemBlur:function(item){
        var me = this;
        if (item != me.focussedItem){ return; }
        // 100ms to focus a new item that belongs to us, otherwise we will assume the user left the field
        me.blurTask = new Ext.util.DelayedTask(function(){
            me.fireEvent('blur', me);
        });
        me.blurTask.delay(100);
    },    
    /**
     * Returns the current data value of the field. The type of value returned is particular to the type of the
     * particular field (e.g. a Date object for {@link Ext.form.field.Date}).
     * @return {Object} value The field value
     */
    getValue: function() {
        var me = this,
            value = null,
            date = me.dateField.getSubmitValue(),
            time = me.timeField.getSubmitValue();
        if(date){
            if(time){
                var format = me.getFormat()
                value = Ext.Date.parse(date + ' ' + time,format)
            }else{
                value = me.dateField.getValue()
            }
        }
        return value
    },
    /**
     * Sets a data value into the field and runs the change detection and validation.
     * @param {Object} value The value to set
     * @return {Ext.form.field.Field} this
     */
    setValue: function(value){
        if (Ext.isString(value)){
            value = Ext.Date.parse(value, this.getFormat()); //this.dateTimeFormat
        }
        this.dateField.setValue(value);
        this.timeField.setValue(value);
    },
    /**
     * Resets the field's {@link #originalValue} property so it matches the current {@link #getValue value}. This is
     * called by {@link Ext.form.Basic}.{@link Ext.form.Basic#setValues setValues} if the form's
     * {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} property is set to true.
     */
    resetOriginalValue: function() {
        var me = this;
        me.originalValue = me.getValue();
        me.dateField.resetOriginalValue();
        me.timeField.resetOriginalValue();
        me.checkDirty();
    },
    /**
     * Returns the value that would be included in a standard form submit for this field. This will be combined with the
     * field's name to form a name=value pair in the {@link #getSubmitData submitted parameters}. If an empty string is
     * returned then just the name= will be submitted; if null is returned then nothing will be submitted.
     *
     * Note that the value returned will have been {@link #processRawValue processed} but may or may not have been
     * successfully {@link #validate validated}.
     *
     * @return {String} The value to be submitted, or null.
     */
    getSubmitValue: function(){   
        var me = this,
            format = me.getFormat(),
            value = me.getValue();
            
        return value ? Ext.Date.format(value, format) : null;        
    },         
    /**
     * Returns the parameter(s) that would be included in a standard form submit for this field. Typically this will be
     * an object with a single name-value pair, the name being this field's {@link #getName name} and the value being
     * its current stringified value. More advanced field implementations may return more than one name-value pair.
     *
     * Note that the values returned from this method are not guaranteed to have been successfully {@link #validate
     * validated}.
     *
     * @return {Object} A mapping of submit parameter names to values; each value should be a string, or an array of
     * strings if that particular name has multiple values. It can also return null if there are no parameters to be
     * submitted.
     */
    getSubmitData: function(){
        var me = this,
            data = null;
            
        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
            data = {};
            data[me.getName()] = '' + me.getSubmitValue();
        }
        return data;
    },
    /**
    * Gets the current date time field format
    */
    getFormat: function(){
        var me = this;
        return (me.dateField.submitFormat || me.dateField.format) + " " + (me.timeField.submitFormat || me.timeField.format)
    },
    /**
     * Replaces any existing {@link #minValue} with the new value and refreshes the Date picker.
     * @param {Date} value The minimum date that can be selected
     */    
    setMinValue: function(date){
        var me = this;
        me.dateField.setMinValue(date);
    },
    /**
     * Replaces any existing {@link #maxValue} with the new value and refreshes the Date picker.
     * @param {Date} value The maximum date that can be selected
     */    
    setMaxValue: function(date){
        var me = this;
        me.dateField.setMaxValue(date);
    },
    validate: function(){
        var me = this;
        return me.dateField.validate();
    }
}); 
by Elvis Hsu No comments Read More
Today, I was browsing around the web and found some interesting articles which are related to minify extjs on the fly. Well, if I can minify the server response and deflate it, that would be even faster to deliver to client's browser? So I decided to give it a go.

Bang~ It is faster than just minify the content. But so far I just tested with Apache server as it is most used http server in my projects. I just added the following code in my .htaccess file

# compress text, html, javascript, css, xml:
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript

By the way, you may want to enable the mod_deflate.so in your httpd.conf to make it work.

Anyway, have a look at How To Optimize Your Site With GZIP Compression. It really gives a heads up. So you may want to have a try on your projects.
by Elvis Hsu No comments Read More
I have been developing some projects with ExtJs for a while and also created some plubg-ins and extensions for these projects. Recently, I found out that I have so many *.js and *.css codes and they are somehow too fat for some slow band width users. Well, I decided to google some solutions to minify my js and css codes. Luckily, I found minify and I am loving it. However, most of my ExtJs plug-ins and extensions are called by Ext.require and it is somehow complicated to override the Ext.Loader.require so I googled again... Ha... the answer came up from here (Using .htaccess and RewriteRule? for Minify).


   Options +FollowSymlinks
   RewriteEngine On
   RewriteBase /
   RewriteRule ^(.*\.(css|js).*)$ min/f=%{REQUEST_URI} [L,NC]


The original post is just rewrite the file name but I need full path.
Well, just replace $1 to %{REQUEST_URI} and put the .htaccess file under the Ext.ux path.
Then job done.

So when you call:
Ext.require([
    'Ext.ux.SimpleIFrame',
    'Ext.ux.PreviewPlugin',
    'Ext.ux.GMapPanel'
]);


The Apache server redirects the JS script URL and the minify class process it.
Have a try and your will love it...
by Elvis Hsu 1 comment Read More