Angular, Google Maps autocomplete and geocoder

Voici  un module avec quelques  directives AngularJS  a utiliser avec Google Map V3 . Bien sur il existe un module complet mais aussi complexe avec AngularUI .Ici l avantage te la simplicité et la possibilité de modifier ce code a votre besoin.

La première directive est pour afficher la carte google : on peut lui passer plusieurs paramètres comme la liste des markers , le centre, les coordonnée géographique ...

<div ng-map style="height:400px;margin:12px;box-shadow:0 3px 25px black;"
        center="{ lat: 40, lon: -73 }"
        markers="[]"
 geo-coord="mapcoord"
 ></div>
La deuxième directive est le geoCoder qui consiste a chercher une adresse et l afficher sur la carte

<div class="input-append text-right"
             ng-geocoder
             ng-model="address"
             geo-coord="mapcoord">
</div>
La troisième directive est AddressAutocomplete  qui  procure une assistance a la saisie  des adresses et remplit un formulaire automatiquement .


<form class="form-horizontal" role="form">
   <div class="form-group">
   <label class="control-label col-sm-2 " for="email">Saisir adresse:</label>
   <div  class="col-sm-10">
 <input type="email" class="form-control" ng-model="fullAddress" 
    ng-address-autocomplete  
    street-name="streetName"
    city="city"
    zip-code="zipCode"
    country="country"
    street-number="streetNumber" />
   </div>
   </div>
    <br/> 
   <div class="form-group">
    <label class="control-label  " for="email">Numero:</label>
    <div>
    <input type="text" class="form-control" ng-model="streetNumber"/>
    </div>
    </div> 
    <br/>
    <div class="form-group">
     <label class="control-label  " for="email">Rue:</label>
     <div>
      <input type="text" class="form-control" ng-model="streetName"/>
     </div>
     </div> 
     <br/> 
     <div class="form-group">
     <label class="control-label  " for="email">Ville:</label>
     <div>
     <input type="text" class="form-control" ng-model="city"/>
     </div>
     </div> 
      <br/>
      <div class="form-group">
      <label class="control-label  " for="email">Code postal:</label>
      <div>
     <input type="text" class="form-control" ng-model="zipCode"/>
     </div>
     </div>
     <br/> 
     <div class="form-group">
       <label class="control-label  " for="email">Pays:</label>
     <div>
      <input type="text" class="form-control" ng-model="country"/>
    </div>
    </div> 
   </form>
Voici l exemple complet : Plunker
 <!DOCTYPE html>
<html   id='ng-app'  >
<head>
<link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css">

     
</head>

<body  ng-app="app" ng-controller="appCtrl">
 <h3 class="text-center">   Angular, Google Maps autocomplete and geocoder </h3>
<div class="text-center">
        <div class="input-append text-right" ng-geocoder ng-model="address" geo-coord="mapcoord">
        </div>
    </div>
     

    <!-- map -->
    <div ng-map style="height:400px;margin:12px;box-shadow:0 3px 25px black;"
        center="{ lat: 40, lon: -73 }"
        markers="[]"
  map="myMap"
  geo-coord="mapcoord"
    > 
    </div>
  <br/> <br/>
  
 <form class="form-horizontal" role="form">
  <div class="form-group">
  <label class="control-label col-sm-2 " for="email">Saisir adresse:</label>
  <div  class="col-sm-10">
   <input type="email" class="form-control" ng-model="fullAddress"  
         ng-address-autocomplete   
         street-name="streetName" 
         city="city"
         zip-code="zipCode"
         country="country"
         street-number="streetNumber" />
  </div>
  </div>
  <br/>  
  <div class="form-group">
  <label class="control-label  " for="email">Numero:</label>
  <div>
   <input type="text" class="form-control" ng-model="streetNumber"/> 
  </div>
  </div>  
  <br/>
  <div class="form-group">
  <label class="control-label  " for="email">Rue:</label>
  <div>
   <input type="text" class="form-control" ng-model="streetName"/> 
  </div>
  </div>  
  <br/> 
  <div class="form-group">
  <label class="control-label  " for="email">Ville:</label>
  <div>
   <input type="text" class="form-control" ng-model="city"/> 
  </div>
  </div>   
   <br/>
   <div class="form-group">
  <label class="control-label  " for="email">Code postal:</label>
  <div>
   <input type="text" class="form-control" ng-model="zipCode"/> 
  </div>
  </div>
  <br/>  
   <div class="form-group">
  <label class="control-label  " for="email">Pays:</label>
  <div>
   <input type="text" class="form-control" ng-model="country"/> 
  </div>
  </div> 
   </form>
  
     

     
</body>
<script src="http://maps.googleapis.com/maps/api/js?key=&sensor=false&extension=.js&libraries=places"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.16/angular.min.js"></script>

 <script>
 
 angular.module("ngMapModule", [])
  .directive("ngMap", function ($timeout) {
    return {
        restrict: "EA",
        replace: true,
        template: "<div></div>",
        scope: {
      geoCoord:"=",
            center: "=",        //{latitude: 10, longitude: 10 } .
            markers: "=",       //[{ lat: 10, lon: 10, name: "sName" }] .
            zoom: "@",          //(1  zoomed out, 25  zoomed in).
            mapTypeId: "@",     //(roadmap, satellite, hybrid, terrain).
            panControl: "@",    //show a pan control on the map.
            zoomControl: "@",   //show a zoom control on the map.
            scaleControl: "@"   //show scale control on the map.
        },
  controller:function($scope){
  $scope.updateMap=function(elem) {
                var options =getOptions();
                $scope.map = new google.maps.Map(elem, options);
                $scope.updateMarkers();
                google.maps.event.addListener($scope.map, 'center_changed', function () {
                    if ($scope.initCenter) clearTimeout($scope.initCenter);
                    $scope.initCenter = $timeout(function () {
                        if ($scope.center) {
                            if ($scope.map.center.lat() != $scope.center.lat ||
                                $scope.map.center.lng() != $scope.center.lon) {
                                $scope.center = { lat: $scope.map.center.lat(), lon: $scope.map.center.lng() };
                                if (!$scope.$$phase) $scope.$apply("center");
                            }
                        }
                    }, 500);
                });
            }
  $scope.updateMarkers=function() {
                if ($scope.map && $scope.markers) {
                    if ($scope.currentMarkers != null) {
                        for (var i = 0; i < $scope.currentMarkers.length; i++) {
                            $scope.currentMarkers[i] = m.setMap(null);
                        }
                    }
                    $scope.currentMarkers = [];
                    var markers = $scope.markers;
                    if (angular.isString(markers)) markers = $scope.$eval($scope.markers);
                    for (var i = 0; i < markers.length; i++) {
                        var m = markers[i];
                        var loc = new google.maps.LatLng(m.lat, m.lon);
                        var mm = new google.maps.Marker({ position: loc, map: $scope.map, title: m.name });
                        $scope.currentMarkers.push(mm);
                    }
                }
            }
  $scope.getLocation=function(loc) {
                if (loc == null) return new google.maps.LatLng(40, -73);
                if (angular.isString(loc)) loc = $scope.$eval(loc);
                return new google.maps.LatLng(loc.lat, loc.lon);
            }
  function getOptions() {
    var options =
       {
        center: new google.maps.LatLng(40, -73),
        zoom: 6,
        mapTypeId: "roadmap"
       };
    if ($scope.center) options.center = $scope.getLocation($scope.center);
    if ($scope.zoom) options.zoom = $scope.zoom / 1;
    if ($scope.mapTypeId) options.mapTypeId = $scope.mapTypeId;
    if ($scope.panControl) options.panControl = $scope.panControl;
    if ($scope.zoomControl) options.zoomControl = $scope.zoomControl;
    if ($scope.scaleControl) options.scaleControl = $scope.scaleControl;
    return options;
   }
  },
        link: function (scope, element, attrs) {
            var scopeArray = ["markers", "mapTypeId", "panControl", "zoomControl", "scaleControl"],toCenter  ;
            for (var i = 0, cnt = scopeArray.length; i < scopeArray.length; i++) {
                scope.$watch(scopeArray[i], function () {
                    cnt--;
                    if (cnt <= 0) {
                        scope.updateMap(element[0] );
                    }
                });
            }
            scope.$watch("zoom", function () {
                if (scope.map && scope.zoom)
                    scope.map.setZoom(scope.zoom / 1);
            });
            scope.$watch("center", function () {
                if (scope.map && scope.center)
                    scope.map.setCenter(scope.getLocation(scope.center));
            });
   scope.$watch("geoCoord", function (val) {
                if (val){
    var coord=new google.maps.LatLng(val.lat, val.lon);
    scope.map.setCenter(coord);
    scope.map.setZoom(12);
    }
                    
            });
   
        }
    };
}).directive("ngGeocoder", function () {
    return {
        restrict: "EA",
  template: '<input   type="text"  ng-model="ngModel" style="width:500px"/>'+
            '<button class="btn" type="button" ng-click="geoCode()" ng-disabled="address.length == 0" title="address" >'+
              '&nbsp;<i class="icon-search"></i></button>',
        scope: {
      ngModel:"=",
   geoCoord:"="
           },
  controller:function($scope){
       
   $scope.geoCode = function () {
    if ($scope.ngModel && $scope.ngModel.length > 0) {
     if (!$scope.geocoder) $scope.geocoder = new google.maps.Geocoder();
     $scope.geocoder.geocode({ 'address': $scope.ngModel }, function (results, status) {
      if (status == google.maps.GeocoderStatus.OK) {
       var location = results[0].geometry.location;
       if (!$scope.$$phase) $scope.$apply(function(){
       $scope.geoCoord={ lat: location.lat(), lon: location.lng() }
       $scope.ngModel = results[0].formatted_address;
       });
       
        
      } else {
       alert("Sorry,  address produced no results.");
      }
     });
    }
   };
   
   
  },
  link: function (scope, element, attrs) {
  
  
  }
  }
 }).directive("ngAddressAutocomplete", function () {
    return {
        restrict: "EA",
        scope: {
      ngModel:"=",
      city:"=",
      zipCode:"=",
      country:"=",
   streetName:"=",
   streetNumber:"="
           },
  link: function (scope, element, attrs) {
   var autocomplete = new google.maps.places.Autocomplete(element[0]);
   google.maps.event.addListener(autocomplete, 'place_changed', function() {  
   var place = autocomplete.getPlace();  
    
   if (!scope.$$phase) scope.$apply(function(){
     var componenents=place.address_components||[];
     for(var i=0;i<componenents.length;i++){
      var item=componenents[i];
      if(item&&item.types){
         if(/route/gi.test(item.types[0])){
         scope.streetName =componenents[1].long_name;
         }
         if(/country/gi.test(item.types[0])){
         scope.country =item.long_name;
         }
         if(/street_number/gi.test(item.types[0])){
         scope.streetNumber =item.long_name;
         }
         if(/postal_code/gi.test(item.types[0])){
         scope.zipCode =item.long_name;
         }
         if(/dministrative_area_level_2|city/gi.test(item.types[0])){
         scope.city =item.long_name;
         }
        }
     }
   });
      
   })
  }
  }
 })
 var app = angular.module("app", ["ngMapModule"]);
     app.controller("appCtrl", function ($scope) {
  
  $scope.mapcoord
});
 </script>
</body>
Voir aussi sur Plunker

Gestion des Performance d'une application Le cube de mise a l'échelle d'une ou Application Cube of scale

           De nos jours les applications sont souvent conçues pour répondre a une grande charge d'utilisation et pour manipuler une masse importante de de données. Ajoute a cela des exigences de performance de plus en plus croissantes.
Pour répondre a ces exigences du point de vue architecture, développement et reploiement d'application, parfois on se demande par quel bout commencer vu que les latences dans une application peuvent être a tous les niveaux:

  • Les performances au niveaux du code lui même 
  • La charge due a l'utilisation croissante 
  • La masse et l’accès aux données.
  • La volumétries des données 
  • Les latences réseaux 
  • Et bien d'autres ...
Pour être un peu machiavélique, diviser pour régner on peut repartir cette situation sur trois axes :

  1. L'axe des X : La charge d’utilisation : combien de serveurs sont nécessaires pour répondre a la charge.
  2. L'axes des Y : Le code et l'architecture de l application répondent ils au besoin ou doit on repartir la'application sur plusieurs services et petites sous application.
  3. L'axe des Y  : Les données combien de serveurs faut-il pour répondre a la charge combien de clusters , combien de shardes ....

Si on représente ces trois points sur un axe on obtient ce que on appel le cube de mise en échelle qui nous renseigne sur les direction a prendre pour la mise a l echelle

                              


Optimisation des Performances dans une application ASP.NET

Introduction

L'Optimisation des performances d'une application d'entreprise reste un domaine large. Les latences peuvent être détectés a tous les niveaux de l'application sinon du système complet .Dans ce billet je vais signaler quelques pratiques et même habitudes a prendre lors du développement d'une application Web en général et d'une application ASP.NET Webform ou MVC . On s’intéresse généralement aux performances d'une application lorsque celle ci  devient complexe et grossit , a ce moment la on entame un travail de refactoring et d’investigation pour trouver le coupable qui ralentit ou qui empêche le système de bien fonctionner. A l inverse il est de bonne pratique de considérer les performances dès le début du projet et a tout les niveaux architecture, développement, données ... Pour commencer cette série de billets dédiées aux performances des applications .NET , je vais commencer par la partie Web et principalement quelques conseils pour optimiser le chargement des ressources html/JS/CSS, la configuration ASP.NET et le server IIS .


Optimisation du chargement de la page Web

Le temps de chargement de la page web est précieux, Selon les études de Google les utilisateurs abandonnent la page si elle ne se charge pas dans moins de 5 secondes. Voici quelques astuces pour optimiser le chargement de la page :
  Réduire le nombre requêtes HTTP : 80% du temps de chargement d'une page web se passe sur le navigateur et principalement pour télécharger les script, images , css ...
- Combiner et minifier les fichier JavaScript et CSS.
- Utiliser les CSS sprites : Minifier les images et utiliser les propriétés background-image et packground-position pour affichage
- Utiliser Les images enligne : Utiliser la propriété src="data: ...."  ce qui vas augmenter la taille du fichier HTML mais réduit le nombre de requêtes HTTP
- Utiliser les CDN : Certains fichier statiques comme les librairie JS, CSS et même certaines images  de préférence de les mettre sur un CDN comme ça ils seront cache par le navigateur .
Ajouter les entêtes d'expiration : Pour le contenu statique utiliser "Never expire". Pour le contenu dynamique mettre le Cache-Control approprié.
- Utiliser la compression GZIP  : La compression réduit la taille et le contenu de la réponse HTTP
- Les CSS dans l entête de la page
- Les JavaScript dans le bas de la page HTML 
- Eviter les expression CSS : color:expression(....
- Si possible mettre les contenus statiques  externes a l'application
- Eviter la redirection de page  
- Eviter la duplication des scripts sur la même page
- Utiliser le paramètre  Etag.
- Faire en sorte que même les requêtes Ajax soient cachées
- De préférence d’utiliser les appels GET par Ajax
- Charger que le contenu nécessaire a la page
- Réduire la taille du DOM sur la page
- Réduire le nombre de iframe sur la page
- Réduire la taille des cookies
- Utiliser la balise <link> non la directive CSS @import 
- Si possible moins de 25k pour un fichier statique : Iphone  limite le cache à 25k
- Eviter les attribut src vides : Cela fait un appel server malgré.


Optimisation de la configuration ASP.NET

Process Model : ASP.NET est configuré par défaut dans le fichier machine.config  dans lequel est configuré le Process Model d'ASP.NET
 <system.web> 
     < processModel autoConfig =" true" > 
Cette configuration  doit être retouchée pour des besoins précis  pour specifier le nombre de thread ,le nombre de requêtes ... Voici toute la configuration pour le Porcess Model :
<processModel
enable="true" timeout="Infinite" idleTimeout="Infinite" shutdownTimeout="00:00:05" requestLimit="Infinite" requestQueueLimit="5000" restartQueueLimit="10" memoryLimit="60" webGarden="false" cpuMask="0xffffffff" userName="machine" password="AutoGenerate" logLevel="Errors" clientConnectedCheck="00:00:05" comAuthenticationLevel="Connect" comImpersonationLevel="Impersonate" responseDeadlockInterval="00:03:00" responseRestartDeadlockInterval="00:03:00" autoConfig="false" maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="40" minIoThreads="30" serverErrorMessageFile="" pingFrequency="Infinite" pingTimeout="Infinite" asyncOption="20" maxAppDomains="2000" />
Le cache server : a Défaut d'avoir une solution de cache server dédiée  utiliser le cache ASP.NET
Optimiser le pipline ASP.NET : ASP.NET par defaut charge certain module comme la session l authentication...  voici la liste de certains modules chargées das ASP.NET  qui sont configurés dans le fichier machine.config

  
  
  
  
  
  
  
  


on peut déjà enlever certains modules qui sont rarement utilisés mais qui consomme du temps et des ressources .

        
         
         
         
         
         

Optimisation  lors du développement : dans certains cas on remarque que l application ASP.NET est lente a compiler et a se charger après chaque compilation voici quelques astuce pour améliorer ça :
    Configurer Appool comme Suspend et AlwaysRunning 
iis1
Optimiser le temps de compilation dans Visual Studio
vs1
Configurer l'optimisation de la compilation : dans Web.config


Certaines astuces pour réduire le temps de démarrage de l application :
Enlever les projets non utilisées dans l'application. Utiliser Razor Generator  pour la près compilation : Razor Genaration peut etre installe comme  un package Nuget et le configurer par la suite dans les fichiers .csproj

 Conclusion

Voila pour cette fois ci quelques astuces a prendre en compte dès le début des développements dans un prochain Billet je reviendrai en détails sur les optimisations du code et la maniéré de tester les performances d'une application plus loin je parlerai aussi de manière  générale sur les performances d'une application .NET Web

internet Explorer IE version and navigator (browser) infos :Javascript

Voici une petite fonction qui vous permet de recuperer les informations du navigateur


function getBrowserInfo(index,regs){
 var index=index||0;
 var regs=regs||["(chrome)\/(\\S+)",
                 "(firefox)\/(\\S+)",
                 "(MSIE) (\\S+);",
                 "(opera)\/.*?version\/(\\S+)",
                 "(opera)\/(\\S+)",
                 "version\/(\\S+).*?(Safari)\/"
                ] ;
 var brower;
 try{
   if(index < regs.length){
     var match=new RegExp(regs[index],"gi").exec(navigator.userAgent);
     if(!match)throw "";
     brower={
            name : match[1],
            longVersion:match[2],
            version:parseFloat(match[2]),
         documentMode:document["documentMode"]
          }
     }
 }catch(e){
   brower=getBrowserInfo(++index,regs);
 }
 return brower;
}


Utilser cette fonction comme ce ci

var browerInfo=getBrowserInfo();


// Voici quelques tests et resultats 
// sur chrome 
//browerInfo={name:"Chrome",version:"29",longVersion:"29.0.1547.66",documentMode:undefined}
// sur firefox
//browerInfo={name:"Firefox",version:"19",longVersion:"19.0",documentMode:undefined}
// sur IE
//browerInfo={name:"MSIE",version:"8",longVersion:"8.0",documentMode:8}



Voila

AngularJS MVVM application structure without loading all controllers at once. Structure d une application AngularJS sans charger tous les controllers

Dans cette exercice on créera un exemple d'application AngularJS sans charger tous les controllers.

Habituellement dans une application AngularJs les controllers de toutes les pages sont chargés des la première page
Ce qui constitue une charge et une lenteur de chargement pour la page d accueil . Une autre autre architecture existe pour charger les controllers de chaque vue au fur de l eau .

Commençons par creer une application AngularJS qui aura une structure de fichier comme suit :
--Partials ----- View1.html
----- View1.html
--Libs
------ angular.js
------ jquery.js
-- Directives
-- Services
-- Filters
-- Factories
-- Controllers
-- index.html
-- app.js
et voici le contenu de la page index.html

<html ng-app="testApp">
  <head>
    <script type="text/javascript" src="jquery.min.js"></script>
    <script type="text/javascript" src="angular.js"></script>
    
  </head>
  <body>
    <div>
	   <h3>heading</h3>
	   <a href="#/">view1</a>
	  <a href="#/view2">view2</a>
	</div>
	
     <div ng-view></div>
	  <script type="text/javascript" src="app.js"></script>
  </body>
</html>

Ici comme on le voit seule le fichier app.js est charge dans la page index.html Voyons maintenant le contenu de app.js :
  angular.module('testApp', [])
  .config(['$routeProvider',
  function($routeProvider) {
    $routeProvider
      .when('/view2', {
      templateUrl: 'partials/view2.html'
    }) .otherwise({
       templateUrl: 'partials/view1.html'
    });
	}])

On déclare deux deux vues partielles associées qui sont liées par les deux liens hypertextes dans index.html .

Examinons maintenant le contenu d une vue partielle:
view1.html

 <script>
//@ sourceURL=http://localhost:8082/dynamicScript.js 
//cette ligne est pour le debugger de chrome
function view1Ctrl($scope){
 $scope.test="view1 Message";
}
</script>
<div ng-controller="view1Ctrl">
{{test}}
</div>
Dans cette vue on distingue le script en ligne qui nous sert directement de controller de la vue et la vue elle meme qui est intégrée

view2.html

 <script>
//@ sourceURL=http://localhost:8082/dynamicScript.js 
//cette ligne est pour le debugger de chrome
function view2Ctrl($scope){
 $scope.test="view2 Message";
}
</script>
<div ng-controller="view2Ctrl">
{{test}}
</div>
Dans cette vue on distingue egalement le script en ligne qui nous sert directement de controller de la vue et la vue elle meme qui est intégrée

Exécuter maintenant l exemple et on verra que la page web s affiche comme prévu

Panneau /fenêtre flottante en bas a droite Javascript JQuery floating/sliding bottom right panel

Voila un Widget a ceux qui cherche une fenêtre ou un panneau en bas a droite . ce qui ressemble aux notifications de Windows .
Ca consiste en un DIV conteneur positionner en FIXED et la position right a 0 bottom à 0 aussi
pour que ca soit coller en bas a droite dans le conteneur il y a la barre des titre qui se compose d un titre et d'un bouton puis le contenu lui même

Avec JQuery on gère les évènements le clique sur le bouton
on appel la méthode slideToggle pour cacher et afficher le contenu
Et voilà on obtient un widget intéressant
voici le code de la page HTML

<DOCTYPE html>
<html>

  <head lang="fr-FR">

    <meta charset="utf-8">
    <title>floating/sliding bottom right panel </title>
      <script src="http://code.jquery.com/jquery-1.8.3.js"></script>
   <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.0/themes/redmond/jquery-ui.css"/>
 
  <style>
  
 #container {
  width: 220px;
  position: fixed;
  bottom: 0;
  right:0;
  border:1px solid #AAA;
 }

 .ui-clearfx {
  padding: .1em 1em;
 }

 #content {
  display: none;
  padding: 10px;
 }
 #header{
  margin: 0;
  border-bottom: 0;
  padding: .6em .2em 0.2em .2em;
 }
 #button{
  float:right
 } 
  </style>
  <script>
  $(function() {
   $("#button").click(function(e){
         $("#button>span")
   .toggleClass("ui-icon-circle-triangle-n")
   .toggleClass("ui-icon-circle-triangle-s");
        $("#content").slideToggle("slow");
        e.preventDefault();
  return false;
    });
  });
  </script>
   </head>
  <body>
    <div id="container" class="ui-widget-content ui-corner-top">
            <div id="header" class="ui-widget-content ui-widget-header ui-tabs-nav">
     <span class=" ui-corner-top ui-clearfx">Ici un titre<span>
     <a href="#" id="button" class="ui-button ui-widget ui-state-default ui-corner-all">
        <span class="ui-button-icon-primary ui-icon ui-icon-circle-triangle-n">
    </span>
     </a>  
   </div>
            <div id="content" class="ui-widget-content" >
                <p> 
    ici le texte <br/>
    ici le texte <br/>
    ici le texte <br/>
    ici le texte <br/>
    ici le texte <br/>
    ici le texte <br/>
    ici le texte <br/>
    </p>
            </div>
        </div>
    
    
  </body>
  
</html>

Démo et code source

première lettre en majuscule JQuery - JavaScript uppercase first letter

Un petit casse tete parfois , lors de l insertion dans un DOM ou simplement pour afficher un texte ou paragraphe :
On a recours a la mise en majuscule automatique de la première lettre .

Bien sure si le texte est sur une page Web on passe directement par la propriété CSS text-transforme
comme cette exemple :

slector{

  text-transform : capitalize;
}


Dans ce cas l’élément vise par ce style aura la première lettre en majuscule mais a l affichage seulement ,
car si on récupère sa valeur texte et on l affiche ailleurs on verra que le texte n est pas transformé .

   

  alert($("selector").text() ) 
  // affiche le text non transformé 

Enfin voila une fonction javascript qui permet de mettre en majuscule la première lettre

   

  function capitalize( str){
   return str.replace(/^(.{1})(.*)$/,function(m,c,d){
                                        return c.toUpperCase()+d;
   });