Deals

Monday, May 27, 2013

Alternate Way to Create Image Button in Sencha Touch

Hello,

Recently I was working on a sencha touch project where I need to use a nig round image in sencha touch button.  We all now that we can use images inside button using iconCls and iconMask property. That will put small icons inside your button along with button rounded corners and background colors. But in my case we don't need button background color or rounded border of button. We just need a round image with transparent background and user should be able to click on it. There are number of ways for doing it.

First we can use xtype : image and put image url to it. But sometimes tap event does not work over image. So this not an option. Other option is to use panel and put image as html inside and add tap evet to panel body. But that will be on complete panel body. So in case of round image if user tapped outside the image but inside a panel, tap event will be fired. So here is the third solution.

As we know that Ext.button extends the Ext.component so we can add html to component.  So we can add image as html as follow.

{
      xtype: 'button',

      html: '<img src="lib/images/myImage.png"/>'
}

After adding this image is added inside the button and but still have button background colors and rounded border. This you can remove by updating your sencha touch CSS. Find the following class in sencha touch CSS.

.x-button, .x-button.x-button-back:after, .x-button.x-button-forward:after, .x-toolbar .x-button, .x-toolbar .x-button.x-button-back:after, .x-toolbar .x-button.x-button-forward:after {
background-image: none;
background-color: #ccc;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f2f2f2), color-stop(3%, #d9d9d9), color-stop(100%,#bfbfbf));
background-image: -webkit-linear-gradient(top, #f2f2f2,#d9d9d9 3%,#bfbfbf);

background-image: -moz-linear-gradient(top, #f2f2f2,#d9d9d9 3%,#bfbfbf);

background-image: -o-linear-gradient(top, #f2f2f2,#d9d9d9 3%,#bfbfbf);

background-image: linear-gradient(top, #f2f2f2,#d9d9d9 3%,#bfbfbf);
}

and replace it with following class. This will remove all background of button but still you will have rounded borders.


.x-button,.x-toolbar .x-button.x-button-back:after,.x-toolbar .x-button.x-button-forward:after{background-image:none;}

Now to remove borders, find following class.

.x-button, .x-toolbar .x-button {
border: 1px solid #999;
border-top-color: #a6a6a6;
background-color: #ccc;
color: #000;
}

and replace it with 

.x-button, .x-toolbar .x-button {
color: #000;
}

That's it and your button will only have image. And still user can tap on and it and have a feeling like button. 

Pelase note that updated sencha touch css is applicable to all the buttons in your application so if you have more than one button which does not have image, please don't use this trick. In my case I was having only one button in application so that's why I am using this trick.

Hope this helps you.

Sunday, May 26, 2013

Capture CSS3 Animations Event in JavaScript

Hello,

This is my first blog on CSS 3 animations. Recently I was working on project where I created some CSS 3 animation. It was a sencha touch project, so we have some requirements like when animation ends we have to switch active item on view port. This we can only do in JavaScript and for that we have to capture CSS 3 animations events in JavaScript. So how to do it?

Basically we are going to add event handler. In case of web kit browser this is webkitAnimationEnd and webkitAnimationStart events. Please note that this event will only work if you have used -webkit-animation on the target. If you are using Transitions, there are some other events. I will cover that in next blogs. Check the code below. This shows exact syntax of adding animation start and end events.

Suppose you have html element with id box1 on which you are applying some CSS 3 animation.

document.getElementById("box1").addEventListener('webkitAnimationStart',function(event){

},false);

Above code will capture animation start event.

document.getElementById("box1").addEventListener('webkitAnimationEnd',function(event){

},false);

Above code will capture animation end event.

If you have infinite animation above functions be invoked every time when animation starts or ends. You also get event object as a parameter to callback function. It contains the target which invoked this event. You can get it using event.srcElement

Please note that above code will only work on web kit browsers.

Monday, May 13, 2013

Passing Query String With Index.html file in iOS Phonegap (Cordova)

Hello,

Imagine a scenario that you have Sencha Touch/ jQuery mobile application and you have used Phonegap (Cordova) to compile it to native iOS application.  Now your application expects some params like authentication token, or user id or anything it can be. You need to send this params along with your index.html file so that you can use it in app launch function. Have you ever faced this situation. If yes then here is the solution. Please remember this solution is specifically for iOS Cordova application.

First let's see how normally it works. When you create a Cordova based application in XCode, You have AppDelegate.h and AppDelegate.m file. Open AppDelegate.m file and find a function below.


- (BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions

In this function find the following lines of code.

self.viewController.wwwFolderName = @"www";
self.viewController.startPage = @"index.html";

This specify that web assets folder is WWW and start page is index.html. If you have some other start page you can change the name here. Now if you try to pass query string as follow, it will not work.


self.viewController.startPage = @"index.html?query1=value1";

Because it treats it as page name and there is no such page. So how to resolve this.

First of all remove the start page name from code.

self.viewController.startPage = @"";

Now we will implement NSURL interface and add some custom functions in it to handle the query string. Add following code to your AppDelegate.m file above implementation of AppDelegate

@implementation NSURL (Additions)

- (NSURL *)URLByAppendingQueryString:(NSString *)queryString {
    if (![queryString length]) {
        return self;
    }
    
    NSString *URLString = [[NSString alloc] initWithFormat:@"%@%@%@", [self absoluteString],
                           [self query] ? @"&" : @"?", queryString];
    NSURL *theURL = [NSURL URLWithString:URLString];
    [URLString release];
    return theURL;
}

@end

This function accepts query string and add it to URL and create new URL. Now add following code at end of didFinishLaunchingWithOptions function.

NSString* newQueryString = @"query1=value1&query2=value2&query3=value3";
NSURL *newurl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:@"www"]];

newurl = [newurl URLByAppendingQueryString:newQueryString];
[self.viewController.webView loadRequest:[NSURLRequest requestWithURL:newurl]];


Above code will build custom URL with query string and load the URL in iOS webview.

Hope this helps you.




Sunday, April 21, 2013

TinyMCE Editor Height Issue in ExtJs Application

Hello,

This is another blog post on TinyMCE editor in ExtJs application, Have you ever noticed that If you use TinyMce editor in ExtJs application there are some issues with height. Sometimes it takes more height then you specified and that might destroy your layout completely. This is due to internal calculations and logic of TinyMCE editor.

The logic is wrong in two ways. First thing is that it always assume that minimum height of TinyMCE editor should be 100 so if you give height less then 100. It will always take it as 100 and hence your layout is wrong. Because outer div of editor will show the height which you gave but it's actual height would be different.

Second issue is that it does not take care of editor's tool bar where you have all the controls. Actually editor's height should be height which you specified minus height of control toolbar. Which actually is not the case. It gives separate height to toolbar. For example if you set height of your editor to 100. It actually set height to 128. 100px height of editor and 28px height of toolbar controls so it's totally wrong. So what is the solution?

Well the solution is in the TinyMCE src file. You will have tiny_mce_src.js file in your app. There go to line no 13301 approximately. There you will see following line.

mh = s.min_height || 100;

This is where the issue is. If you give height less then 100 it will always take 100 as minimum height. So change it as follow.

mh = s.min_height || s.height;

Now it will take minimum height which you specified. Now go to line no 13426 approximately.  Here change the height from

height : h

to

height : h-28

That's it and all your issues related to heights are resolved.

It took 4 hours for me to find the solution so I hope this post saves your time.

Thanks.






TinyMCE editor in ExtJs Application Returns Old Value.

Hello,

Finally I got some to add some more interesting blogs. Recently I have faced an issue with TinyMCE editor in ExtJs application. The issue was little wired. We have a TinyMCE editor in ExtJs form panel where it's disabled first. There is a button in form panel which enables. After that if we update any value in TinyMCE editor, it shows on screen but when we get value from form panel, the value of TinyMCE field is always the old one.

After struggling for some hours, I find out the issue. When TinyMCE is disabled, there are no events of active editor. But when we enable it editor should be initialized properly and all the event handlers should be attached. However it's not happening. So what is the solution for it. Change the logic of TinyMCE intilization and add key up event.


setup : function( ed ) {
ed.onKeyUp.add(function(ed) {
tinymce.activeEditor.save();
});
}

This you can find it your TinyMCEHtmlEditor.js file. What it does is it saves the state of current active editor when we type something it it. This logic works when you have more then one TinyMCE editor in single form. Because when you are typing inside it tinymce.activeEditor gives instance of current active editor and keyup events save its state. So when you getValue of editor, it reflects the new value.

Hope this helps you.

Thursday, February 28, 2013

iOS Phonegap ( Cordova ) Open Link in Safari


Have you ever encountered the situation in your corodova project where you have set OpenAllWhitelistURLsInWebView to YES in your Cordova.plist file and you have to open one single URL in external Safari application.? If yes than read this blog.


For cordova we have to whitelist some external urls if we have any. By default it will open in external Safari browser to prevent that we have to set following in Cordova.plist file.

This will open all the external urls in same web view. So to add exception URL which should open in external Safari browser make following changes to AppDelegate.m file. 

- (BOOL) webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = [request URL];
    NSString* urlString =  [url absoluteString];
    
    if ([urlString rangeOfString:@"www.myexternalurl.com"].location == NSNotFound) {

    }
    else {
        [[UIApplication sharedApplication] openURL:[request URL]];
        return NO;
    }
}


and in your JavaScript simply write following line.

window.location.href = "www.myexternalurl.com";

Once web view start loading the url it will invoke shouldStartLoadWithRequest event. Here we are checking the url string and if we find it to be external URL, it will be opened in external Safari browser. Webview will not load this URL since we return NO.

Android Add In-app billing to existing project

Hello,

If you have ever encountered situation, where you need to add In-app billing to your existing project, than this blog is for you. Please note that for this you need Google Play Account and valid Google Merchant Account.

First open Android SDK manager. You can open it from Window - > Android SDK Manager. If it's not available in menu go to Window -> Customize Perspective and Go to third tab  Command Groups Availability.


And check the Android SDK and AVD Manager. Now it should be available in menu. Open it and Go to Extra.


Check the Google Play Billing Library and Click on Install items. This will download necessary files of billing library. Also it will download the sample application. No go to your project src folder in eclipse and Right click on it. Choose Menu New - > Package. Give the name com.android.billing.vending to the package and add file IInAppBillingService.aidl to it. You can find your file in your Android SDK folder at this path extras - > google - > play_billing - > in-app-billing-v03

Now create one more package in in your src and give name com.yourappname. util and add following files to it form sample application. Replace yourappname with your application name.



Now compile your project and it should generate IInAppBillingService.java file in gen folder.


Now add following line to your AndroidManifest.xml file


That's it and now your application is ready for in app billing. For testing use reserved SKUs by google play store. Now create a new activity class and give the suitable name to it. in my case I name it as PurchaseActivity

Add a member to a class 

IabHelper mHelper;

Add following code to onCreate function of activity.

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_purcahse);
String base64EncodedPublicKey = "yourapppublickey";
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
  public void onIabSetupFinished(IabResult result) {
      if (!result.isSuccess()) {
        // Oh noes, there was a problem.
        Log.d("inappp", "Problem setting up In-app Billing: " + result);
      }
      String purchaseToken = "inapp:"+getPackageName()+":android.test.purchased";
     
      startPurchase();
  }
});

Replace yourapppublickey with your application's public key. For this you need create application in google play store and it give you application public key. Here android.test.purchased is the reserved SKU maintained by Google Play Store for the testing purpose. You don't need to spend money to test it.

Add following functions to your class.

public void startPurchase(){
mHelper.launchPurchaseFlow(this, "android.test.purchased", 10001,   
  mPurchaseFinishedListener, "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
}

IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener 
  = new IabHelper.OnIabPurchaseFinishedListener() {
  public void onIabPurchaseFinished(IabResult result, Purchase purchase) 
  {
      if (result.isFailure()) {
        Log.d("inapp", "Error purchasing: " + result);
        return;
      }      
      else if (purchase.getSku().equals("test")) {
      Log.d("inapp","Purchase successful" + result);
      }
  }
};

Once purchased you have to consume purchase. Please note that this blog does not mention the consumption process. This just shows how to test in app billing in your project. Later you can replace the test SKUs with your own SKUs.