Recently, I found a presentation on how to solve cross domain issues. I think it's quite useful for web developers.
Web 2.0, Ruby, Rails, TDD, BDD,
rSpec, XMPP, BOSH, REST,
Javascript, Ajax, Google Maps API,
Google Gears API, CSS,
Java, C#, Social Network, RMagick, Nginx
Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts
Saturday, July 31, 2010
Cross-Domain Solutions
Labels:
javascript,
presentation,
web
Friday, February 19, 2010
Meta-programming in Ruby and JavaScript
Recently, I have been working with writing a ruby gem, Yoolk API Gem. What is really interesting for me is I do some meta programming and object-oriented programming in Ruby which I have never experienced before. A few month later, there is a requirement that my team needs to write in JavaScript, but I don't want to touch JavaScript really much. Therefore, my team member took over this task. Whenever I write code in Ruby, I just try to think how to do it in JavaScript as well. Several things that came up to my mind with some from my team member:
1. Defer class from a variable.
2. Access class method from instance object
3. Define method of an object
4. Define class methods
1. Defer class from a variable.
// JavaScript
var klass = "Person";
p = new window[klass]; //class without namespace
p = new yoolk[klass]; //class with namespace
# Ruby
klass = "Person"
p = Object.const_get(klass).new #class without namespace
p = Yoolk.const_get(klass).new #class with namespace
2. Access class method from instance object
// JavaScript
var p = new Person();
p.constructor.getCount();
#Ruby
p = Person.new
p.class.count
3. Define method of an object
//JavaScript
var p = new Person();
p.hello = function() {
alert('hello');
};
//Ruby
p = Person.new
def p.hello
puts "hello"
end
4. Define class methods
//JavaScript
Person.hello = function() {
alert('hello');
};
//Ruby
def Person.hello
puts "hello"
end
Labels:
javascript,
ruby
Saturday, June 27, 2009
Maintaining Javascript Pop-Up Window Communication Across Window Opener Page Loads
I came across a blog post that talks how to maintain a reference to javascript popup window while the parent window has been navigated away. This scenario doesn't want to reload the child popup window. I just quoted out from 1 Pixel Out. There is a really nick trick.
In the main window:
In the popup:
http://www.bennadel.com/blog/89-Maintaining-Javascript-Pop-Up-Window-Communication-Across-Window-Opener-Page-Loads.htm
http://www.1pixelout.net/2005/04/19/cross-window-javascript-communication/
http://www.1pixelout.net/2006/12/15/cross-window-javascript-communication-20/
http://www.1pixelout.net/wp-content/downloads/popups20.zip
In the main window:
var popupWin = null;
function openPopup() {
var url = "popup.htm";
popupWin = open( "", "popupWin", "width=500,height=400" );
if( !popupWin || popupWin.closed || !popupWin.doSomething ) {
popupWin = window.open( url, "popupWin", "width=500,height=400" );
} else {
popupWin.focus();
}
}
function doSomething() {
openPopup();
popupWin.doSomething();
}
In the popup:
self.focus();
function doSomething() {
alert("I'm doing something");
}
http://www.bennadel.com/blog/89-Maintaining-Javascript-Pop-Up-Window-Communication-Across-Window-Opener-Page-Loads.htm
http://www.1pixelout.net/2005/04/19/cross-window-javascript-communication/
http://www.1pixelout.net/2006/12/15/cross-window-javascript-communication-20/
http://www.1pixelout.net/wp-content/downloads/popups20.zip
Labels:
javascript
Cross-window Javascript communication
It reminds me about uploading via iframe that I did a year ago when my colleague asked me to help with login openid in a popup window. It's a similar story with this problem. Actually, login with openid could not place in a iframe because you could the code that prevents this.
Now, let's see a quick summary on this basic communication.
Communication from parent to child window, you need to a reference of the child window so that can call any function in the child window.
Communication from child to parent window, you need to use this way:
Here is the problem, the parent window needs to know when the uploading (in iframe) or logging in (in popup window) is done. The only way that the parent window can notified by the child window after finish processing. Usually, for uploading and logging in with openid, the action in your controller would render a view back. The trick is here on the onload of the body, you could notify the parent window.
That would solve the problem, and you could send any information back through your view.
<script type="text/javascript">if(top == self) { document.write(""); } else { top.location.href = "http://www.yahoo.com"; }</script>
Now, let's see a quick summary on this basic communication.
Communication from parent to child window, you need to a reference of the child window so that can call any function in the child window.
// Create a new popup window
var popupWin = window.open(url, "popupWin");
// To call functions defined in the popup:
popupWin.doSomething();
Communication from child to parent window, you need to use this way:
window.opener.doSomethingOnParent();
Here is the problem, the parent window needs to know when the uploading (in iframe) or logging in (in popup window) is done. The only way that the parent window can notified by the child window after finish processing. Usually, for uploading and logging in with openid, the action in your controller would render a view back. The trick is here on the onload of the body, you could notify the parent window.
def login
@status = "something"
end
#view
<html><head></head>
<body onload="window.opener.handleOpenIDResponse('" + @status + "');window.close();">
</body>
</html>
That would solve the problem, and you could send any information back through your view.
Labels:
javascript
Wednesday, May 13, 2009
JavaScript in Object-Oriented Way
I conducted a training to some developers in my office about one full day, yesterday. It is quite exhausted anyway, but everyone seems understand really well. This slide covers many advanced features of JavaScript: Function, Object, Closure,.... Some other points I have pointed out in this slide are about how to make private variable, public variable, static variable, privileged variable and how to do inheritance. I took about 20 different sources as my references and three famous authors. It took me two weeks, at every weekend, to finish this slide.
JavaScript in Object-Oriented Way
View more presentations from cchamnap.
Labels:
javascript
Thursday, May 7, 2009
JavaScript Mixins
I have just reviewed JavaScript Design Patterns, and I think it is good to mention this.
It is possible to do a mixin class in JavaScript as in Ruby. This is another way to make our code reuse without inheritance. Consider you have a function, and you wish to use in many classes. In practice, you create a class that contains your general-purpose methods, and then use it to augment other classes. Class with these general-purpose methods is called Mixin class. It is generally not instantiated or called directly, instead it exists to provide methods to other classes.
This sort of method could potentially be useful in many different types of classes, but it doesn’t make sense to have each of these classes inherit from Mixin. Similarly, duplicating the code in each class doesn’t make much sense either. The best approach is to use the augment function to add this method to each class that needs it:
This can be thought of as a way to implement multiple inheritance in JavaScript.
A more robust augment allows copying one or two of them over to another class.
You can now write augment(Author, Mixin, 'serialize'); to only augment Author with the single serialize method.
In other times, you don't have to need this augment function in order to do Mixins. You could do this by using apply or call method inside constructor function.
Often it makes more sense to augment a class with a few methods than it does to make
one class inherit from another. This is a lightweight way to prevent code duplication. Unfortunately, there aren’t many situations where it can be used. Only methods general enough to be used in very dissimilar classes make good candidates for sharing (if the classes aren’t that dissimilar, normal inheritance is often a better choice).
It is possible to do a mixin class in JavaScript as in Ruby. This is another way to make our code reuse without inheritance. Consider you have a function, and you wish to use in many classes. In practice, you create a class that contains your general-purpose methods, and then use it to augment other classes. Class with these general-purpose methods is called Mixin class. It is generally not instantiated or called directly, instead it exists to provide methods to other classes.
var Mixin = function() {};
Mixin.prototype = {
serialize: function() {
var output = [];
for(key in this) {
output.push(key + ': ' + this[key]);
}
return output.join(', ');
}
};
This sort of method could potentially be useful in many different types of classes, but it doesn’t make sense to have each of these classes inherit from Mixin. Similarly, duplicating the code in each class doesn’t make much sense either. The best approach is to use the augment function to add this method to each class that needs it:
augment(Author, Mixin);
var author = new Author('Ross Harmes', ['JavaScript Design Patterns']);
var serializedString = author.serialize();
This can be thought of as a way to implement multiple inheritance in JavaScript.
/* Augment function. */
function augment(receivingClass, givingClass) {
for(methodName in givingClass.prototype) {
if(!receivingClass.prototype[methodName]) {
receivingClass.prototype[methodName] = givingClass.prototype[methodName];
}
}
}
A more robust augment allows copying one or two of them over to another class.
/* Augment function, improved. */
function augment(receivingClass, givingClass) {
if(arguments[2]) { // Only give certain methods.
for(var i = 2, len = arguments.length; i < len; i++) {
receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
}
}
else { // Give all methods.
for(methodName in givingClass.prototype) {
if(!receivingClass.prototype[methodName]) {
receivingClass.prototype[methodName] = givingClass.prototype[methodName];
}
}
}
}
You can now write augment(Author, Mixin, 'serialize'); to only augment Author with the single serialize method.
In other times, you don't have to need this augment function in order to do Mixins. You could do this by using apply or call method inside constructor function.
var Author = function(name, books) {
this.name = name || "";
this.books = books || [];
Mixin.apply(this);
};
Often it makes more sense to augment a class with a few methods than it does to make
one class inherit from another. This is a lightweight way to prevent code duplication. Unfortunately, there aren’t many situations where it can be used. Only methods general enough to be used in very dissimilar classes make good candidates for sharing (if the classes aren’t that dissimilar, normal inheritance is often a better choice).
Labels:
javascript
Prototypal Inheritance vs. Classical Inheritance
While it is possible to emulate classical inheritance like Java or C#, it is clear that we do prototypal inheritance by taking advantages of prototype lookup chains. Each has its own advantages and disadvantages. Here I quoted from JavaScript Design Patterns:
The classical approach to creating an object is to (a) define the structure of the object, using
a class declaration, and (b) instantiate that class to create a new object. Objects created in this
manner have their own copies of all instance attributes, plus a link to the single copy of each
of the instance methods.
In prototypal inheritance, instead of defining the structure through a class, you simply
create an object. This object then gets reused by new objects, thanks to the way that prototype
chain lookups work. It is called the prototype object because it provides a prototype for what the other objects should look like.
Instead of using a constructor function named Person to define the class structure, Person
is now an object literal. It is the prototype object for any other Person-like objects that you want to create. Define all attributes and methods you want these objects to have, and give them
default values.
To create a new Person-like object, use the clone function. This provides an empty object with
the prototype attribute set to the prototype object. This means that if any method or attribute
lookup on this object fails, that lookup will instead look to the prototype object.
To create Author, you make a clone.
Here is the clone function. First the clone function creates a new and empty function, F. It then sets the prototype attribute of F to the prototype object. Lastly, the function creates a new object by calling the new operator on F. The cloned object that is returned is completely empty, except for the prototype attribute, which is (indirectly) pointing to the prototype object, by way of the F object.
In classical inheritance, each instance of Author has its own copy of the books array. You could add to it by writing author1.books.push('New Book Title'). That is not initially possible with the object you created using prototypal inheritance because of the way prototype chaining works. A clone is not a fully independent copy of its prototype object; it is a new empty object with its prototype attribute set to the prototype object. When it is just created, author1.name is actually a link back to the primitive Person.name. When you write to author1.name, you are defining a new attribute directly on the author1 object.
Classical inheritance is well understood, both in JavaScript and the programmer commu-
nity in general. Almost all object-oriented code written in JavaScript uses this paradigm. If you
are creating an API for widespread use, or if there is the possibility that other programmers not
familiar with prototypal inheritance will be working on your code, it is best to go with classical.
JavaScript is the only popular, widely used language that uses prototypal inheritance, so odds
are most people will never have used it before. It can also be confusing to have an object with
links back to its prototype object. Programmers who don’t fully understand prototypal inheri-
tance will think of this as some sort of reverse inheritance, where the parent inherits from its
children. Even though this isn’t the case, it can still be a very confusing topic. But since this
form of classical inheritance is only imitating true class-based inheritance, advanced JavaScript
programmers need to understand how prototypal inheritance truly works at some point any-
way. Some would argue that hiding this fact does more harm than good.
The classical approach to creating an object is to (a) define the structure of the object, using
a class declaration, and (b) instantiate that class to create a new object. Objects created in this
manner have their own copies of all instance attributes, plus a link to the single copy of each
of the instance methods.
In prototypal inheritance, instead of defining the structure through a class, you simply
create an object. This object then gets reused by new objects, thanks to the way that prototype
chain lookups work. It is called the prototype object because it provides a prototype for what the other objects should look like.
Instead of using a constructor function named Person to define the class structure, Person
is now an object literal. It is the prototype object for any other Person-like objects that you want to create. Define all attributes and methods you want these objects to have, and give them
default values.
/* Person Prototype Object. */
var Person = {
name: 'default name',
getName: function() {
return this.name;
}
};
var reader = clone(Person);
alert(reader.getName()); // This will output 'default name'.
reader.name = 'John Smith';
alert(reader.getName()); // This will now output 'John Smith'.
To create a new Person-like object, use the clone function. This provides an empty object with
the prototype attribute set to the prototype object. This means that if any method or attribute
lookup on this object fails, that lookup will instead look to the prototype object.
To create Author, you make a clone.
/* Author Prototype Object. */
var Author = clone(Person);
Author.books = []; // Default value.
Author.getBooks = function() {
return this.books;
}
var author0 = clone(Author);
author0.name = 'Dustin Diaz';
author0.books = ['JavaScript Design Patterns'];
var author1 = clone(Author);
author1.name = 'Ross Harmes';
author1.books = ['JavaScript Design Patterns'];
Here is the clone function. First the clone function creates a new and empty function, F. It then sets the prototype attribute of F to the prototype object. Lastly, the function creates a new object by calling the new operator on F. The cloned object that is returned is completely empty, except for the prototype attribute, which is (indirectly) pointing to the prototype object, by way of the F object.
/* Clone function. */
function clone(object) {
function F() {}
F.prototype = object;
return new F;
}
In classical inheritance, each instance of Author has its own copy of the books array. You could add to it by writing author1.books.push('New Book Title'). That is not initially possible with the object you created using prototypal inheritance because of the way prototype chaining works. A clone is not a fully independent copy of its prototype object; it is a new empty object with its prototype attribute set to the prototype object. When it is just created, author1.name is actually a link back to the primitive Person.name. When you write to author1.name, you are defining a new attribute directly on the author1 object.
var authorClone = clone(Author);
alert(authorClone.name); // Linked to the primative Person.name, which is the
// string 'default name'.
authorClone.name = 'new name'; // A new primative is created and added to the
// authorClone object itself.
alert(authorClone.name); // Now linked to the primative authorClone.name, which
// is the string 'new name'.
authorClone.books.push('new book'); // authorClone.books is linked to the array
// Author.books. We just modified the
// prototype object's default value, and all
// other objects that link to it will now
// have a new default value there.
authorClone.books = []; // A new array is created and added to the authorClone
// object itself.
authorClone.books.push('new book'); // We are now modifying that new array.
Classical inheritance is well understood, both in JavaScript and the programmer commu-
nity in general. Almost all object-oriented code written in JavaScript uses this paradigm. If you
are creating an API for widespread use, or if there is the possibility that other programmers not
familiar with prototypal inheritance will be working on your code, it is best to go with classical.
JavaScript is the only popular, widely used language that uses prototypal inheritance, so odds
are most people will never have used it before. It can also be confusing to have an object with
links back to its prototype object. Programmers who don’t fully understand prototypal inheri-
tance will think of this as some sort of reverse inheritance, where the parent inherits from its
children. Even though this isn’t the case, it can still be a very confusing topic. But since this
form of classical inheritance is only imitating true class-based inheritance, advanced JavaScript
programmers need to understand how prototypal inheritance truly works at some point any-
way. Some would argue that hiding this fact does more harm than good.
Labels:
javascript
Saturday, April 11, 2009
Upload in Gears 0.5
Uploading in Gears is pretty easy since its HttpRequest object supports uploading imagery data. If you want that uploaded file could serve locally (in offline mode), you need to use LocalServer API. Moreover, it is feasible to upload in chunk for large files as well. It involves the use of Blob API as well as good handling on server side. I found two links that is able to achieve this:
http://snippets.dzone.com/posts/show/6175
http://uploadmovietool.appspot.com/. However, I just show a simple implementation both server side script (Rails) and client side script (JavaScript).
Let's start from select a file to upload with the help of Desktop API, openFiles(). You need to pass the callback, and some option attributes like filter and singleFile. After user has selected a file, the callback will be invoked with one parameter that is a File object of that file. Notice that, this file object has two properties: name and blob. Thus, you can use LocalServer API to capture this file by calling captureBlob() and passing blob object, a unique url for accessing this file, and a content type. If you don't provide a content-type, the browser doesn't know how to view this file when it has intercepted by LocalServer. Usually, it will launch a download of this file. Oop! Don't forget to create a localserver object. I assume you understand gears api good enough.
Next, you need to create a HttpRequest object. Then, you do a post to your server side script. You can set some request headers like: 'Content-Disposition', 'Content-Type', and 'Content-Range'. Gears provides an event handler called onprogress. When this event is triggered, you would get ProgressEvent object. This object has 3 properties: total, loaded, and lengthComputable. These 3 properties are useful in updating UI. Last, you need to pass the blob object to send() of HttpRequest object. You can do this by calling getAsBlob() and passing the url that previously called by captureBlob().
In Rails, it is quite easy to handle actually. You just need to extract file name of request header 'HTTP_CONTENT_DISPOSITION'. Then, you perform an OS check to write a file of the whole request body. It is a method called raw_post of request object.
http://snippets.dzone.com/posts/show/6175
http://uploadmovietool.appspot.com/. However, I just show a simple implementation both server side script (Rails) and client side script (JavaScript).
Let's start from select a file to upload with the help of Desktop API, openFiles(). You need to pass the callback, and some option attributes like filter and singleFile. After user has selected a file, the callback will be invoked with one parameter that is a File object of that file. Notice that, this file object has two properties: name and blob. Thus, you can use LocalServer API to capture this file by calling captureBlob() and passing blob object, a unique url for accessing this file, and a content type. If you don't provide a content-type, the browser doesn't know how to view this file when it has intercepted by LocalServer. Usually, it will launch a download of this file. Oop! Don't forget to create a localserver object. I assume you understand gears api good enough.
var desktop = google.gears.factory.create('beta.desktop');
desktop.openFiles(
function(files) {
var file = files[0];
if(!file) return;
//capture file for serving locally
fileName = file.name;
blobStore.captureBlob(file.blob, fileName, "image/JPEG");
},
{ filter: ['.jpg'], singleFile: true }
);
Next, you need to create a HttpRequest object. Then, you do a post to your server side script. You can set some request headers like: 'Content-Disposition', 'Content-Type', and 'Content-Range'. Gears provides an event handler called onprogress. When this event is triggered, you would get ProgressEvent object. This object has 3 properties: total, loaded, and lengthComputable. These 3 properties are useful in updating UI. Last, you need to pass the blob object to send() of HttpRequest object. You can do this by calling getAsBlob() and passing the url that previously called by captureBlob().
function upload() {
var xhrUpload = google.gears.factory.create("beta.httprequest");
xhrUpload.open("POST", '/upload/files');
xhrUpload.setRequestHeader('Content-Disposition', 'attachment; filename="' + fileName + '"');
xhrUpload.setRequestHeader('Content-Type', 'image/JPEG');
xhrUpload.setRequestHeader('Content-Range', 'bytes ' + file.blob.length);
//Update UI
xhrUpload.upload.onprogress = function(progressEvent) {
document.getElementById("status").innerHTML = ((progressEvent.loaded/progressEvent.total)*100).toFixed(0) + "%";
};
xhrUpload.onreadystatechange = function() {
switch(xhrUpload.readyState) {
case 4: //complete
document.getElementById("status").innerHTML = "done";
break;
}
};
xhrUpload.send(blobStore.getAsBlob(fileName));
}
In Rails, it is quite easy to handle actually. You just need to extract file name of request header 'HTTP_CONTENT_DISPOSITION'. Then, you perform an OS check to write a file of the whole request body. It is a method called raw_post of request object.
class UploadController < ApplicationController
def files
path = request.env['HTTP_CONTENT_DISPOSITION'][/^attachment\; filename="([^\"]+)"$/, 1]
if RUBY_PLATFORM.index("win")
File.open("public/images/#{path}", "wb") { |f| f.write(request.raw_post) }
else
File.open("public/images/#{path}", "w") { |f| f.write(request.raw_post) }
end
end
end
Labels:
gears,
javascript,
ruby on rails
Friday, March 27, 2009
Geocoding on Google Maps
Geocoding is the process of converting from address into geographic coordinates which you then can position on the map. It can be accessed directly via an HTTP request or by using a GClientGeocoder object. It is worthwhile to mention two methods of GClientGeocoder object.
1.
2.
geocoding-extraction
geocoding-reverse
Recently, I realized Google has added another information of data returned by this method, ExtendedData which consists of north, east, south, and west of that area. This is quite useful when positioning location on the map with appropriate zoom level. All you have to do, construct a GLatLngBounds object with these data, then call getBoundsZoomLevel() by passing this GLatLngBounds object to determine proper zoom level that fits map view port.
1.
GClientGeocoder.getLatLng(): this method allows you to get location of a specific location by querying google geoserver. You need to pass two arguments, address and a callback function. That callback function is invoked with one parameter, a GLatLng object of that location, when there is a reply from this service. See example here.2.
GClientGeocoder.getLocations(): this method allows you more ability than the previous one by returning a JSON object consisting of the following information: Status (request, code), Placemark (address, AddressDetails, Accuracy, Point, coordinates,...). Moreover, it supports both standard and reverse geocoding. If you pass this method a GLatLng object instead of a String address, the geocoder will perform a reverse lookup and return a structured JSON object of the closest addressable location. See examples:geocoding-extraction
geocoding-reverse
Recently, I realized Google has added another information of data returned by this method, ExtendedData which consists of north, east, south, and west of that area. This is quite useful when positioning location on the map with appropriate zoom level. All you have to do, construct a GLatLngBounds object with these data, then call getBoundsZoomLevel() by passing this GLatLngBounds object to determine proper zoom level that fits map view port.
var getLocation = function(address) {
var geoCoder = new GClientGeocoder();
geoCoder.getLocations(
address,
function(location){
document.getElementById('txtAddressId').value = address;
//if this address is found
if(location.Status.code == 200) {
var placeMark = location.Placemark[0];
var latLngBox = placeMark.ExtendedData.LatLonBox;
//default zoom level is 7
var latlng, zoom = 7;
if(latLngBox) {
//determine zoom level if possible
var latLngBound = new GLatLngBounds(new GLatLng(latLngBox.south, latLngBox.west), new GLatLng(latLngBox.north, latLngBox.east));
zoom = map.getBoundsZoomLevel(latLngBound);
}
latlng = new GLatLng(placeMark.Point.coordinates[1], placeMark.Point.coordinates[0]);
map.setCenter(latlng, zoom);
} else {
alert('Address is not found.');
}
}
);
}
Labels:
google maps api,
javascript
Thursday, March 26, 2009
Load Google Maps Dynamically
Previously, I posted how to load google maps script dynamically for performance reasons. However, when callback function is get called, we could not pass any parameters to this callback, because the callback we passed is the name specified in string.
There is another way if you use multiple APIs from Google, Google AJAX APIs. This framework allows you to load one API key for all supported Google AJAX APIs (including Google Maps) and also provides a common namespace for each API, allowing different Google APIs to operate together. If you decide not to use the Google AJAX API framework, you can continue to use the existing namespace. There is a method from this framework called load() with 2 parameters: moduleName, and callback function. Hence, I could use the same way to load google map except the url to load and call load(). Here is from google documentation.
To solve the previous problem, you could actually add the script tag of Google AJAX APIs, which describes more precisely at http://code.google.com/apis/ajax/documentation/. The Google AJAX APIs <script> tag loads a single method, while google.load() which loads individual AJAX APIs. With this method, you can load any specific Google API on demand.
There is another way if you use multiple APIs from Google, Google AJAX APIs. This framework allows you to load one API key for all supported Google AJAX APIs (including Google Maps) and also provides a common namespace for each API, allowing different Google APIs to operate together. If you decide not to use the Google AJAX API framework, you can continue to use the existing namespace. There is a method from this framework called load() with 2 parameters: moduleName, and callback function. Hence, I could use the same way to load google map except the url to load and call load(). Here is from google documentation.
function mapsLoaded() {
var map = new google.maps.Map2(document.getElementById("map"));
map.setCenter(new google.maps.LatLng(37.4419, -122.1419), 13);
}
function loadMaps() {
google.load("maps", "2", {"callback" : mapsLoaded});
}
function initLoader() {
var script = document.createElement("script");
script.src = "http://www.google.com/jsapi?key=ABCDEFG&callback=loadMaps";
script.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(script);
}
To solve the previous problem, you could actually add the script tag of Google AJAX APIs, which describes more precisely at http://code.google.com/apis/ajax/documentation/. The Google AJAX APIs <script> tag loads a single method, while google.load() which loads individual AJAX APIs. With this method, you can load any specific Google API on demand.
function mapsLoaded() {
var map = new google.maps.Map2(document.getElementById("map"));
map.setCenter(new google.maps.LatLng(37.4419, -122.1419), 13);
}
function loadMaps() {
google.load("maps", "2", {"callback" : mapsLoaded});
}
Labels:
google maps api,
javascript
Tuesday, January 27, 2009
SplitButton and MenuButton
Probably, somebody also experiences difficulties with dealing with SplitButton and MenuButton when you add new items, select an item, replace it with new items. To deal with those items, you need to call getMenu().
1. To clear existing items, call clearContent() of getMenu()
2. To add item(s), call addItem() or addItems(). Remember each item has three properties: "text", "value", and "onclick". After calling this method, you need to call render by passing the container of this button, otherwise it won't appear on the browser.
3. To replace with new data, just combine two previous snippet codes
4. To enable selection when clicking on each item, each item must have onclick property with an object literal as shown below:
1. To clear existing items, call clearContent() of getMenu()
split.getMenu().clearContent();
split.set("label", "Choose One");
2. To add item(s), call addItem() or addItems(). Remember each item has three properties: "text", "value", and "onclick". After calling this method, you need to call render by passing the container of this button, otherwise it won't appear on the browser.
split.getMenu().addItems(splitData);
split.getMenu().render(split.get('container'));
3. To replace with new data, just combine two previous snippet codes
split.getMenu().clearContent();
split.set("label", "Choose One");
split.getMenu().addItems(splitData);
split.getMenu().render(split.get('container'));
4. To enable selection when clicking on each item, each item must have onclick property with an object literal as shown below:
splitData = {
fn: function(type, args, item) {
split_group.set("label", item.cfg.getProperty("text"));
}
}
Labels:
javascript,
yui
Handle DateTime field in Gears
SQLite in Gears supports DATETIME data type, but it works differently from JavaScript context. SQLite only support the following formats as shown on SQLite Date and Time Functions. If you provide invalid format, SQLite will not give an error, but the function call (SQLite DateTime function) will return null, or record could not be inserted/updated. There are two ways to handle this situation.
1. If you don't use ORM JavaScript library such JazzRecord or JStORM, you could make this field an Integer field and call getTime() of JavaScript Date object to store. For displaying data back, you can still sort by ascending/descending order. Pass value that get from getTime() to a constructor of Date object to convert a Date object.
One exception with this is that you can use SQLite DateTime functions when querying back because the format you store is not recognized by SQLite. You have to loop through in JavaScript and an if statement.
2. This way is preferable because it supports full SQLite Date and Time Functions, but it needs some helper method to transform format between SQLite and JavaScript back and forth.
1. If you don't use ORM JavaScript library such JazzRecord or JStORM, you could make this field an Integer field and call getTime() of JavaScript Date object to store. For displaying data back, you can still sort by ascending/descending order. Pass value that get from getTime() to a constructor of Date object to convert a Date object.
var db = google.gears.factory.create('beta.database');
db.open('database-test');
db.execute('create table if not exists Test (Phrase text, Timestamp int)');
//store in db
db.execute('insert into Test values (?, ?)', ['Monkey!', new Date().getTime()]);
var rs = db.execute('select * from Test order by Timestamp desc');
while (rs.isValidRow()) {
//convert to date object
var date = new Date(rs.field(1));
alert(rs.field(0) + '@' + date.getDate() + "/" + (date.getMonth()+1) + "/" + date.getFullYear());
rs.next();
}
rs.close();
One exception with this is that you can use SQLite DateTime functions when querying back because the format you store is not recognized by SQLite. You have to loop through in JavaScript and an if statement.
2. This way is preferable because it supports full SQLite Date and Time Functions, but it needs some helper method to transform format between SQLite and JavaScript back and forth.
var Util = {
fromJSDateToSQLiteDate: function(date) {
var toTwoCharacters = function(number) {
return (number.toString().length == 2) ? number.toString() : '0' + number.toString();
};
var strYear = date.getFullYear();
var strMonth = toTwoCharacters(date.getMonth() + 1);
var strDate = toTwoCharacters(date.getDate());
var strHour = toTwoCharacters(date.getHours());
var strMinute = toTwoCharacters(date.getMinutes());
var strSecond = toTwoCharacters(date.getSeconds());
return strYear + '-' + strMonth + '-' + strDate + ' ' + strHour + ':' + strMinute + ':' + strSecond;
},
fromSQLiteDateToJSDate: function(strDateTime) {
var strDate = strDateTime.split(' ')[0];
var strTime = strDateTime.split(' ')[1];
var arrDate = strDate.split('-');
var arrTime = strTime.split(':');
return new Date(arrDate[0], arrDate[1]-1, arrDate[2], arrTime[0], arrTime[1], arrTime[2]);
}
};
Labels:
gears,
javascript
Friday, January 23, 2009
Refresh DataSource of DataTable
I have been using YUI as a UI framework for my projects recently. I found the documentation of YUI is very bad since it just tells that you do this, you will get this. It doesn't tell why I need to do this, and it still misses some common examples. Most often, I need to check what are methods and properties do this object have.
In order to reset new data when your data have been updated by somewhere, you need to call reset() from getRecordSet() of datatable object. Then, call setRecords() by passing your new data. If you have paginator, you also have to update it by calling setPage() to its current page and reset the total number of record.
In order to reset new data when your data have been updated by somewhere, you need to call reset() from getRecordSet() of datatable object. Then, call setRecords() by passing your new data. If you have paginator, you also have to update it by calling setPage() to its current page and reset the total number of record.
dataTable.getRecordSet().reset();
dataTable.getRecordSet().setRecords(newData);
dataTable.refreshView();
//refresh paginator
dataTable.get("paginator").setPage(dataTable.get("paginator").getCurrentPage());
dataTable.get("paginator").set("totalRecords", dataTable.getRecordSet().getLength());
Labels:
javascript,
yui
Sunday, December 21, 2008
How do you dynamically create a radio button in Javascript that works in all browsers?
Well, another bug from IE is the createElement() method. Unlike other browsers, it works weirdly by setting the default input "type" attribute to "text". Thus, you cannot change the "type" attribute to other value beside "text". Have a look on the documentation of this method from msdn microsoft.
Try the following code in IE by yourself, you might end up with the weird behavior on IE.
To solve this this problem, you need to pass the entire html code of element you want to create to createElement() method.
The following code I quote from http://stackoverflow.com/questions/118693/how-do-you-dynamically-create-a-radio-button-in-javascript-that-works-in-all-br, and it works across all browsers.
Here are some other references:
http://www.quirksmode.org/bugreports/archives/2005/10/Radios_name_attribute_doesnt_work_when_using_appen.html
http://cf-bill.blogspot.com/2006/03/another-ie-gotcha-dynamiclly-created.html
Try the following code in IE by yourself, you might end up with the weird behavior on IE.
var radio = document.createElement("input");
radio.setAttribute("type", "radio");
radio.setAttribute("name", "test_1");
radio.setAttribute("value", "yes, it doesn't work!");
radio.setAttribute("checked", "checked");
To solve this this problem, you need to pass the entire html code of element you want to create to createElement() method.
var radio = document.createElement("<INPUT TYPE='RADIO' NAME='RADIOTEST' VALUE='First Choice'>");
The following code I quote from http://stackoverflow.com/questions/118693/how-do-you-dynamically-create-a-radio-button-in-javascript-that-works-in-all-br, and it works across all browsers.
function createRadioElement( name, checked ) {
var radioInput;
try {
var radioHtml = '<input type="radio" name="' + name + '"';
if ( checked ) {
radioHtml += ' checked="checked"';
}
radioHtml += '/>';
radioInput = document.createElement(radioHtml);
} catch( err ) {
radioInput = document.createElement('input');
radioInput.setAttribute('type', 'radio');
radioInput.setAttribute('name', name);
if ( checked ) {
radioInput.setAttribute('checked', 'checked');
}
}
return radioInput;
}
Here are some other references:
http://www.quirksmode.org/bugreports/archives/2005/10/Radios_name_attribute_doesnt_work_when_using_appen.html
http://cf-bill.blogspot.com/2006/03/another-ie-gotcha-dynamiclly-created.html
Labels:
javascript
Friday, December 19, 2008
JavaScript Frameworks
I have read one page, the comparison of javascript frameworks. It is good to know benefits, drawbacks, and limitations that each brought us back. From my personal experience:
1. MooTools is a compact framework, but it is suitable small web applications. One of the bad things I hate this framework is that it overrides the core javascript object. Even Dom objects has been overridden by MooTools. It has get() method and some other methods.
2. YUI has very bad documentation, but has lots of live functional examples. It has lots of properties, methods, and events. It is hard for the newbies to find a properties he need because the documentation just you do and you get it. It doesn't tell why and how this framework works. Sometimes I need to hook through the code. One the best things of YUI is has good configurator and it is modulus. You can take some functionalities off that are not useful in your web application. It also supports Back button support when you use Ajax Request.
3. ExtJS has two types of licenses: Commercial and GPL. It is good this framework if you build a single web application because it has many web controls look like windows controls. It has a very good documentation in air application and html pages. It has more features than YUI.
4. jQuery is a great JavaScript framework. It has great documentation and let you write less and do more. The size is also small enough. Actually, I like this framework.
5. Prototype & script.aculo.us. I used to work with this. Well, I think using jQuery is better than this.
http://en.wikipedia.org/wiki/Comparison_of_JavaScript_frameworks
1. MooTools is a compact framework, but it is suitable small web applications. One of the bad things I hate this framework is that it overrides the core javascript object. Even Dom objects has been overridden by MooTools. It has get() method and some other methods.
2. YUI has very bad documentation, but has lots of live functional examples. It has lots of properties, methods, and events. It is hard for the newbies to find a properties he need because the documentation just you do and you get it. It doesn't tell why and how this framework works. Sometimes I need to hook through the code. One the best things of YUI is has good configurator and it is modulus. You can take some functionalities off that are not useful in your web application. It also supports Back button support when you use Ajax Request.
3. ExtJS has two types of licenses: Commercial and GPL. It is good this framework if you build a single web application because it has many web controls look like windows controls. It has a very good documentation in air application and html pages. It has more features than YUI.
4. jQuery is a great JavaScript framework. It has great documentation and let you write less and do more. The size is also small enough. Actually, I like this framework.
5. Prototype & script.aculo.us. I used to work with this. Well, I think using jQuery is better than this.
http://en.wikipedia.org/wiki/Comparison_of_JavaScript_frameworks
Labels:
javascript
Friday, October 10, 2008
Javascript MVC
I found two frameworks that allow you to develop application that follows MVC pattern in Javascript.
Personally, I like TrimJunction, a part of TrimPath. Moreover, it supports gears synchronization.
http://javascriptmvc.com/
http://code.google.com/p/trimpath/wiki/TrimJunction
Personally, I like TrimJunction, a part of TrimPath. Moreover, it supports gears synchronization.
http://javascriptmvc.com/
http://code.google.com/p/trimpath/wiki/TrimJunction
Labels:
javascript,
news
Tuesday, October 7, 2008
JSON
JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is based on a subset of the JavaScript Programming Language. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.
JSON is built on two structures:
* A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
* An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.
Go to http://json.org/ to see more. It has a small library that is quite useful for build web 2.0 to convert from json to text and vice versa. This is useful for sending data using json format as data exchange.
JSON is built on two structures:
* A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
* An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.
Go to http://json.org/ to see more. It has a small library that is quite useful for build web 2.0 to convert from json to text and vice versa. This is useful for sending data using json format as data exchange.
Labels:
javascript
Thursday, October 2, 2008
Experimenting Google Maps with Local Files
I found one link, and I just quote it from http://cafe.elharo.com/web/google-maps-tip-1-experimenting-with-local-files/:
As you probably know using Google maps on a web site requires a custom API key that is locked to the web site. For example, my key is ABQIAAAANzhjmjn_aQro8IDfoVHCkxT-n61mIiazNPHwWTk3s75Ar5J1YhQDxyPhUR-O4Nfg_1iRn1pAUseY4g and every page that uses a Google map includes this script element:<script src="http://maps.google.com/maps?file=api&v=1&key=ABQIAAAANzhjmjn_aQro8IDfoVHCkxT-n61mIiazNPHwWTk3s75Ar5J1YhQDxyPhUR-O4Nfg_1iRn1pAUseY4g" type="text/javascript"></script>
I’m not giving away any secret by telling you that. You could figure out the same thing using View Source. However. the key is locked to the web site. If you try using that key on a different site, the map won’t load.
This is all well and good. However it’s very inconvenient for debugging, testing, and experimenting, because you can’t load a map on your local file system. Everything has to be tested on the live Web server. You could probably password proterct a directory to play around in, but what a pain.
It turns out that you can use this script element on your local hard drive:<script src="http://maps.google.com/maps?file=js" type="text/javascript"></script>
Then you can test out and play with Google Maps without loading the file onto the production web server first. Cool!
Labels:
google maps api,
javascript
Friday, September 26, 2008
Phnom Penh Map overlays on Google Maps
I have been too busy lately. I have uploaded a small project (called Oy-Moy) several weeks ago on Google Apps Engine, but I didn't have time to post it in my blog. It is about taking a map (jpeg/png) to overlay on top of Google Maps. Doing this has two ways: one is create a new maptype (GMapType) and another is create a new tilelayer (GTileLayer). The belows are list of links that show how to do this. I found the last link, http://www.bdcc.co.uk/GoogleCrunch/Crunch.htm, is the easiest way to do. It is abit slow because the tile images are too big in size about 132kb per tile. I just download this image somewhere on the internet and try this with google maps api.
http://groups.google.com/group/Google-Maps-API/web/more-info-gtilelayer-gtilelayeroverlay?pli=1
http://code.google.com/apis/maps/documentation/overlays.html#Tile_Overlays
Here is the link of my project: http://oy-moy.appspot.com/
http://groups.google.com/group/Google-Maps-API/web/more-info-gtilelayer-gtilelayeroverlay?pli=1
http://code.google.com/apis/maps/documentation/overlays.html#Tile_Overlays
Here is the link of my project: http://oy-moy.appspot.com/
Labels:
google maps api,
javascript
Monday, September 15, 2008
createDocumentFragment() in Javascript
For some javascript developers like me, I never used and even heard this method createDocumentFragment(). I have learned and read many javascript books (about 10), but most of them didn't mention this method at all. Today, I just encounter this method when I read my existing book on one chapter how to sort table in javascript. I saw the author use this method. This book named "Wrox - Javascript for Web Developers".
"createDocumentFragment()" is basically somewhere to store your newly created nodes before you append them to the document. When you are ready to append all the nodes to the document, all you need to do is one append and they all get added. Creating a fragment is extremely easy.
You now have somewhere to store your new nodes. To add nodes to the fragment, all you need to do is append the childs to the fragment.
After this, call
"createDocumentFragment()" is basically somewhere to store your newly created nodes before you append them to the document. When you are ready to append all the nodes to the document, all you need to do is one append and they all get added. Creating a fragment is extremely easy.
var docFragment = document.createDocumentFragment();
You now have somewhere to store your new nodes. To add nodes to the fragment, all you need to do is append the childs to the fragment.
function myFunction() {
var docFragment = document.createDocumentFragment();
docFragment.appendChild(document.createTextNode("my text node 1"));
docFragment.appendChild(document.createTextNode("my text node 2"));
return docFragment;
}
After this, call
document.body.appendChild(myFunction());
Labels:
javascript
Subscribe to:
Posts (Atom)