Sencha Touch with GameThrive.com

Montag, 17. November 2014
Hey Touchers,

some of you might know GameThrive.com. For those who don't: it's a completly free push notification service. This weekend GaemThrive published a guide for Phonegap. I had to apply some changes so it's working with Sencha. This is how you will get GameThrive working with Sencha Touch:

1. Install the external preconditions from step 1 and / or 2 HERE

2. Add the following plugins.

3. Add this to your launch function and replace the app_id (iOS) or senderId(Android) in the jsonData Object:



This is it. You will find a full Sencha Architect example to download HERE.

Questions and improvements are welcome!


Source:
http://documentation.gamethrive.com/v1.0/docs/phonegap-sdk-installation
Read more ...

-- FIX -- Sencha Touch does not center Map correctly

Dienstag, 4. November 2014
Some of you may already have faced this issue. Centering Google Maps does not always work how it should, especially If you use markers. Here is how to fix this issue:


First I we need a map, for example this one here:



Now comes the important part. You need to add a listener on your map for the painted event. When the painted event is fired we do also need a timeout to set the center. This can be really small.




This should to it, the map will now be centered correctly.
Read more ...

Sencha Touch change theme dynamically / programmatically

Dienstag, 2. September 2014
Here's an example how to change the Sencha Touch theme within your coding.

Demo: LINK

Source: LINK

The most important part is this function:




I know there is improvement to be done while the new css is beeing applied but I think you can do it on your own ;)


Read more ...

Ext.ProgressIndicator outside of a Ajax.request

Donnerstag, 21. August 2014
It's a long time since my last tutorial. But I think I got another useful example to show.
Maybe some already know the new ProgressIndicator in Sencha Touch 2.3.x. You can simply attach it to a Ajax.request as the progress option to show the download/upload progress to the users of your app.
I wanted to use this also for other use-cases such as the FileTransfer class in Cordova / Phonegap. Even if your now bound to this example I did the a showcase with the FileTransfer.download method :)

DEMO LINK

ZIP LINK


Read more ...

!!! UPDATED !!! Sencha Touch Grid: Percentage based width

Dienstag, 1. Juli 2014
As many of you I was wandering why Sencha didn't include the possibility to set a column width to a specified 25% of the screen. So here is a how to enable this feature by yourself.

DEMOhttps://dl.dropboxusercontent.com/u/2056172/KeepAlive/GridPrecentageWidth/ExampleProject/index.html

Full Project: https://dl.dropboxusercontent.com/u/2056172/KeepAlive/GridPrecentageWidth/GridColumnPercentage.zip

Full Tutorial:

First we need a sample grid and set the  width of the columns to a percentage value, for example '25%'

Ext.define('ExampleProject.view.SampleGrid', {
    extend: 'Ext.grid.Grid',
    alias: 'widget.samplegrid',

    requires: [
        'Ext.grid.column.Column'
    ],

    config: {
        height: '100%',
        id: 'samplegrid',
        store: 'MyStore',
        title: 'MyGrid',
        columns: [
            {
                xtype: 'column',
                itemId: 'column1',
                width: '40%',
                dataIndex: 'data1',
                text: 'Column1'
            },
            {
                xtype: 'column',
                itemId: 'column2',
                width: '25%',
                dataIndex: 'data2',
                text: 'Column2'
            },
            {
                xtype: 'column',
                itemId: 'column3',
                width: '25%',
                dataIndex: 'data3',
                text: 'Column3'
            }
        ],
        listeners: [
            {
                fn: 'onGridPainted',
                event: 'painted'
            },
            {
                fn: 'onGridWidthChange',
                event: 'widthchange'
            }
        ]
    
    }
)};

All we need to to now is to call a function on the painted event which will let us render the percentage value to a pixel value and overwrite the width on the column.

So add a painted listener because we need to set the new size when the grid is painted:


onGridPainted: function(element, eOpts) {
        this.renderColumnPercentage(element);
},

And now calculate the pixels from the percentage value:

var grid = this,
    
    columnArr = grid.getColumns(),
    
    numberOfCols = columnArr.length,
    
    clientWidth = element.getAttribute('clientWidth');

columnArr.forEach(
    function(column, index, array) {
        
        var perWidth = column.getWidth(); // Percentage or Pixel width --> '25%' || '123'
        
        if (!Ext.isNumeric(perWidth) && perWidth) { // Checking for a percentage value
            
            perWidthNum = perWidth.substr(0,perWidth.length-1) / 100; // Numeric Width --> 0.25
            pxWidth = clientWidth * perWidthNum; // Width in Pixel --> 123
            
        }
        
        // Header width
        column.bodyElement.setWidth(pxWidth);
        column.refreshSizeState();
        
        // Each column has its own class
        if (! column.getCellCls()) {
            column.setCellCls(createCellCssClass(pxWidth));
        } else {
            // Query doms for a class --> 1 Class = 1 Column
            var elements = Ext.query('.' + column.getCellCls()),
                newClass = createCellCssClass(pxWidth),
                oldClass = column.getCellCls();
            
            // Loop doms and replace old class with new one
            Ext.Array.each(elements, function(ele, index, elementsItSelf) {
                
                ele.classList.remove(column.getCellCls());
                ele.classList.add(newClass);
                
            });
            
            column.setCellCls(newClass);
            
        }
        
    }
);

function createCellCssClass(pxWidth) {
    
    var className = 'cell-' + 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
    
    var css = document.createElement('style');
    css.type = 'text/css';
    
    var styles = '.' + className + ' { width: ' + pxWidth + 'px !important; }';
    
    if (css.styleSheet)
        css.styleSheet.cssText = styles;
    else
        css.appendChild(document.createTextNode(styles));
    
    document.getElementsByTagName("head")[0].appendChild(css);

    return className;
}

The width is set on the elements level to prevent loosing the percentage value on the column level.

Last we need to call the same function when widthchanged is fired on the grid itself because this will need resizing for all columns.
Just add a listener to perform the resizing again:

onGridWidthChange: function(component, value, oldValue, eOpts) {
        this.renderColumnPercentage(component.bodyElement);
},


Read more ...

Shorthanders

Dienstag, 8. April 2014
As I often see many developer write way to much code even if the do not have to. Here are my tipps for you to safe lines of coding :)

Read more ...

Sencha Touch Grind-Printer

Montag, 31. März 2014
Maybe someone of you already had the wish to print a grid easily from within a Sencha Touch application.

Requirements:

  • Cordova
  • Cordova printer plugin: https://github.com/FRD49/phonegap-print-plugin


Here is a short javascript source written by myself to archive this. Documentation is in the code itself. Columns without a dataindex will not be printed!

Read more ...

Build List / Grid Searchfield

Donnerstag, 20. Februar 2014
I want you to show a little tutorial how to create a searchfield to filter a list, grid or something else which has a relation to a store. I want to show this to you by using a list.

If you need you can download the Architect 3 project from here: https://mega.co.nz/#!9NFyRCLL!98dkUmISgGO_p0crDI8YExINmf5ORCglkDrWjuRyu7Y


First we create a Store with a model and some data in it. If you want to take a look, you'll have a link here: https://gist.github.com/difa1/9115899

Second we need to create a simple list in a panel:

Ext.define('MyApp.view.MyPanel', {
    extend: 'Ext.Panel',
    requires: [
        'Ext.dataview.List',
        'Ext.XTemplate'
    ],
    config: {
        layout: 'vbox',
        items: [
            {
                xtype: 'list',
                flex: 1,
                itemTpl: ['{name}, {namelast}'],
                store: 'persons'
            }
        ]
    }
});

Third we would like to implement the searchfield. You can place it however you want.

Ext.define('MyApp.view.MyPanel', {
    extend: 'Ext.Panel',
    requires: [
        'Ext.field.Search',
        'Ext.dataview.List',
        'Ext.XTemplate'
    ],
    config: {
        layout: 'vbox',
        items: [
            {
                xtype: 'searchfield',
                docked: 'top',
                itemId: 'storeSearchField',
                label: 'Field'
            },
            {
                xtype: 'list',
                flex: 1,
                itemId: 'mylist',
                itemTpl: ['{name}, {namelast}'],
                store: 'persons'
            }
        ]
    }
});

Now that the basics a build we build a new controller where all the logic is stored. So lets go to Step 4 and create the controller with 2 listeners: keyup and clearicontap:

Ext.define('MyApp.controller.logicController', {
    extend: 'Ext.app.Controller',
    config: {
        control: {
            "searchfield#storeSearchField": {
                clearicontap: 'onStoreSearchFieldClearicontap',
                keyup: 'onStoreSearchFieldKeyup'
            }
        }
    },
    onStoreSearchFieldClearicontap: function(textfield, e, eOpts) {
        // Logic
    },
    onStoreSearchFieldKeyup: function(textfield, e, eOpts) {
        // Logic
    }
});

The logic for the clearicontap is pretty simple... All we want is to clear all filters. All we need is the clearfilter method :

    onStoreSearchFieldClearicontap: function(textfield, e, eOpts) {
        Ext.getStore('persons').clearFilter();
    }


The keyup is a bit more tricky, why I like to use a basic function for it. I tried to explain all steps in the coding itself. If anything were unclear, you could contact me on Google+ ;)

onStoreSearchFieldKeyup: function(textfield, e, eOpts) {
    this.filterList(textfield, Ext.getStore('persons'));
},

filterList: function(textfield, store) {
    // Get the searchfield content
    var value = textfield.getValue();

    // Clear previous filters
    store.clearFilter();

    // Check for search value, if not present we don't need to to anything...
    if (value) {

        // Split search value: Space --> 2 custom values!
        var searches = value.split(' '),
        regexps = [],
        i;

        // Loop search values and build regex
        for (i = 0; i < searches.length; i++) {

            // Ignore spaces
           if (!searches[i]) continue;

           // Regex array
           regexps.push(new RegExp(searches[i], 'i'));
            
       }

       // Filter the store
       store.filter(function(record) {

           // Clear matches first
           var matched = [];

           // Loop all regex expressions
           for (i = 0; i < regexps.length; i++) {
               var search = regexps[i];
               var didMatch;

              didMatch = record.get('name').match(search) ||
                         record.get('namelast').match(search);
                    // You can add as many model fields as you want! --> record.get('city1').match(search) ||


              // Write match to array
              matched.push(didMatch);
          }

          // Nothing found? Do not return anything ;)
          if (regexps.length > 1 && matched.indexOf(false) != -1) {

               return false;

          } else {

               // Found something? Just return to store ;)
               return matched[0];

          }
     });

     // Finally load store
     store.load();
}



Read more ...

Part 3: Send file attachments by email

Montag, 3. Februar 2014
In this last part I want you to show how you can send an attachment by email. Generally you can add any file from the device you have in your sandbox. I will show you how to add the csv file which we created in Part 1 and Part 2

First we need a Phonegap / Cordova plugin. If you didnt know how to setup your project for use with phonegap, you would have to take a look at Part 2.

1. Add emailComposer Plugin
Open the terminal and cd to your Phonegap / Cordova folder and execute the following command:

cordova plugin add https://github.com/katzer/cordova-plugin-email-composer.git

This is the call structure from the developer website:

/*
 * Opens an email draft pre-filled with the passed properties.
 */
window.plugin.email.open({
    to:          Array, // contains all the email addresses for TO field
    cc:          Array, // contains all the email addresses for CC field
    bcc:         Array, // contains all the email addresses for BCC field
    attachments: Array, // contains all full paths to the files you want to attach
    subject:    String, // represents the subject of the email
    body:       String, // represents the email body (could be HTML code, in this case set isHtml to true)
    isHtml:    Boolean, // indicats if the body is HTML or plain text
});

For further informations about the plugin take a look to the developer website: https://github.com/katzer/cordova-plugin-email-composer

2. Send the email

The function should be self explaining. You can either pass the recipient, cc, bbc as string or as Array. Of course you can send any kind of attachments using this function. If an example is needed how to read file from LocalFileSystem and send them please ask for it and I'm willing to prove an example.

FILE2MAIL: function(recipient, cc, bcc, subject, body, attachementURL) {
    if (!Ext.isArray(recipient)) {
        recipient = new Array(recipient);
    }

    if (!Ext.isArray(cc)) {
        cc = new Array(cc);
    }

    if (!Ext.isArray(bcc)) {
        bcc = new Array(bcc);
    }

    if (!Ext.isArray(attachementURL)) {
        attachementURL = new Array(attachementURL);
    }

    window.plugin.email.open({
        to:          recipient, // contains all the email addresses for TO field
        cc:          cc, // contains all the email addresses for CC field
        bcc:         bcc, // contains all the email addresses for BCC field
        attachments: attachementURL, // contains all full paths to the files you want to attach
        subject:    subject, // represents the subject of the email
        body:       body, // represents the email body (could be HTML code, in this case set isHtml to true)
        isHtml:    true // indicats if the body is HTML or plain text
   });
}

3. Combining Part 1 & Part 2 & Part 3

var dummyStore = Ext.getStore('dummyStore');

STORE2CSV(dummyStore,null, stringSuccess);

function stringSuccess(csv){
    DATA2FILE('export.csv',csv,fileSavedSuccess)
}

function fileSavedSuccess(file){
    FILE2MAIL('dummyEmail@gmail.com','','','hallo test file','Test Attachement',file.fileName);
}


If you have any kind of questions or improvements please leave a comment or contact me. I appreciate any help or hints!


Read more ...

Sencha Touch Grid Action Column

Montag, 3. Februar 2014
As you may know the current grid version (2.3.0.2) in the Sencha Touch framework doesn't support the action column at the moment.

I this post, I want you to show how you can add clickable "button" in a column. In fact is it not a real button, but it will allow you to take track which cell is clicked and to take actions then.

First we need a grid with some columns in it. The column which needs action should be a template column so you can style it like you want. Something like this:

Ext.define('SiteCockpit.view.ExampleGrid', {
    extend: 'Ext.grid.Grid',
    alias: 'widget.examplegrid',

    requires: [
        'Ext.grid.column.Template',
        'Ext.XTemplate',
        'Ext.grid.plugin.MultiSelection',
        'Ext.grid.plugin.Editable'
    ],

    config: {
        itemId: 'exampleGrid',
        store: 'dummyStore',
        title: 'Example Grid',
        columns: [
            {
                xtype: 'templatecolumn',
                tpl: [
                    '<tpl>',
                    '    <div class="button1-field"></div>',
                    '<tpl>'
                ],
                width: 50
            },
            {
                xtype: 'templatecolumn',
                tpl: [
                    '<tpl>',
                    '    <div class="button2-field"></div>',
                    '<tpl>'
                ],
                width: 50
            },
            {
                xtype: 'column',
                fdname: 'exidv',
                width: 150,
                align: 'center',
                dataIndex: 'exidv',
                text: 'exidv'
            }
       ]
    }
})

As you can see the first and the second column do not have any text just a class. If you want some text just add by yourself.

Now we need to declare these classes in the sass to get a button like style. It is up to you how you want to style it. I just added 2 icons.
//
//    
// .button1-field { content: ""; height: 2.5em; width: 2.5em; background-image: url(data:image/png;base64,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); background-size: 1.5em; background-size: 1.5em; display: block; background-repeat: no-repeat; background-position: bottom; } .button2-field { content: ""; height: 2.5em; width: 2.5em; background-image: url(data:image/png;base64,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); display: block; background-size: 2em; background-size: 2em; background-repeat: no-repeat; background-position: bottom; }

Next we need to know when and more important which cell was tapped! I took this logic in a separate controller. We use the classes to know which one was tapped. It sounds pretty simple and it even is :)

Ext.define('SiteCockpit.controller.gridController', {
    extend: 'Ext.app.Controller',

    config: {
        control: {
            "grid": {
                itemtap: 'onDetailGridTap'
            }
        }
    },

    onDetailGridTap: function(dataview, index, target, record, e, eOpts) {
        var me = this;

        switch (e.target.className) {

            case 'button1-field':

                // First row was tapped!    
                break;

            case 'button2-field':

                // Second row was tapped!
                break;
        }
    }
})

I hope it is all clear and will help you a bit until the action column is supported :)
Read more ...

Part 2: Sencha Store to local CSV file

Sonntag, 2. Februar 2014
Hey guys,

This is Part 2 of 3 How to send a Sencha Store as CSV file by email. If you missed the first part, you would like to take a look here http://abitofcoding.blogspot.com/2014/01/part-1-sencha-touch-store-to-csv-string.html

1. Get Phonegap / Cordova ready
Firstly we will need our app wrapped with Phonegap / Cordova. There are several ways to do, since Touch 2.3.0 Sencha offers a pretty nice integration for Phonegap and Cordova. Since the you can setup your project with a single Sencha CMD command:



// FOR PHONEGAP
// sencha phonegap init [APP IDENTIFIER] [APP NAME]
sencha phonegap init com.mycompany.MyApp MyApp

// FOR CORDOVA
// sencha cordova init [APP IDENTIFIER] [APP NAME]
sencha cordova init com.mycompant.MyApp MyApp


Take a look at the Sencha Docs for more options and information: http://www.sencha.com/blog/leveraging-phonegap-within-sencha-touch/

2. Install requirements
As we need access to the device filesystem we need to install the file plugin for Phonegap / Cordova.
If you use Phonegap / Cordova 3.* it's pretty simple:

// FOR CORDOVA
//same for phonegap as for cordova
cordova plugin add org.apache.cordova.file
// the transfer plugin is not really needed but nice to avoid errors :)
cordova plugin add org.apache.cordova.file-transfer


That's it :D

3. Building and saving

As mentioned Part 1 is about building the CSV string. This one we will use now to safe on file.
You can create and add any content to any kind of file you want.
Take the CSV string from Part 1 as data and take a filename which is something like *.csv and you will have a CSV file created on your device!
Questions or improvements are welcome!

// FOR CORDOVA
DATA2FILE: function(filename, data, callback) {
        // default filename
        var defaultFileName =  'export-file.txt';

        if (filename === undefined || filename === null) {
            filename = defaultFileName;
        }

        // Request the file system
        window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);

        // Access to filesystem is OK
        function gotFS(fileSystem) {
            fileSystem.root.getFile(filename, {create: true}, gotFileEntry, fail);
        }

        // File is ready
        function gotFileEntry(fileEntry) {
            fileEntry.createWriter(gotFileWriter, fail);
        }

        // Write file content
        function gotFileWriter(writer) {
            writer.onwriteend = function(evt) {
                console.log('finished writing');
                if (callback !== undefined) {
                    callback(writer);
                }
            };
            writer.write(data);
        }

        function fail(error) {
            console.log('Error: ', error.code);
        }
    }

To combine the CSV string from Part 1 and this method something like this is possible:

var duSto = Ext.getStore('dummyStore');
STORE2CSV(duSto,null,
 function(csvData){
  DATA2FILE('export.csv',csvData, function( // PART 3 HOW TO SEND COMING SOON){}
        }
) 



Read more ...

Part 1: Sencha Touch store to csv string

Freitag, 31. Januar 2014
I put a lot of research in this topic. The idea was to send a Sencha Touch store as csv by email to someone.

In this post I would like to show you the first step: generate CSV data from a store. There will be further post to this topic:

Part 2: Save csv string as csv file on the device
Part 3: Send csv file from device as email to recepients

If you have comments, questions or improvements please post them in the comment area!



The parameters are easy to understand:
// store: a reference to the store, which you want to send
// inFilter(optional): pass a filter function and the store will be filtered before taking data from it
// callback(optional): pass a callback function to use the csv data somewhere else

STORE2CSV: function (store, inFilter, callback) {
    var dataArray = new Array();

    if (inFilter === undefined || inFilter === null) {

        doBuild();

    } else {

        store.clearFilter();
        store.filter(inFilter);
        doBuild();

    }

    function doBuild() {

        store.load({
            callback: function (r, options, success) {
                if (success === true) {
                    store.each(function (item) {
                        dataArray.push(item.getData());
                    });
                    var csv = createCSV(dataArray);

                    if (callback !== undefined) {

                        callback(csv);

                    }
                }
            }
        });
    }

    function createCSV(objArray) {

        var array = typeof objArray != 'object' ? Ext.util.JSON.encode(objArray) : objArray,

            str = '',
            line = '',
            value = '',

            head = array[0]; // HEAD LINE

        for (var index in array[0]) {
            value = tryHeaderTranslate(index) + "";

            line += '"' + value.replace(/"/g, '""') + '",';
        }

        line = line.slice(0, -1);
        str += line + '\r\n';

        for (var i = 0; i < array.length; i++) {
            line = '';

            for (var index in array[i]) {
                value = array[i][index] + "";
                line += '"' + value.replace(/"/g, '""') + '",';
            }

            line = line.slice(0, -1);
            str += line + '\r\n';
        }
        return str;

    }

    // Try to translate the header
    function tryHeaderTranslate(header) {

        // you could translate or change the headers here if want to...
        return header;

    }
}
Read more ...

iOS7 Phonegap / Cordova statusbar fix

Freitag, 31. Januar 2014


Since Apple has release the complete new iOS7 to public you may have some trouble with your phonegap apps. The reason is simple: the statusbar is not a reserved area anymore. It got a transparent bar with a 20px height.

It seems a simple thing but it is going to annoy you and especially your users!
Here is a simple trick to fix your application again, there might be other solutions to solve it in javascript within your application but I prefer the Objective-C way. If you had the app running as a website you wouldn't have to apply any changes.

Just replace the existing viewWillAppear function in your MainViewController.m, rebuild and you're done.

// Fix for shrinking screen on Camera, Camera-Roll, InAppBrowser and more...
bool sizeWasAdjusted = false;
- (void)viewWillAppear:(BOOL)animated
{
    // View defaults to full size.  If you want to customize the view's size, or its subviews (e.g. webView),
    // you can do so here.
    //Lower screen 20px on ios 7
    if (!sizeWasAdjusted && [[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
        CGRect viewBounds = [self.webView bounds];
        viewBounds.origin.y = 20;
        viewBounds.size.height = viewBounds.size.height - 20;
        self.webView.frame = viewBounds;
        sizeWasAdjusted = true;
    }
    [super viewWillAppear:animated];
}
Read more ...