Affichage des articles dont le libellé est JavaScript. Afficher tous les articles
Affichage des articles dont le libellé est JavaScript. Afficher tous les articles

Intégrer Google Maps sur un site web

Tout le monde aime Google Maps et ceux qui possèdent un commerce avec pignon sur rue désirent souvent afficher la carte pour indiquer leur localisation. Je vais vous montrer à quel point c'est facile d'intégrer Google Maps et je vous présenterai quelques options intéressantes.

D'abord, il vous faut une clé d'API (gratuite) qui est reliée au domaine sur lequel on veut l'installer (fonctionne aussi sur les sous-domaines et les répertoires).

Une fois en possession de votre clé, vous devrez faire un peu de JavaScript. Incluez en entête la librairie externe de Google Maps en prenant soin d'y placer votre clé d'API.
<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=true&amp;key=VOTRE_CLE" type="text/javascript"></script>
Dans le code HTML, déclarez un conteneur dans lequel la carte s'affichera. Prenez soin d'attacher les fonctions aux événements load et unload (libre à vous de le faire comme ci-dessous ou avec Prototype ou jQuery).
<body onload="initGM()" onunload="GUnload()">
<div id="mapHolder" style="width:800px;height:600px"></div>
</body>
Ouvrez un bloc JavaScript et déclarez les objets principaux :
var map;
var geocoder;
Je prendrai pour acquis qu'on utilisera la carte pour afficher qu'une seule coordonnée. Déclarez deux nouvelles variables qui contiendront les informations à afficher dans la bulle (lorsqu'on cliquera sur le marqueur) :
var title = "La Banquise";
var address = "994, Rue Rachel Est, Montreal, QC H2J 2J3";
Il faut définir la fonction qui initialise la carte au chargement de la page. Quelques lignes seraient suffisantes mais comme je présente quelques options, je commenterai au fur et à mesure dans le code.
function initGM() {
if (GBrowserIsCompatible()) {

// mapHolder est le conteneur HTML
map = new GMap2(document.getElementById("mapHolder"));

// on peut utiliser cette façon mais qui
// connait vraiment les coordonnées ?
// map.setCenter(new GLatLng(37.4419, -122.1419), 13);

// à la place, les trouver avec Geocoder!
geocoder = new GClientGeocoder();

// la variable address a été définie
// plus haut
geocoder.getLocations(address, addToMap);

// constantes du choix de carte
// G_NORMAL_MAP
// G_SATELLITE_MAP
// G_HYBRID_MAP
map.setMapType(G_NORMAL_MAP);

// affiche les contrôles par défaut
// (zoom et types de cartes)
// map.setUIToDefault();

// ou bien, personnaliser les contrôles
// on doit utiliser addControl

var mapTypeControl = new GMapTypeControl();

// positions possibles
// G_ANCHOR_TOP_RIGHT
// G_ANCHOR_TOP_LEFT
// G_ANCHOR_BOTTOM_RIGHT
// G_ANCHOR_BOTTOM_LEFT
var topRight = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10,10));
map.addControl(mapTypeControl, topRight);

// pour le contrôle de zoom
// GSmallMapControl / GLargeMapControl
// GLargeMapControl = la barre verticale
// dégradée
map.addControl(new GSmallMapControl());
}
}
Il ne reste qu'à définir la fonction addToMap() qui contrôle aussi le contenu affiché dans la bulle.
function addToMap(response){
place = response.Placemark[0];

// obtenir la latitude et longitude
point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);

// centrer la carte sur ce point
// 18 représente la profondeur du zoom
map.setCenter(point, 18);

// créer le marqueur
var numberedIcon = new GIcon(G_DEFAULT_ICON);

// permet de changer l'icône par défaut
// par exemple le logo de l'entreprise
// numberedIcon.image = 'http://www.domaine.com/marker.png';
markerOptions = { icon:numberedIcon, clickable:true };
marker = new GMarker(point, markerOptions);

// ajouter le marqueur à la carte
map.addOverlay(marker);

GEvent.addListener(marker, "click",
function() {
var streetAddress = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.Thoroughfare.ThoroughfareName;
var city = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName;
var state = place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName;

marker.openInfoWindowHtml(
'<strong>' + title + '</strong>' + '<br>' + streetAddress + '<br>' + city + ', ' + state);
}
);
}
Ça peut ne pas sembler très clair ce que je fais avec var streetAddress = place.AddressDetails... mais si vous éclatez l'objet "place" avec Firebug (console.log(place)), vous aurez accès à toute la structure de l'objet JSON qui permet de récupérer toutes les informations de géolocalisation sur le point demandé.

Je n'ai pas encore pris le temps de régler l'affichage du code sur mon blogue alors je vous suggère de l'ouvrir en cliquant sur "view plain" dans le coin supérieur gauche des blocs de code pour le voir mieux indenté et sans retour de chariots automatiques.

Vous voilà maintenant avec une carte fonctionnelle.
Continue Reading...

Problème avec le service Google Maps : non disponible

Ce matin, j'étais en train de préparer un article expliquant comment intégrer Google Maps à son site web (avec certaines options) et alors que je testais différentes configurations, le service de Google s'est soudainement interrompu et la carte ne s'affichait plus.

J'ai ouvert Firebug et j'ai vu dans la console deux messages d'erreurs consécutifs : GUnload is not defined et GBrowserIsCompatible is not defined. C'était curieux car j'ai révisé le code source et tout semblait en ordre.

Ensuite, j'ai examiné les headers HTTP (sous l'onglet NET de Firebug), je me suis rendu compte que l'appel à "http://maps.google.com/maps" retournait l'erreur 503 : Service Unavailable.



Pourquoi le service ne serait pas disponible ? Serait-ce une panne ? J'ai ouvert le node (+) GET sorry?continue... pour connaître le détail et les sous-onglets Response et HTML ont pu m'éclairer sur ce qui se passait.

Il semblerait que vu le nombre répété de requêtes vers son service, il ait considéré mes demandes comme étant douteuses. Sous HTML, on peut voir le message suivant :

We're sorry... but your computer or network may be sending automated queries. To protect our users, we can't process your request right now. To continue searching, please type the characters you see below : [captcha].



J'ai fait le test de cliquer avec le bouton droit de la souris sur le lien "GET sorry?continue...", j'ai fait "Open in new tab" pour accéder à la page. J'ai entré le captcha et lorsque je suis retourné sur ma page qui incluait l'appel à Google Maps, le service était à nouveau disponible.

J'ai refait tout le processus pour faire afficher la trace de la création des cookies et il semblerait que dans certains circonstances, Google refuse de créer le cookie GDSESS qui est nécessaire à l'authentification du service de cartographie. Dès que le captcha est correctement remplit, ce cookie est créé et il le service fonctionnera tant et aussi longtemps qu'il existera.
Continue Reading...

Small clouds - Large clouds


So, I attended this seminar recently, in which the usual suspects were paraded in front of a saucer-eyed audience; There was Amazon, Salesforce, local hopes and established players in equal measures. The first presentation was by a Swedish guy named Joakim Lindbom, CTO at Cap Gemini in Sweden - a really sharp guy, by the way.

His talk was about Amazon EC2, and I had heard a lot of it before, but not everything. Joakim focused on the architectural choices that Amazon had made when creating their different services, being an architect himself. He argued successfully the common knowledge that it really isn't possible to scale a relational database to do what Amazon have to do, and that the same apply to services.

In general a cloud-based architecture means that you use a distributed queueing service both to store incoming requests and to communicate between system parts. Yes, a kind of ESB, if you will, but simple!

It also means using schemaless databases that don't mind adding another column even though there's already 1.0E9 items in the table. 

And then it struck me; If it is absolutely critical to use ___SIMPLE___ (meaning non-complex, OK?) services which are both asynchronous (queued, event-driven) and dynamically or non-typed, to be able to build a system over a certain size - why is this not critical when building smaller system?

Or, to phrase the questions differently; How comes it is possible to build systems that does not comply with these traits, since they have been proven to be just critical? Size, is the answer of course.

But to expand that answer is to get to the core of the problem; Smaller sized systems can skimp on doing things right, because it doesn't show up until they get larger. And what small system doesn't?

So, essentially, what has been discovered to be critical in building large-scaled 'cloud' systems is just as essential in building smaller system, it just isn't as evident. Which of course can be translated as saying that it isn't critical. And, no, sure, it isn't critical. But what I'm saying is that even smaller system will by necessity cost less to build, if built according to the same principles the larger-scale system use, if nothing else but the simple fact that they will grow over time.

One of the successes of Erlang has been the reational approach to distributed proecessing; Since interprocess communication in Erlang is message-based, putting those messages on a bus á la Amazon's simple queue service, will be transparent to the processes using it, and also, those very processes need not know where they are and can so be safely dotted out in the cloud somewhere.

Imagine if someone would do that kind of stuff to another cool language, maybe one with first-class and anonymous functions, duck-typing (Simple, 'schemaless'), closures and late binding (i.e. easy to code in), like ... JavaScript? Maybe someone already has? :) 

No wait, nobody has to, right. It usable that way right off the bat. 

Have a nice weekend all y'all.

Cheers,
PS

Continue Reading...

Google Friend Connect finally support signed request

Why is that a big deal?

Here's the short answer; Now you can get the viewer id of a user loading your page and send it back to your server in a trusted way.

Before (up to two weeks ago, when I last tried it) it was only possible to send back info from the web page in an untrusted way.

What I mean by that is that you could load a custom opensocial gadget, which got the viewer id using the opensocial api, and then proceeded to use the opensocial makeRequest() call to route that information back to an url on your server. However, since this information orgiginated in the browser, potentially someone might somehow get a malign script to run on your page (from an ad, perhaps) and make up any old id, to then send back to your server.

In the opensocial specification, there is different modes of makeRequest, of which one is to make a signed request. To describe a signed request, I've drawn a small diagram above. Let's walk through it, and return to the signed request in a little while.

Let's say that you have copied in some Google Friend Connect gadgets on one of your pages, by registering your site with GFC, noting your sites code, and so on, the first thing that happens is that a person going to you site loads your page (1). In your page lies the gfc gadget references, which load the gadgets themselves from the GFC proxy servers (I call them proxies since much of what they do is route information back and forth third parties) (2). If this is the first time the users has been to the site and/or the user have not 'joined' the site on a GC sense, he/she may now proceed to do so (still (2)).

Now you have written your own, custom opensocial gadget, which is also loaded into the page in (2). It probably resides on your server, but could actually be loaded from any server on the internet. That gadget does the following;

a) Get the id of the viewer
b) tell the gfc/opensocial JavaScript api that is loaded to post the data to an url on your server. Two weeks ago, this could only be done without authentication.

This will send the data (viewer id) first to the gfc proxies(3), which will then route it forward to your server (4).
On your server is a special script that parses the post data out from the HTTP request (5).

The only thing that has changed now is that the makeRequest call can use the authentication mode gadgets.io.AuthorizationType.SIGNED, which will result in a 'stamp' made by the gfc proxies as the message passes through them. This is what it looks like in a small PHP script I wrote to collect the incoming signed info;


2009-02-22 12:41:36>---------------------> id=82146293318299142645, nick=psvensson
2009-02-22 12:41:36> post param -- the_user_id -> 32146007816295742145
2009-02-22 12:41:36> post param -- the_user_nickname -> psvensson
2009-02-22 12:41:36> get param -- opensocial_owner_id -> 03600513378691222179
2009-02-22 12:41:36> get param -- opensocial_viewer_id -> 78096296444182405045
2009-02-22 12:41:36> get param -- opensocial_app_id -> 09127246177732455082
2009-02-22 12:41:36> get param -- opensocial_app_url -> http://xxxyyyzzz.com/osaccess.xml
2009-02-22 12:41:36> get param -- xoauth_signature_publickey -> pub.1008283802.-8019269915578004945822.cer
2009-02-22 12:41:36> get param -- oauth_version -> 1.0
2009-02-22 12:41:36> get param -- oauth_timestamp -> 981102302897
2009-02-22 12:41:36> get param -- oauth_consumer_key -> friendconnect.google.com
2009-02-22 12:41:36> get param -- oauth_signature_method -> RSA-SHA1
2009-02-22 12:41:36> get param -- oauth_nonce -> 01831428822001149500
2009-02-22 12:41:36> get param -- oauth_signature -> MviLJcsxuU2tN9hQTkMEqZrEaC7ZUX31Cz7HH17I00vT2q8NJWH28OzvDab1Cl,01YtetX+Yln/IkuTj+I11SzFwZu5aXQda5D9HBeq+zjdxwWfuLGo62AaMjm5lvJGwWrMW6q+vm33MVOFWecxuXzSPmDfsCE9Tyf+b3M=

Numbers and other stuff are messed with a bit, due to posting :) But the thing is that two weeks ago, only the two POST lines were getting though, and any signed request returned and error in th browser.

This is the dawn of maybe not a new era, but a new eralischimo. Now you can use trusted user ids without having to manage the users, changing password, creating capthcas (and keeping up with the bots), listing friends and manage those connections, et.c. Now you just slam a gadget on the page, and get an id back you can trust. Not half bad eh?

Cheers,
PS

[UPDATE]

OK, this is a bit silly. There is more to this than just using signed makeRequests :) The reason I forgot this, is that the magic sauce was something I added in desperation some time ago when I tried to make signed requests work; I added a certificate to my domain using google accounts;

https://www.google.com/accounts/ManageDomains

Where you can upload a x.509 certificate that you can associate with your domain. The process is explained in more detail here;

http://code.google.com/apis/accounts/docs/RegistrationForWebAppsAuto.html

Including how to generate x.509 certs from scratch on Windows and Linux (Maybe mac as well).
Continue Reading...

Using Dojo to implement the 12 standard screen patterns


I really enjoyed reading Theresa Neil's article just recently on the 12 standard screen layout types. She gave a lot of examples, but what I found lacking was some nice templates that could be used if you wanted to jump right in and implement one or two of the patterns. I've been meaning to write a post about Dojo's Layout containers for a while now, so my initial idea was to provide Dojo examples to each of the 12 screen patterns.



As it turns out, not all patterns exist today as plain off-the-shelf examples, I decided to skip some of the patterns, since my blogging time is a bit limited, and just bite the bullets that I can quickly show.

Since we've just concluded that I'm really lazy, It will come as no suprise that I'll just provide links (where possible) to existing Dojo unit tests, that can be copied straight off (possibly changing where the css and js loads from, but I assume you're familiar with such procedures)

1. Master/Detail

[Would be simple to do with StackContainer. I have a releated, flipped example here, which loads html page snippets using Ajax and flip them over 'hypercard'-like when menu selection changes]

2. Column Browse.

There's actually a faily new Dojo widget that provides this 'mac explorer' kind of cuntionality. Data source riven and all. Verry snappy :)

http://download.dojotoolkit.org/current-stable/dojo-release-1.2.3/dojox/widget/tests/test_RollingList.html


3. Search / Results

This pattern is of course the perfect fit for Dojo's DataGrid with filtering queries to the data store from where it draws its contents; Note that the example uses Google's cross-domain JS API to get the data which the grid is filled with;

http://download.dojotoolkit.org/current-stable/dojo-release-1.2.3/dojox/data/demos/demo_GoogleSearchStore_Grid.html

4. Filter DataSet.

This is also a tricky one to find as-is. Several data stores in Dojo support complex queries, and creating a filtering panel that let the user apply filters to the tiems retrieved from the data store is not particlarly hard. Mail me or comment here if you really want an example, and I'll post one later.

5. Form

No worries here. There's forms galore;

http://download.dojotoolkit.org/current-stable/dojo-release-1.2.3/dijit/tests/form/Form.html


6. Palette / Canvas

Due to Dojo's unique cross-browser native 2D api, which detect if it should use SVG, VML, Canvas or Silverlight, there are several other DOjo API's which utilizes this for charting and other things. There'sfor example an excellent Sketching API which support manipulations of SVG files, as well as a related example in the dojox.gfx section. I chose these tests because they both provide a palette / canvas like experience, involving actual graphics. You should also check out openJacob's draw2D if you are the least interested in that kind of stuff :)

7. Dashboard.

This patterns has me a bit confused. Except for the charting / graphing widgets it seems to me to be similar to a form or something. Perhaps an assymetric DataGrid. Let's focus on the charting then. There are several good dojox.charting examples available, all which build on the work of dojox.gfx.

8. Spreadsheet

This is again a prime candidate for DataGrid, depending on whether to implement a real spreadheet or just look a bit like one. No exmaple included.

9. Wizard

OK, there's no widget for this - exactly- though the pattern would be fairly simple to implement. Again, mail or comment if you really want an exact copy of the pattern in Dojo. Meanwhile, here _is_ a Wizard widget, but it only shows one 'scren' of the wizard at any one time;

http://download.dojotoolkit.org/current-stable/dojo-release-1.2.3/dojox/widget/tests/test_Wizard.html

10. Q:A

I'm not really sure I get this one exactly. It is just #1 but over-confident, or what?

11. Parallel Panels

These we've got. and in spades. There's the obvious AccordionContainer, the classical TabContainer, as well as the fully hackable StackContainer.

12. Interactive Model.

This one covers quite a wide area. The emphasis seem to be on graphical interaction, which I'll have to get back to you for, because now it's time for lunch :)

Cheers,
PS
Continue Reading...

What makes Dojo diferent?




Dojo (and also Ext, IIRC) have a couple of semi-unique features, being proper data abstractions in the client layer and extendable, hierarchical widgets systems.

I know Dojo best, so I'll use that as an example;

Data abstraction means a separate API layer between widgets (or other classes) and the actual data. All dojo.data datastores (as they are called) have the same kind of API, but manages access to data differently. For example theres one store called ItemFileReadStore, which just read in a JSON object from an url and provide it as a bag of items to widgets.

Let's say that you use this data store to provide data to a combobox which implements type-ahead (which the Dojo one does). After testing you want to have a more advance data store which only fetches some items at a time (because the amount of data on the server is too large to load at once) and caches it. That means switching to the JsonRestStore, which uses the same API as the first one, et.c.

Here are some good articles that give more meat on dojo.data;

http://www.sitepen.com/blog/2008/06/13/restful-json-dojo-data/




The widget system in Dojo let you define custom widgets and place them on the page, using a single element with special properties. Dojo scans for these elements and look up the widget definition (in a JavaScript file and the HTML template for the widget (pointed out by the JavaScript file).

Dojo then calls special functions in the widget class according to lifecycle events, and also manage unique id creation for html template elements, instantiation of subwidgets, et.c.

Dojo uses this system for all its own widgets internally, and many custom widget projects I do for customers start out with subclassing an existing widget (using Dojo's pseudo- OO). The reason this work so well is that Dojo have proper namespacing, which also correspond (but can be overridden) to directory hierarchies, so class/widget lookup is both straightforward and understandable.

At the moment jQuery have no data abstraction or widget subsystem (unless I've misunderstood jQuery UI completely, in which case I would very much like to be corrected :), and neither have YUI.

Now I've done it again. :) This is my next blog post, apparently.

Cheers,
PS
Continue Reading...

The power of Dojo i18n

I had said at an early stage that I was going to use Dojos i18n system to translate snippets of text in World Change Network. Now that the time came to actually implement it, I realized I had some learning to do to get all bits and pieces right. As it turned out, using Dojos i18n system for you own purposes is really simple.

If you take a look at the unit test for i18n at http://download.dojotoolkit.org/current-stable/dojo-release-1.2.2/dojo/tests/i18n.js you see that it uses three major tricks;

1. Load the i18n strings bundle of your choice using dojo.requireLocalization("tests","salutations",locale);
2. Get a specific bundle using var salutaions = dojo.i18n.getLocalization("tests", "salutations", "en");
3. Get the specific string for a given key using salutations['hello'];

Let's check the arguments for number (1) and (2; Only the first two are needed, which describe the dojo package to look for bundles in and the name of the bundle. If you want to specify another locale than the one the browser declares, it can be added as third argument, "sv" for Swedish, when the browser would say "en-us", et.c.

All well and good, but where do we put our different version of strings? As it turns out, in the dojo/test directory a directory named 'nls' can be found. In the root of that is a file called 'salutations.js'. This is the default key-value translation that i18n falls back on if the locale cannot be found.

Then comes a host of subdirectories ; zh, nl, il, dk, de, et.c et.c., one for each locale (that you want or can define). In each of these is a separate 'salutations.js' containing locale-specific resources.

The file format look like this;

{
it: "Italian",
ja: "Japanese",
ko: "Korean",
......
hello: "Hello",
dojo: "Dojo",
hello_dojo: "${hello}, ${dojo}!",
file_not_found:"The file you requested, ${0}, is not found."
}

for the default file, and like this in the 'it' subdirectory;

{
it: "italiano",
hello: "Ciao"
}

And that's it.

I began creating a small naive custom widget, which subtituted the content of the element where it is declared with the localized string found for the content used as key. It's not very fast, but simple to understand and use.

dojo.provide("layout.translate");

dojo.require("dijit._Templated");
dojo.require("dijit._Widget");
dojo.require("dojo.i18n");

dojo.declare("layout.translate", [ dijit._Widget ],
{
widgetsInTemplate : false,
string : "",

postCreate: function()
{
if (!this.string)
{
this.string = this.domNode.innerHTML;
}
console.log("postCreate for layout.translate called. locale == '"+dojo.locale+"'");
dojo.requireLocalization("layout", "salutations");
var res = dojo.i18n.getLocalization("layout", "salutations");
console.log("Translation key was '"+this.string+"'");
var str = res[this.string];
this.domNode.innerHTML = str;
}

});

Note that I just copied the whole nls directory from dojo/test for my own uses, and edited the files, leaving the original filename intact, just in case :) A better way of utilizing i18n would be to have a base class for all custom widgets, which read in a i18n bundle, and injects all keys into each class, so that every subclass has a lot of this._i18n_command_delete (If we have a naming convention that let all i18n keys begin with '_i18n_' for example).

Then we could have all custom widget templates just sprinkle their markup with a lot of ${_i18n_command_delete} and so on, which would pull in the current value of that 'this' property of the widget when it is rendered in the page.

Hmm....

Come to think of it, it seems to be possible for this to be put inside dijit._Widget, or possibly _Templated, which would make it spread to all custom widgets automatically. The only thing needed would be to prepend '_i18n_' to all key names, so that 'command_delete' inside a bundle file would become this_i18n_command_delete in the widget.

One would also need to have a convention that this only worked if the developer put a 'nls' directory under the package directory where widgets of a certain package are declared, following the order declared earlier.

Actually, this would be a pretty neat idea. Just my fault for using a blog post instead of TRAC to add feature requests! Oh, you mean I could do it myself? OK, I'll add it to the queue :)

Cheers,
PS




Continue Reading...

lala moulati ana9a maghribia

seo

 

Blogroll

Site Info

Text

telechargementz Copyright © 2009 WoodMag is Designed by Ipietoon for Free Blogger Template