lundi 6 mai 2013

WinJS : ouvrir une url dans le navigateur du système

Aujourd’hui c’est une toute petite astuce que je vous propose, puisqu’elle tient en 2 lignes de code. Mais comme à chaque fois que j’ai besoin de ces 2 lignes, je cherche sur Google, je me suis dit que j’allais le mettre ici, histoire de savoir où le trouver la prochaine fois.

Donc le problème : comment on fait en WinJS pour ouvrir une url dans le navigateur ? La réponse se trouve sur ce blog, et la doc sur msdn. Il suffit d’utiliser le Launcher adéquat.

var uri = new Windows.Foundation.Uri('http://www.yoururl.com/');
Windows.System.Launcher.launchUriAsync(uri);





Notez qu’ici on utilise LaunchUriAsync pour ouvrir le navigateur, mais d’autres applications peuvent être démarrées ; par exemple un éditeur d’image pour une uri associée à une image, ou une autre de vos applications présente sur le store.



Par contre, vous n’avez aucune visibilité sur ce que votre utilisateur fera une fois le launcher démarré : il peut utiliser une autre application que celle que vous lui recommandez, c’est son droit. Faites-y attention.



Pour plus de détails, la doc est toujours là !

jeudi 14 février 2013

Arrêtons avec le browser-sniffing !

En tant qu’utilisateur d’Opera*, ça fait un petit moment que j’ai envie de parler de ce sujet, et l’annonce récente de l’abandon du moteur Presto par mon navigateur fétiche m’a enfin décidé à écrire cet article.

Le “browser-sniffing”, pour ceux qui ne savent pas ce que c’est, consiste à activer ou désactiver des fonctionnalités d’un site web en fonction du user-agent du navigateur. Mais avant de voir pourquoi c’est si mal de faire ça, nous allons faire un peu d’histoire.

Petit historique des user-agents

Le “user-agent” d’un navigateur est une chaine de caractères, qui est incluse dans l’en-tête de chaque requête HTTP effectuée. Ceci permets de fournir diverses informations sur le navigateur, la version, la langue…

Le user-agent “Opera/8.50 (Windows NT 5.1; U; en)” par exemple, représente le navigateur Opera, en version 8.5, qui tourne sous Windows XP, et installé en anglais (le “U” ne veut plus rien dire).

Remontons un peu dans le temps. À l’origine, il y avait Mosaic, le premier navigateur web devenu populaire. Il se faisait appeler à l’époque tout simplement “NCSA_Mosaic/2.0 (Windows 3.1)”.
Puis est arrivé Mozilla (“Mozilla/1.0 (Win3.1)”), rapidement renommé en Netscape, mais qui n’a pas changé de user-agent. Très vite, Netscape s’est mis en avant avec un meilleur support du html que son concurrent, à l’époque où les “frames” devenaient populaires. Vu que Mosaic ne supportait pas les frames, les développeurs ont commencé à différencier les navigateurs : c’est le début du browser sniffing : si le navigateur est Mozilla, il a droit aux frames, sinon il a une version light du site.

Ensuite est arrivé Internet Explorer (“Microsoft Internet Explorer/4.0b1 (Windows 95)”), et les ennuis commencent : Microsoft a fait un navigateur qui supporte les frames, mais son nom n’étant pas “Mozilla”, de nombreux sites web refusaient d’envoyer le site complet, quand ils ne bloquaient pas totalement l’accès.
La solution pour Microsoft : se déguiser en Mozilla. Dès la seconde version du navigateur, le user-agent est devenu “Mozilla/1.22 (compatible; MSIE 2.0; Windows 95)”, ce qui signifie un navigateur “compatible mozilla”, et dont le vrai nom MSIE, se trouve plus loin.
Et ceci dure toujours, le user agent de la dernière version d’Internet Explorer se présente toujours comme “Mozilla compatible” : “Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; Touch)

Sautons quelques années pour voir un autre cas intéressant : Opera 9.64.
Opera*, le seul navigateur à avoir les cojones de se présenter sous son vrai nom (:D), affichait fièrement un “Opera/9.64 (Windows NT 5.1; U; en) Presto/2.1.1”. Certains sites, ne voyant pas la compatibilité Mozilla dans le user-agent, étaient dégradés (donnant une mauvaise image totalement injustifiée au navigateur), mais globalement ça marchait quand même plutôt bien.
Puis Opera est devenu le premier navigateur à passer en version 10, dont les versions beta s’identifiaient en tant que “Opera/10”. Et là, de gros soucis sont de nouveau apparus : beaucoup de site se sont retrouvés cassés sur cette version, car les serveurs vérifiaient le navigateur (Opera), et le premier caractère de la version. Les serveurs web ne se sont pas étonnés de voir une vieille version “1” revenir à la mode et se sont contentés de bloquer ces versions.
Ce user-agent n’a donc pas passé la beta, depuis la version 10, Opera indique être “Opera/9.80”.

Je pense que vous commencez à comprendre le problème.

Pourquoi le browser-sniffing c’est mal

J’en viens donc au point de mon article : le browser-sniffing doit cesser. Il est toujours tentant de vérifier quel navigateur on a en face, pour lui renvoyer un rendu correct, mais ce n’est pas la bonne solution. Réfléchissons, comment pouvons nous reconnaitre à coup sûr le navigateur ?

  • On va lire son nom et sa version dans le user-agent.
    Non, vous avez bien vu juste au dessus, ce n’est pas comme ça que vous aurez les bonnes valeurs. D’une version à l’autre le nom du navigateur ou son numéro de version peut se retrouver à des emplacements différents. Le user-agent n’est pas standardisé, vous ne pourrez pas retrouver toutes les valeurs possibles comme ça.
  • On peut faire une base de données des user-agents
    Vous pouvez essayer, vous n’y arriverez pas. Avec les différents navigateurs, les différents OS, et les navigateurs mobiles (qui souvent incluent aussi le modèle du téléphone et le nom de l’opérateur de téléphonie), les combinaisons sont infinies. Et ça impliquerait de rester à jour

De plus, revenons au cas d’Opera* : dans sa version 12, il utilise le moteur de rendu Presto, la prochaine version utilisera WebKit, avec forcément des différences (certaines fonctionnalités qui n’étaient pas supportés le seront, mais inversement, peut-être certaines supportées par Presto ne le sont pas par WebKit). Si vous faites aujourd’hui des règles spécifiques à Opera, vous allez devoir les mettre à jour pour la prochaine version. Et qui sait si d’autres navigateurs ne feront pas la même chose dans les prochains mois ?

Si vous ne me croyez toujours pas

Il suffit de faire une recherche Google :

image

Les premiers résultats sont dans l’ordre:

  • la page Wikipedia (avec un paragraphe qui en décrit les problèmes)
  • 3 articles qui disent qu’il ne faut pas l’utiliser
  • Les documentations de Dojo et jQuery sur les fonctionnalités de sniffing ; les deux commencent par expliquer qu’il faut éviter de l’utiliser.

Voilà, j’espère vous avoir convaincu de ne plus utiliser cette méthode pour le développement de vos sites.

Avant de nous quitter, je vous laisse les quelques liens qui m’ont aidé à la rédaction de cet article, et je vous dit à très bientôt !

Sources :

http://my.opera.com/ODIN/blog/300-million-users-and-move-to-webkit
http://fr.wikipedia.org/wiki/User-Agent
http://webaim.org/blog/user-agent-string-history/
http://whatsmyuseragent.com/

 

* Je vous assure, ce billet n’est pas sponsorisé par Opera, promis ! :-)

mardi 22 janvier 2013

WinJS : problèmes pouvant survenir avec les listes groupées

J’ai eu des bugs sur mes applications WinJS, et je me suis dit que j’allais partager avec vous, parce que vous savez, j’aime bien partager (et puis ça fait plus de 6 mois que j’ai pas blogué, y’a des gens qui risquent de s’inquiéter).

Donc j’ai trouvé 2 bugs, les 2 en rapports avec des listes groupées.

1 – SemanticZoom : “Object doesn't support property or method 'itemFromDescription'”

Si vous ne connaissez pas le principe du SemanticZoom, c’est tout simple. Vous avez deux vues : une liste d’éléments, affichés par groupe, et une liste n’affichant que les groupes. À l’utilisation, vous avez votre liste d’éléments, vous faites un zoom arrière (en pinçant les doigts, ou Ctrl+molette) et la liste des groupes apparait. Lorsque vous cliquez sur un groupe vous repassez sur la liste d’éléments, avec le groupe cliqué affiché. C’est le fonctionnement du start menu de Windows 8.

En mettant en place mon contrôle SemanticZoom, j’ai donc eu l’exception suivante : “Object doesn't support property or method 'itemFromDescription'”, dont la description ne fournit absolument aucun détail sur l’origine du bug.

Après investigation, j’ai donc trouvé que l’origine venait des identifiants du groupe : ils étaient de type entier. Et ça, le SemanticZoom, il aime pas.

La solution : utiliser des Strings.

var bindingList = new WinJS.Binding.List().createGrouped(
function(item) { return item.group.id.toString(); },
function(item) { return item.group; });

2 – Liste groupée et filtrée : “Unable to get property 'id' of undefined or null reference”

Une fois que j’ai réussi à gérer ma liste groupée, j’ai voulu ajouter un filtre. Au lieu d’afficher tous mes items, je décider de n’afficher que mes items favoris.

Pour ça, je peux créer une binding list filtrée, de la manière suivante, en me basant sur la liste précédente.

var bindingList = new WinJS.Binding.List().createGrouped(
    function(item) { return item.group.id.toString(); },
    function(item) { return item.group; }
);

var filteredList = bindingList.createFiltered(
    function(item) { return item.isFavorite; }
);

Et là, encore une fois, j’ai une exception : “Unable to get property 'id' of undefined or null reference”. Et encore une fois, l’erreur est très explicite. Comme ce n’est pas le message de l’exception qui va vous aider, je vous dis de suite ce qu’il s’est passé :

En créant la liste, la binding list a récupéré la liste des groupes, en fonction des items présents. Puis lorsque le filtre a été appliqué, on s’est retrouvé avec des groupes vides. Et là paf, exception.

La solution : inverser les appels à createGrouped et createFiltered :

var filteredList = new WinJS.Binding.List().createFiltered( function(item){return item.isFavorite;});
var groupedList = filteredList.createGrouped(
    function(item) { return item.group.id.toString(); },
    function(item) { return item.group; }
);

Ainsi, les groupes sont calculés à partir de la liste déjà filtrée, et tout fonctionne !

vendredi 24 août 2012

Utiliser le Live SDK dans une application Windows 8 “ModernUI” javascript

Microsoft fourni depuis quelques temps une API pour se connecter aux services Live, depuis tout type d’applications : Desktop, mobile, ou web. Cette API permet d’utiliser depuis vos applications les services de Skydrive, Messenger et Hotmail.

Nous allons voir dans cet article comment se connecter à Windows Live depuis une application Windows 8 Javascript pour pouvoir utiliser ces services.

Enregistrement de l’application

La première chose à faire est d’enregistrer l’application pour qu’elle ait le droit d’accéder au service. Il suffit d’aller sur le site suivant et de suivre les indications : https://manage.dev.live.com/build

Le site vous donnera un nouveau “Package name” que vous devrez mettre dans le fichier package.appxmanifest :

image

Ceci vous permettra d’utiliser les services Live lors du développement.

Lorsque vous voudrez publier votre application sur le Windows Store, il faudra remettre à jour cette valeur. Pour ça, vous devez créer l’application dans votre Dashboard Windows 8.
Puis dans Visual Studio, dans “Project” > “Store” > “Associate App with the Store”, vous pourrez faire l’association.

image

Sachez aussi que si vous utilisez ces services, vous devrez spécifier des conditions de service, et une déclaration de confidentialité : 2 liens à enregistrer dans les fonctionnalités avancées de votre application, dans le Dashboard du Windows Store.

Installation du SDK

La première chose à faire est de télécharger et d’installer le SDK Live, puis de le référencer dans le projet :

image

Ensuite, il faudra référencer le SDK dans vos pages :

<script src="/LiveSDKHTML/js/wl.js"></script>



Connexion



Pour pouvoir se connecter, il faut commencer par initialiser les API, à l’aide de la méthode WL.init, qu’on va définir en lui donnant le scope : les données à laquelle on veut accéder dans notre application. C’est important, car lorsque on se connectera avec le compte de l’utilisateur, une fenêtre lui demandera d’accéder à son compte live, avec la liste des données à laquelle on demande à accéder.



WL.init({
scope: ["wl.signin"]
});



Contrairement à une application web, nous n’avons pas besoin ici de fournir d’identifiant d’application, puisqu’il est fourni automatiquement par le SDK lui même, l’application est reconnue par le package name, qu’on a défini précédemment.



On peut maintenant se connecter pour de bon à Live. Pour ça, 2 possibilités : soit l’affichage d’un bouton pour l’utilisateur, soit une connexion automatique par code.



Pour créer un bouton, on va utiliser la méthode WL.ui. On a besoin d’un conteneur dans le HTML :



<div id="signin"></div>



Et on fait l’appel à la méthode pour faire apparaitre le bouton :



WL.ui({
name: "signin",
element: "signin"
});



Ceci va nous donner le bouton suivant :



image


On peut aussi de connecter automatiquement en javascript en utilisant la méthode WL.login:



WL.login();



Dans les deux cas une fenêtre s’affichera pour demander l’autorisation à l’utilisateur d’utiliser son compte.



image




Utilisation de l’API



Maintenant que vous vous êtes connecté et que l’utilisateur vous a donné les droits d’accéder à son compte live, vous pouvez utiliser l’API REST.



Si par exemple on veut récupérer le nom et le prénom de l’utilisateur, ça se fera de la manière suivante :



WL.api({
path: "me",
method: "GET"
}).then(
function (response) {
// Les information sont contenues dans l'objet response :
// response.first_name, response.last_name
},
function (responseFailed) {
// En cas d'erreur
}
);



Ici on fait un appel au chemin “me” de l’API. En fait, la requête est faite sur l’url https://apis.live.net/v5.0/me. Lorsque la réponse arrive, on traite le résultat (à l’aide de la méthode then) avec une fonction pour traiter la réponse, et une fonction appelée en cas d’erreur.



Voilà, à partir de là on a tout ce qu’il faut pour commencer à utiliser toutes les fonctionnalités de l’API live dans l’application. A bientôt (j’espère) sur ce blog pour voir plus en détail ce qu’on va pouvoir faire de ça. En attendant, rendez-vous sur msdn si vous voulez approfondir le sujet.

lundi 16 avril 2012

Nouvel article : Le dév Windows 8, avec HTML5 et Javascript

Je commence aujourd’hui une série d’articles sur le développement d’applications Metro en HTML5 et Javascript. Je découvre le développement sous Windows 8 en faisant l’application TGS (version tablette de l’application existant déjà sur Windows Phone), et j’en profite pour écrire une série d’articles au fur et à mesure de mon avancement.

Pourquoi HTML5 et Javascript ?

Vous le savez peut-être déjà si vous avez suivi les annonces concernant Windows 8 : les applications Metro pourront être développées en utilisant plusieurs langages :

  • Soit XAML, comme en ont l’habitude les développeurs Silverlight et WPF
  • Soit en utilisant HTML5 et Javascript

Il m’a donc fallu faire un choix, qui s’est porté sur la seconde option principalement pour une raison : l’application va afficher du contenu html téléchargé depuis un web service. Lorsqu’on veut faire ça dans une application XAML (comme je l’ai fait en Windows Phone), on est obligé de customiser un contrôle WebBrowser, qui malgré tout nos efforts ne pourra jamais s’intégrer parfaitement au reste de l’application (le scroll et le zoom dans le browser sont gérés indépendamment du reste de l’application). Dans une application HTML5, on n’a pas besoin d’un conteneur spécial, le code html téléchargé s’intègre naturellement dans l’application.

Si en terme de fonctionnalités, HTML5 et XAML sont équivalents, il va nous falloir apprendre une nouvelle syntaxe pour réaliser les opérations courantes, et c’est ce que nous allons voir ensemble, en commençant dans ce premier article par l’utilisation basique des contrôles WinRT.

L’article est disponible sur le site Labs de Bewise : Ma première application Metro/Javascript. Partie 1 : les contrôles

lundi 20 février 2012

Mon nouveau site web en HTML 5

Bonjour tout le monde !

Pas d’article technique aujourd’hui, je veux juste vous présenter mon nouveau site en HTML 5. J’ai essayé de faire un portage HTML5/CSS3/Javascript du nouveau menu démarrer de Windows (j’avoue, j’ai pris quelques libertés sur les couleurs et les animations) ; et franchement, je me suis fait plaisir.

Pour les curieux, vous pouvez faire un petit tour dans le code source pour voir de quoi ça a l’air (attention, vous avez le droit de regarder,ça veut pas dire que vous avez le droit de tout pomper Clignement d'œil)

Pour le voir, c’est par là : Guillaume Lacasa

mardi 23 août 2011

WP7 : “Unspecified error” lorsqu’on modifie un template, depuis la mise à jour Mango

J’ai eu une erreur dans un de mes projets WP7 lors du passage au SDK 7.1 (Mango), sur un code qui fonctionnait très bien avec le SDK 7.0, avec un message d’erreur très précis, comme on les aime :

image

Evidemment, pas moyen de trouver la moindre personne sur le net ayant déjà rencontré (et corrigé) l’erreur (quelqu’un a finalement posé la question sur StackOverflow ce week-end, ayant déjà trouvé la réponse entre temps j’espère lui avoir été utile).

J’ai donc investigué pour trouver l’origine de ce bug, qui venait d’une Listbox, dont les templates des items avaient été redéfinis :

<ListBox  x:Name="lstUsers">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ContentControl x:Name="ContentContainer"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Foreground="{TemplateBinding Foreground}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>





La solution : il faut définir la propriété TargetType sur le ControlTemplate :

<ControlTemplate TargetType="ListBoxItem">




<ListBox  x:Name="lstUsers">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentControl x:Name="ContentContainer"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Foreground="{TemplateBinding Foreground}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>





Maintenant ça fonctionne aussi bien avec l’ancien qu’avec le nouveau SDK :)