Archive for the ‘JavaScript;Ajax’ Category

JavaScript 101: Creating a custom object

December 6, 2009

// initialize the object
var MyOwnClass = {};

// define all the members for the object
(function(){

// declare and define a property
var foo = “hello world! I’m foo.”;

// define a method
this.init = function()
{
alert(“yo! ” + foo);
}

}).apply(MyOwnClass );

// hook up with the DOM event
window.addEventListener(“load”, MyOwnClass.init, false);

Block statements in control flow constructs

December 2, 2009

There is no need to block (using braces to wrap) single line statements in a control flow (as-if, do-while, for/while); and you can mix blocks and non block statements together like this:

if(num > 0)
trace(num+” is positive;\n”);
else if(num <0)
{
trace(num+” is negative.”);
trace(num+” don’t be negative;\n”);
}
else if(num == 0)
trace(num+” is neutral;\n”);

This applies to all the control statements although the example here is just of if/else .

With this being said, The Elements of C# Style recommends Always us block statements in control flow constructs. Reason one is that it makes it easy to add additional statements in it; reason two is it’s easier to read than those without blocks.

Notes for Building iPhone With HTML, CSS and JavaScript by Jonathan Stark

October 17, 2009

The book. Author: Jonathan Stark.

  • Page scaling in iPhone
    By default Mobile Safari will zoom out for a page that is wider than 980px unless you specify “viewport” <meta> tag to tell it not to;

    <meta name = "viewport" content = "user-scalable=no, width=device-width" />
  • CSS for iPhone
    <link rel=”stylesheet” type=”text/css” href=”styles/iphone.css” media=”only screen and (max-device-width: 480px)” />
    <link rel="stylesheet" type="text/css" href="styles/desktop.css" media="screen and (min-device-width: 481px)" />
    <!--[if IE]>
    <link rel="stylesheet" type="text/css" href="styles/desktop.css" media="all" />

    <![endif]-->
  • Icon for iPhone home screen, a.k.a. “web clip icon”By default, this is a 57px by 57px named “apple-touch-icon.png” in your web root. iPhone will add gloss and 10px(?) radius rounded corner to it. If you don’t want the iPhone to add effects to your webclip icon, change the name of the file to “apple-touch-icon-precomposed.png“.In the case you want to add a web clip icon for an individual page that is different from the rest of the site, add one of the following lines to the of the page:

  • <link rel="apple-touch-icon" href="myCustomIcon.png" />
    <link rel="apple-touch-icon-precomposed" href="myCustomIcon.png" />

  • Full-screen modeAdd the following line to the of your page and your web app will in display full screen mode when launched from the web clip icon, which will give you an extra of 104 px in height:

    <meta name="apple-mobile-web-app-capable" content="yes" />

    Once you’ve added the apple-mobile-web-app-capable meta tag, you have the option to control the background color of the 20 pixel status bar at the top of the screen using the apple-mobile-web-app-status-bar-style meta tag. The normal gray Safari status bar is the default, or you can change it to black. You can also set it to black-translucent which makes it partialy transparent and additionally removes it from the document flow. In other words, your content will be shifted up by 20 pixels and behind the status bar the when page first loads, so you might have to position your header a little lower to compensate.

  • Here are some webkit(?)/Safari specific CSS or newer CSS3 attributes or confusing ones:

  • text-shadow
    text-shadow: 0px 1px 0px #fff;

    The parameters: horizontal offset, vertical offset, blur, and color.
  • -webkit-gradient
    background-image: -webkit-gradient(linear, left top, left bottom, from(#ccc), to(#999));
    a CSS gradient can be used anywhere you would normally specify a url() (e.g. background image, list style image). The parameters from left to right are as follows: the gradient type (can be linear or radial), the starting point of the gradient (can be left top, left bottom, right top, or right bottom), the end point of the gradient, the starting color, and the ending color.
  • -webkit-border-top-left-radius, etc.
    #header ul li:first-child a {
    -webkit-border-top-left-radius: 8px;
    -webkit-border-top-right-radius: 8px;
    }
  • first-child/last-child pseudo classes

    #header ul li:first-child a {
    -webkit-border-top-left-radius: 8px;
    -webkit-border-top-right-radius: 8px;
    }
    #header ul li:last-child a {
    -webkit-border-bottom-left-radius: 8px;
    -webkit-border-bottom-right-radius: 8px;
    }

    The first-child and last-child pseudo classes can be a bit confusing. For example, li:first-child will select the first li that is the child of its ul parent. It does not select whatever is the first child of the li.
  • rgb/rgba
    text-shadow: rgba(125,125,125,0.6) 0px -1px 0px;
  • -webkit-border-image and border-width
    border-width: 0 8px 0 8px;
    -webkit-border-image: url(images/button.png) 0 8 0 8;

    These two propoerties together allow you to assign portions of a single image to the border area of an element. They are similar to 9-slice scaling in Flash or 9-patch in Android. The parameters in border-width refer to top/right/bottom/left side of the image.

MVC revisit: Take two

June 7, 2009

I find that MVC is much easier to understand both at the conceptual level and at the implementation level if you think about it from the perspective of how you communicate with the Model.

  1. Control is the input to Model. Basically, the Control is responsible to take input from the user or the system and stransfer it to the changes in the Model; The View is merely there to render the changes from the Model; so it can be considered as the output from the Model. You should keep the business logic as much as possible inside the Model and leave Control/View simple and dandy.For Flex 3 (Halo) components, the way of input is realized by implimenting the “change” listener of the controls, like this:

    <mx:TextInput id="mTxt" change="mVO.txtValue = mTxt.htmlText;"/>

    In Flex 3, when you bind a model to a control, it is one-way communication, meaning the control will reflect the change whenever there is one in the model; but the control would not be able to change the model. That’s why we need to wire through the change listener to make this happen.

    The output is hooked up by setter methods in the Model. Whenever you detect some changes that are historical, you would notify your listeners.

    [Bindable]
    public function set myValue(v:int):void
    {
    _
    myValue = v;
    notifyListeners();
    }

    In ActionScript 3, we normally implement “notifyListeners” by way of dispatchEvent. Your client listens to the event and updates the View by querying the changes from the Model. You may want to have different types of events so that your listeners can respond differently. For example, you normally would invalidate properties of your component and regenerate all the renderers when the data provider has changed, besides doing other updates; and you don’t want to do this kind of heavy-lifting each time when changes occur on the “less important” members of the Model.

  2. Asynchronous data. Sometimes you may compose something like an HTTPService component into your Model so that it can request external data.The data that are requested by the Control at a lot of times are not immediately available, and normally you would not notify your listeners until they are ready (For example, parsed into an XMLList object that can be consumed by component’s dataProvider).
  3. Static members are available before non-static members of the objects. You can use static members to set some initial values of your member variables.
  4. When you smell spaghetti code in your Model, try to partition/refactor your Model into smaller Value Objects. Value objects are a good way to structure your data/make flat Model hierarchical.
  5. For larger projects, you may want to duplicate Model (or value objects) so that multiple client can access the same data. For example, in your main window of your AIR application, you initialize your model like so:

    public var chatModel:ChatModel = new ChatModel();In another console window, you want to access the same model, like so:

    private var chatModel:ChatModel = Application.application.chatModel;

Postfix operators: x++

March 30, 2009

Although postfix operators are unary operators, they are classified separately from the rest of the unary operators because of their higher precedence and special behavior. When a postfix operator is used as part of a larger expression, the expression’s value is returned before the postfix operator is processed. In other unary operators, such as prefix increments/decrements, the increment or decrement operation is completed before the value of the overall expression is returned.

#include <iostream>
using namespace std;

int main()
{
int max = 3;
int total = 7;

int count = 0;
cout<<“unary test for postfix:”<<endl;
for(int i = 0; i< total; i++)
{
count = count >= max? 0 : count++;
cout<<“#”<<i<<“: “<<“count is “<<count<<endl;
}
cout<<endl;

count = 0;
cout<<“unary test for prefix:”<<endl;
for(int i = 0; i< total; i++)
{
count = count >= max? 0 : ++count;
cout<<“#”<<i<<“: “<<“count is “<<count<<endl;
}
cout<<endl;

cout<<“for loop test:”<<endl;
count = 0;
for(int i = 0; i< total; i++)
{
if(count >= max)
{
count = 0;
}else
{
//both are the same.
//count++;
++count;
}
cout<<“#”<<i<<“: “<<“count is “<<count<<endl;
}
cout<<endl;
}
/**result
unary test for postfix:
#0: count is 0
#1: count is 0
#2: count is 0
#3: count is 0
#4: count is 0
#5: count is 0
#6: count is 0

unary test for prefix:
#0: count is 1
#1: count is 2
#2: count is 3
#3: count is 0
#4: count is 1
#5: count is 2
#6: count is 3

for loop test:
#0: count is 1
#1: count is 2
#2: count is 3
#3: count is 0
#4: count is 1
#5: count is 2
#6: count is 3
*/

click on marker always show the last entry of data

June 14, 2008

This is a question from a co-worker of my last job. His is using gcliendGeocoder within a for-loop to dynamically get lat/lng and creating makers on Google maps. The problem is each time you click on a marker, the html text in the info window is always the one that should be for the last marker in the for-loop.

His code:

for (id = 0; id < addresses.length; id++)
{
var description = addresses[id];
var myBiz = biz[id];
geocoder.getLatLng(
description,
function(point)
{
var marker = new GMarker(point);
GEvent.addListener(marker, ‘click’,function(){marker.openInfoWindowHtml(description);});
map.addOverlay(marker);
}
);
}

The point here is “geocoder.getLatLng” is an “asynchronous” callback. That means when the “for-id-loop” reaches its end, the very first “getLatLng” may not get back yet. That’s why you always get the last description in the array. The fix is to add an additional counter inside the call back of “getLatLng”, and assign it as a dynamic property to the marker that gets returned from the callback, and then increment the counter by one at the end of the callback. When you handle the click, you always do a lookup on the marker using the id to find the right marker and the description.

var markers = [];
var closureID = 0;

for (id = 0; id < addresses.length; id++) {
var description = addresses[id];

geocoder.getLatLng(
description,
function(point) {
if(point)
{
var marker = new GMarker(point);
marker.id = closureID;
markers[closureID]=marker;
GEvent.addListener(marker, ‘click’,
function()
{
markers[marker.id].openInfoWindowHtml(addresses[marker.id]);
}
);
map.addOverlay(marker);
++closureID;
}
}
);

}

To see it in action, here is what happens “before“, and “after“:

E4X in ActionScript 3 and Flex 3

January 1, 2008

The following top AS3 classes, in conjunction with HTTPService and mx.rpc.events.ResultEvent classes are used in Flex (2+) to handle XML:

XML/XMLList/Namespace/QName

XMLList Class can be considered a collection of XML objects. It is a native ActionScript class that is advised to handle XML such as data binding. XMLNode has become the legacy class in AS 2.

So the first step of handling XML data is to deserialize an XML document or object into XMLList objects.

<mx:HTTPService id="dataFetcher" url="http://mysite/myData.xml" resultFormat="e4x" result="onData(event)" />

Remember you will almost always need to initialize the call by adding the following code to the “creationComplete” event handler of the mx:Application node:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="dataFetcher.send()"/>

To deserialize the an XML object (sample shown as follows), use ResultEvent Class, like so:

<delSum Test="1" timestamp="2007-12-10T21:07:48Z">
<del pId="Dem" dNeed="2029" dTot="4056" dChosen="991" dToBeChosen="3237">
<Cand cId="1746" cName="Clinton" dTot="290" d1="+290" d7="+290" d30="+150"/>
<Cand cId="1918" cName="Obama" dTot="194" d1="+194" d7="+194" d30="+55"/>
</del>
<del pId="GOP" dNeed="1113" dTot="2225" dChosen="251" dToBeChosen="2153">
<Cand cId="893" cName="Romney" dTot="109" d1="+109" d7="+109" d30="+1"/>
<Cand cId="302" cName="Paul" dTot="47" d1="+47" d7="+47" d30="0"/>
</del>
</delSum>

private function onData(event:ResultEvent):void
{
demData = event.result.del.(@pId=="Dem").Cand.(@cName!="Uncommitted");
gopData = event.result.del.(@pId=="GOP").Cand.(@cName!="Uncommitted");
}

Note that event.result represents the top node, which is <delSum> node in the XML document.

XML filtering:

To locate a set of XML objects that represents similar characteristics, use the parenthesis () to include sets of boolean statements, following a dot after the node you want to carry out the filtering against, like so:

var product1:XMLList = catalog.product.(@id==1);//Returning the product node or nodes if there are multiple products whose id is equal to 1

or

var productName:String = catalog.product.(price<50).name;//Returns the name node

or

var manufName:String = catalog.product.(price<50).@manufacturer;//Returns the manufacturer attribute under the name node

To get list of candidate names:

var _tst:XMLList = event.result.del.(@pId=="GOP").Cand.(@cName!="Uncommitted").@cName
trace((_tst[0] is XML)+"; "+_tst[0].nodeKind() )//Returns "true; attribute"
trace(gopData[0].@cName+"; "+(gopData[0].nodeKind())//Returns "Romney; element"

Types of node include: text, comment, processing-instruction, attribute, or element.

google map css trap 101

November 6, 2007

#1. An div rule will sometimes screw up the overlay popup. Suppose you have #container>#mapDiv, the following will add a weird white bar underneath the popup window (speech bubble when openInfoWindowHTML/openInfoWindow are called):

#container div{
margin-top:10px;
padding-bottom:10px;
}

#2. For some mysterious reasons, sometimes the GInfoWindow object gets some extra document div(s) nested when you call openInfoWindowHTML/openInfoWindow and that results in extra white padding space between the real content and teh GInfoWindow object. The workaround is to specify the “maxWidth” property in the GInfoWindowOption object which is the second parameter for an openInfoWindow(HTML) call:

GEvent.addListener(marker, "click", function() {
marker.openInfoWindow(venue.getHTML(), {maxWidth:300});
});

Assign additional class to a div using Prototype 1.5/6

October 5, 2007

Senario:

You need to do something like this (only one div gets assigned class “hilit” at a time):

<div class = “thumbDivOther hilit” id=”thumb_intro” onclick=”showItem(‘intro’, this);”>

Code:

currHilitDiv.removeClassName(‘hilit’);
//This doesn’t work in IE6
//div.addClassName(‘hilit’);
Element.addClassName(div, ‘hilit’);
currHilitDiv = div;

Instantiate one Flash object at once in a page

October 5, 2007

Senario:

I need to instantiate only one Flash object at once in a page, for instance under a row of tabs when the user clicks on one of them. Sometimes I toggle between different Flash objects; sometimes just another DOM div takes place of the Flash object. It’s very straightforward in Firefox since all you need to do is to toggle the “display” property (set it to the value of “none”). With Prototype library, you can use Element.hide()/show(). In IE, situations get a little complicated since if that Flash is playing a video clip, the stream continues (you still hear sound, etc.) regardless of its containing div’s “display”/”visibility” property values.

Solutions:

For the former situation, simply write a new swf object to the same div:

function loadSWF(fileName)
{
swfURL = appURL+’swf/’+fileName+’.swf’;
var so = new SWFObject(swfURL, “soObj”, “500”, “360”, “8”, “#eeeeee”);
so.addParam(“allowscriptaccess”,”always”);
so.addParam(“swliveconnect”, “true”);
so.useExpressInstall(“http://myhostname.com/js/swfobject/expressinstall.swf&#8221;);
so.write(“vidHolder”);
}

For the latter situation, destroy the swf object by doing the following when toggling to another div which doesn’t contain any swf object. This will stop the audio/video streams:

$(‘vidHolder’).innerHTML = “”;