Monday, October 24, 2016

Sticky notes in your webpage...

Sticky notes are a good way to keep things noted such as "To Do Lists". There are many ways we can have sticky notes in a desktop or notebook. But if we have a portal or a website and needed to provide this facility, we have a good JQuery plug in.

http://postitall.txusko.com/plugin.html

You may find there is a Chrome plugin too but what you need is the JQuery one. Download it and add it to your project. After that, provide relevant references.
 <!-- CSS -->  
 <link rel="stylesheet" href="dist/jquery.postitall.css">  
 <!-- JS -->  
 <script src="libs/jquery/dist/jquery.min.js"></script>  
 <script src="dist/jquery.postitall.js"></script>  

You also may find some plug ins such as JQuery draggabletrumbowyg editor and minicolors for color picker.

You can find relevant examples and "How to" in the documentation here.

Now let's see how we can use this in our own website with more features.

 function addPersonalNote() {  
   var p = jQuery.noConflict();  // to avoid multiple JQuery references
   p.PostItAll.new({  //create new note
     content: 'Default content to show',  //
     id: 0,  // this has to be unique 
     posX: $(window).width() / 2,  // center of the page
     posY: '10',  //top of the page
     features: { addNew: false },  // adding new upon another is prohibited
     onCreated: function (id, options, obj) { return undefined; },  //fires at the creation time
     onChange: function (id) {  return undefined;  },  // fires when content is changed
     onSelect: function (id) { return undefined; },  // fires when selected
     onDelete: function (id) { return undefined; }  // fires when deleted
   });  
 }  

This is a simple way of adding a new note. The function "addPersonalNote()" creates a new sticky note as below.

 You can maximize it, minimize or even close it. or even can add new icons too. Also you can have the option to change the color through color picker too.



In our next part, we will talk about how to save this in the database. Until that, practice what we have done so far...

Happy Coding... :)

Monday, September 26, 2016

Using Google MAPs to show your store locations - Part 3 (Final)

Referring to part 1 and 2 (previous posts), today let's discuss how a fully dynamic store locator's are shown in Google Maps.

If you didn't read,
Refer Part 1 Here.
Refer Part 2 Here.

Step 1. Create a Google Map Developer Account and obtain a key. (See Part 1 for details)
Step 2. Add references to your page.

 <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />  
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js" type="text/javascript"></script>  
   <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"  
     type="text/javascript"></script>  
   <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" />  
   <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB7Mg6XsXVsRdEOIA3sAM0CmVq03R_Y9kc"  
     type="text/javascript"></script>  
   <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js" type="text/javascript"></script>  

Step 3. Add HTML for map canvas and store list. (Bootstrap is used )

 <div id="wrapper">  
     <div id="google_map">  
       <div id="map_canvas" style="min-height: 768px;">  
       </div>  
     </div>  
     <div>  
       <div id="over_map" class="postcodeSearch">  
         <div class="row">  
           <div class="col-lg-12">  
             <div class="PCHeader">  
               Trouvez Votre Hyperburo  
             </div>  
           </div>  
         </div>  
         <hr />  
         <div class="row">  
           <div class="col-lg-9 geolocate-me">  
             <i class="fa fa-chevron-right" aria-hidden="true"></i>Par géolocalisation</div>  
           <div class="col-lg-3 text-right">  
             <button class="btn btn-danger btn-sm" type="button" title="Geolocate me" onclick="geolocateme();">  
               <i class="fa fa-crosshairs" aria-hidden="true"></i>  
             </button>  
           </div>  
         </div>  
         <hr class="hr-devide" />  
         <div class="row">  
           <div class="col-lg-12">  
             <i class="fa fa-chevron-right" aria-hidden="true"></i>Par département ou code postal  
           </div>  
         </div>  
         <hr class="hr-devide" />  
         <div class="row">  
           <div class="col-lg-12">  
             <div class="input-group">  
               <input id="txtadPostCode" class="form-control" type="text"  
                 placeholder="Ex: 750001"></input>  
               <span class="input-group-btn">  
                 <button id="btnGoToPostCode" type="button" class="btn btn-danger" onclick="GoToPostCode();">  
                   <i class="fa fa-hand-o-right" aria-hidden="true"></i>  
                 </button>  
               </span>  
             </div>  
           </div>  
         </div>          
       </div>  
     </div>      
     <hr class="hr-devide" />  
     <div id="over_map_corp" class="postcodeSearch">  
       <div id="divCorpList" class="divCorpList">  
       </div>  
     </div>  
   </div>  

Step 4. Add a class that has all the properties of the store locations including address details.

 public class CorporateLocation  
   {  
     public int idCorporate { get; set; }  
     public string lbCorporate { get; set; }  
     public int idAddress { get; set; }  
     public string coMapCoordinate { get; set; }  
     public string Latitude { get; set; }  
     public string Longitude { get; set; }  
     public string adLine1 { get; set; }  
     public string adLine2 { get; set; }  
     public string adLine3 { get; set; }  
     public string adRegion { get; set; }  
     public string adPostCode { get; set; }  
     public string coCountry { get; set; }  
     public string lbCountry { get; set; }  
     public string adPhone { get; set; }  
     public string adFax { get; set; }  
     public string lbDomain { get; set; }  
   }  

coMapCoordinate has the latitude and longitude together separated by a comma.
Ex: 6.926610,79.896203

Step 5. Create your procedure that returns the list of store location result.

 CREATE PROCEDURE dbo.CorporateLocationSel (  
 @LatitudeFrom vcMax,  
 @LatitudeTo vcMax,  
 @LongitudeFrom vcMax,  
 @LongitudeTo vcMax,  
 @adPostCode vcPostCode = NULL)  
 AS  
 .........  

If the postcode is sent to the procedure, it should look the store location table that matches to the postcode and return the list.

Else you need to filter the store locations based on latitude and longitude. For that you need to do some calculations based on user's current geolocation. Do it inside your stored procedure and return the list. For example, see the below query.

 SELECT  
           idCorporate,            
           lbCorporate,  
           idAddress,  
           coMapCoordinate,  
           Latitude,  
           Longitude,  
           adLine1,  
           adLine2,  
           adLine3,  
           adRegion,  
           adPostCode,  
           coCountry,  
           lbCountry,  
           adPhone,  
           adFax,  
           lbDomain  
       FROM (SELECT  
           c.idCorporate,            
           c.lbCorporate,  
           ad.idAddress,  
           ad.coMapCoordinate,  
           SUBSTRING(ad.coMapCoordinate, 1, CASE CHARINDEX(',', ad.coMapCoordinate)  
            WHEN 0 THEN LEN(ad.coMapCoordinate)  
            ELSE CHARINDEX(',', ad.coMapCoordinate) - 1  
           END) AS 'Latitude',  
           SUBSTRING(ad.coMapCoordinate, CASE CHARINDEX(',', ad.coMapCoordinate)  
            WHEN 0 THEN LEN(ad.coMapCoordinate) + 1  
            ELSE CHARINDEX(',', ad.coMapCoordinate) + 1  
           END, 1000) AS 'Longitude',  
           ISNULL(ad.adLine1, '') AS adLine1,  
           ISNULL(ad.adLine2, '') AS adLine2,  
           ISNULL(ad.adLine3, '') AS adLine3,  
           ad.adCity,  
           ISNULL(ad.adRegion, '') AS adRegion,  
           ad.adPostCode,  
           ad.coCountry,  
           cn.lbCountry,  
           ISNULL(c.adPhone, '') AS adPhone,  
           ISNULL(c.adFax, '') AS adFax,  
           ISNULL(dns.lbDomain, '') AS lbDomain  
       FROM dbo.cstCorporate AS c  
       INNER JOIN dbo.gblAddress AS ad  
           ON c.idInvoiceAddress = ad.idAddress            
       JOIN dbo.gblCountry cn  
           ON ad.coCountry = cn.coCountry  
       LEFT JOIN dbo.cmcDns dns  
           ON dns.idCorporateLocal = c.idCorporate) Address  
 WHERE Latitude BETWEEN @LatitudeFrom AND @LatitudeTo  
 AND Longitude BETWEEN @LongitudeFrom AND @LongitudeTo  

The @LatitudeFrom, @LatitudeTo, @LongitudeFrom, @LongitudeTo are 4 parameters that we used with min and max values of latitude and longitude sent from web method that contains the user's current location.

Always better to keep a 1 degree difference between min and max values of latitude and longitude where the diameter of the area could equal to 111 kms. (Each degree of latitude is approximately 69 miles (111 kilometers) apart.)

Step 6. Add a web method that returns a serialized list of store location objects.

 [WebMethod]  
   public static string GetLocations(decimal Latitude, decimal Longitude, string adPostCode)  
   {  
     var clList = new cbCorporateLocation().SelStoreLocation(Latitude, Longitude, adPostCode);  
     JavaScriptSerializer Serializer = new JavaScriptSerializer();  
     return Serializer.Serialize(clList);  
   }  

Step 7. In your Business Logic Layer, you can define the min and max latitude / longitude values.

 public List<CorporateLocation> SelCorporateLocation(decimal Latitude, decimal Longitude, string adPostCode)  
     {  
       decimal LaUpper = Latitude + new decimal(0.5);  
       decimal LaLower = Latitude - new decimal(0.5);  
       decimal LoUpper = Longitude + new decimal(0.5);  
       decimal LoLower = Longitude - new decimal(0.5);  
       if (adPostCode == "0")  
         adPostCode = null;  
 ......... continue your method ...  

Step 8. Now you have the list of stores and you need to show them on Google Map. For that you have a bit of JavaScript works to do. Here I customize the map window for a custom theme. Look at the below JS functions.

 <script type="text/javascript">  
           //common function : get query string parameter values   
     function getParameterByName(name, url) {  
       if (!url) url = window.location.href;  
       name = name.replace(/[\[\]]/g, "\\$&");  
       var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),  
             results = regex.exec(url);  
       if (!results) return null;  
       if (!results[2]) return '';  
       return decodeURIComponent(results[2].replace(/\+/g, " "));  
     }  
           //common function : if the returned url does not have http; add it here  
     function addhttp(url) {  
       if (!/^(f|ht)tps?:\/\//i.test(url)) {  
         url = "http://" + url;  
       }  
       return url;  
     }  
           // use JQuery ready function   
     $(document).ready(function () {  
       $("#over_map").draggable(); //make the post code search box draggable  
       $("#over_map_corp").draggable(); //make the store list box draggable  
       $("#over_map").hide(); //hide the post code search box until map is loaded  
       $("#over_map_corp").hide(); //hide the store list box until map is loaded  
       var adPostCode = getParameterByName('adPostCode'); //get url parameter [postcode]  
       $("#txtadPostCode").val(adPostCode); //append to textbox  
       getLocation(adPostCode);  
     });  
           // get locations and draw them on map  
     function GetLocations(Latitude, Longitude, adPostCode) {  
       var objPara = {  
         Latitude: Latitude,  
         Longitude: Longitude,  
         adPostCode: adPostCode  
       };  
       $.ajax({  
         type: "POST",  
         url: "Default.aspx/GetLocations",  
         data: JSON.stringify(objPara),  
         contentType: "application/json; charset=utf-8",  
         dataType: "json",  
         success: function (msg) {  
           var ret = JSON.parse(msg.d);  
           var LaFrom = 0;  
           var LaTo = 0;  
           var LoFrom = 0;  
           var LoTo = 0;  
                          //this each will get the median values of latitude and longitude of returned values  
           $.each(ret, function (i, val) {  
             if (LaFrom == 0)  
               LaFrom = val.Latitude;  
             else {  
               if (val.Latitude < LaFrom)  
                 LaFrom = val.Latitude;  
             }  
             if (LaTo == 0)  
               LaTo = val.Latitude;  
             else {  
               if (val.Latitude > LaTo)  
                 LaTo = val.Latitude;  
             }  
             if (LoFrom == 0)  
               LoFrom = val.Longitude;  
             else {  
               if (val.Longitude < LoFrom)  
                 LoFrom = val.Longitude;  
             }  
             if (LoTo == 0)  
               LoTo = val.Longitude;  
             else {  
               if (val.Longitude > LoTo)  
                 LoTo = val.Longitude;  
             }  
           });  
           var la = (parseFloat(LaFrom) + parseFloat(LaTo)) / 2;  
           var lo = (parseFloat(LoFrom) + parseFloat(LoTo)) / 2;  
           if (la != 0 && lo != 0) {  
             Latitude = la;  
             Longitude = lo;  
           }  
                          // map with ceter values and zoom  
           var map = new google.maps.Map(document.getElementById('map_canvas'),  
           {  
             zoom: 10,  
             center: new google.maps.LatLng(Latitude, Longitude),  
             mapTypeId: google.maps.MapTypeId.ROADMAP  
           });  
                          //if post code is sent, change the zoom value  
           if (!adPostCode)  
             map.setZoom(10);  
           else  
             map.setZoom(8);  
           var infowindow = new google.maps.InfoWindow({ pixelOffset: new google.maps.Size(-10, 10) });  
           var marker, i;  
           var corpList = "";  
           $.each(ret, function (i, val) {  
             marker = new google.maps.Marker(  
             {  
               position: new google.maps.LatLng(val.Latitude, val.Longitude),  
               map: map,  
               icon: '2.png' //custom icon  
             });  
             var address = '';  
             if (val.adLine1.length > 0)  
               address += val.adLine1;  
             if (val.adLine2.length > 0)  
               address += val.adLine2;  
             if (val.adLine3.length > 0)  
               address += val.adLine3;  
             var postcode = '';  
             if (val.adPostCode.length > 0)  
               postcode += '<br/>' + val.adPostCode;  
             var country = '';  
             if (val.lbCountry.length > 0)  
               country += '<br/>' + val.lbCountry;  
             var phone = '';  
             if (val.adPhone.length > 0)  
               phone += '<br/> Phone : ' + val.adPhone;  
             var fax = '';  
             if (val.adFax.length > 0)  
               fax += '<br/> Fax : ' + val.adFax;  
             var lbDomain = '';  
             if (val.lbDomain.length > 0)  
               lbDomain += '<div class="iw-link" onclick="fnGoToResellerSite(\'' + val.lbDomain + '\')" title=' + val.lbDomain + '> Voir la fiche </div>';  
             var divId = "div" + val.idCorporate;  
             corpList += '<div class="row" id=' + divId + ' ><div class="col-lg-12"><div class="panel panel-red"><div class="panel-heading"><i class="fa fa-map-marker" aria-hidden="true"></i> ' + capitalizeFirstLetter(val.lbCorporate) + '</div><div class="panel-body">' + capitalizeFirstLetter(address) + postcode + capitalizeFirstLetter(country) + '</div></div></div></div>';  
                               //the infowindow content to show the store location when clicked  
             var contentString = '<div id="iw_content"><div id="iw-container">' +  
                       '<div class="iw-title">' + val.lbCorporate + '</div>' +  
                       '<div class="iw-content">' +  
                        '<div class="iw-address">' + address + postcode + country + '</div>' +  
                        '<div class="iw-contact">' + phone + fax + '</div>' +  
                        lbDomain +  
                       '</div>' +  
                       '</div></div>';  
                               // add click event to map                           
             google.maps.event.addListener(marker, 'click', (function (marker, i) {  
               return function () {  
                 infowindow.setContent(contentString);  
                 infowindow.pixelOffset = new google.maps.Size(-10, 10);  
                 infowindow.open(map, marker);  
                                         //DRAWING THE InfoWindow  
                 // Reference to the DIV that wraps the bottom of infowindow  
                 var iwOuter = $('.gm-style-iw');  
                 var iwBackground = iwOuter.prev();  
                 // Removes background shadow DIV  
                 iwBackground.children(':nth-child(2)').css({ 'display': 'none' });  
                 // Removes white background DIV  
                 iwBackground.children(':nth-child(4)').css({ 'display': 'none' });  
                 // Moves the infowindow 115px to the right.  
                 iwOuter.parent().parent().css({ left: '115px' });  
                 // Moves the shadow of the arrow 76px to the left margin.  
                 iwBackground.children(':nth-child(1)').attr('style', function (i, s) { return s + 'left: 76px !important;' });  
                 // Moves the arrow 76px to the left margin.  
                 iwBackground.children(':nth-child(3)').attr('style', function (i, s) { return s + 'left: 76px !important;' });  
                 // Changes the desired tail shadow color.  
                 iwBackground.children(':nth-child(3)').find('div').children().css({ 'box-shadow': 'rgba(72, 181, 233, 0.6) 0px 1px 6px', 'z-index': '1' });  
                 // Reference to the div that groups the close button elements.  
                 var iwCloseBtn = iwOuter.next();  
                 // Apply the desired effect to the close button  
                 iwCloseBtn.css({ opacity: '1', right: '38px', top: '3px', border: '7px solid #d01320', 'border-radius': '13px' });  
                 // The API automatically applies 0.7 opacity to the button after the mouseout event. This function reverses this event to the desired value.  
                 iwCloseBtn.mouseout(function () {  
                   $(this).css({ opacity: '1' });  
                 });  
                 //setting arrow color  
                 iwOuter.parent().children(':nth-child(1)').children(':nth-child(3)').children(':nth-child(1)').children(':nth-child(1)').css({ 'border-color': '#d01320', 'border-style': 'solid', 'border-width': '0 0 0 1px' });  
                 iwOuter.parent().children(':nth-child(1)').children(':nth-child(3)').children(':nth-child(2)').children(':nth-child(1)').css({ 'border-color': '#d01320', 'border-style': 'solid', 'border-width': '0 1px 0 0' });  
                 map.setCenter(marker.getPosition());  
               }  
             })(marker, i));  
           });  
                          //binding store list here  
           $('#divCorpList').html('');  
           $('#divCorpList').append(corpList);  
           $.each(ret, function (i, val) {  
             var address = '';  
             if (val.adLine1.length > 0)  
               address += val.adLine1;  
             if (val.adLine2.length > 0)  
               address += val.adLine2;  
             if (val.adLine3.length > 0)  
               address += val.adLine3;  
             var postcode = '';  
             if (val.adPostCode.length > 0)  
               postcode += '<br/>' + val.adPostCode;  
             var country = '';  
             if (val.lbCountry.length > 0)  
               country += '<br/>' + val.lbCountry;  
             var phone = '';  
             if (val.adPhone.length > 0)  
               phone += '<br/> Phone : ' + val.adPhone;  
             var fax = '';  
             if (val.adFax.length > 0)  
               fax += '<br/> Fax : ' + val.adFax;  
             var lbDomain = '';  
             if (val.lbDomain.length > 0)  
               lbDomain += '<div class="iw-link" onclick="fnGoToResellerSite(\'' + val.lbDomain + '\')" title=' + val.lbDomain + '> Voir la fiche </div>';  
             var contentString = '<div id="iw_content"><div id="iw-container">' +  
                       '<div class="iw-title">' + val.lbCorporate + '</div>' +  
                       '<div class="iw-content">' +  
                        '<div class="iw-address">' + address + postcode + country + '</div>' +  
                        '<div class="iw-contact">' + phone + fax + '</div>' +  
                        lbDomain +  
                       '</div>' +  
                       '</div></div>';  
             var divId = "div" + val.idCorporate;  
             var geocoder = new google.maps.Geocoder;  
             var elem = document.getElementById(divId);  
             if (elem) {  
               elem.addEventListener('click', function () {  
                 infowindow.setContent(contentString);  
                 infowindow.pixelOffset = new google.maps.Size(-115, 10);  
                 geocodeLatLng(geocoder, map, infowindow, val.coMapCoordinate, contentString);  
               });  
             }  
           });  
           $("#over_map").fadeIn(3000);  
           $("#over_map_corp").fadeIn(3000);  
         },  
         error: function (err) {  
           alert(err.responseText);  
         }  
       });  
     }  
           //if user click on a single store from the list shown in the list, this method is popping up the address of the given point  
     function geocodeLatLng(geocoder, map, infowindow, latlng, contentString) {        
       var latlngStr = latlng.split(',', 2);  
       var latlng = { lat: parseFloat(latlngStr[0]), lng: parseFloat(latlngStr[1]) };  
       geocoder.geocode({ 'location': latlng }, function (results, status) {  
         if (status === 'OK') {  
           if (results[1]) {  
             map.setZoom(16);  
             var marker = new google.maps.Marker({  
               position: latlng,  
               map: map,  
               icon: '2.png'  
             });  
             map.setCenter(marker.getPosition());  
             infowindow.open(map, marker);  
             var iwOuter = $('.gm-style-iw');  
             var iwBackground = iwOuter.prev();  
             iwBackground.children(':nth-child(2)').css({ 'display': 'none' });              
             iwBackground.children(':nth-child(4)').css({ 'display': 'none' });  
             iwOuter.parent().parent().css({ left: '115px' });  
             iwBackground.children(':nth-child(1)').attr('style', function (i, s) { return s + 'left: 76px !important;' });  
             iwBackground.children(':nth-child(3)').attr('style', function (i, s) { return s + 'left: 76px !important;' });  
             iwBackground.children(':nth-child(3)').find('div').children().css({ 'box-shadow': 'rgba(72, 181, 233, 0.6) 0px 1px 6px', 'z-index': '1' });  
             var iwCloseBtn = iwOuter.next();  
             iwCloseBtn.css({ opacity: '1', right: '38px', top: '3px', border: '7px solid #d01320', 'border-radius': '13px' });  
             iwCloseBtn.mouseout(function () {  
               $(this).css({ opacity: '1' });  
             });  
             iwOuter.parent().children(':nth-child(1)').children(':nth-child(3)').children(':nth-child(1)').children(':nth-child(1)').css({ 'border-color': '#d01320', 'border-style': 'solid', 'border-width': '0 0 0 1px' });  
             iwOuter.parent().children(':nth-child(1)').children(':nth-child(3)').children(':nth-child(2)').children(':nth-child(1)').css({ 'border-color': '#d01320', 'border-style': 'solid', 'border-width': '0 1px 0 0' });  
             google.maps.event.addListener(marker, 'click', (function (marker) {  
               return function () {                  
                 infowindow.setContent(contentString);  
                 infowindow.pixelOffset = new google.maps.Size(-10, 10);  
                 infowindow.open(map, marker);  
                 var iwOuter = $('.gm-style-iw');  
                 var iwBackground = iwOuter.prev();  
                 iwBackground.children(':nth-child(2)').css({ 'display': 'none' });  
                 iwBackground.children(':nth-child(4)').css({ 'display': 'none' });  
                 iwOuter.parent().parent().css({ left: '115px' });  
                 iwBackground.children(':nth-child(1)').attr('style', function (i, s) { return s + 'left: 76px !important;' });  
                 iwBackground.children(':nth-child(3)').attr('style', function (i, s) { return s + 'left: 76px !important;' });  
                 iwBackground.children(':nth-child(3)').find('div').children().css({ 'box-shadow': 'rgba(72, 181, 233, 0.6) 0px 1px 6px', 'z-index': '1' });  
                 var iwCloseBtn = iwOuter.next();  
                 iwCloseBtn.css({ opacity: '1', right: '38px', top: '3px', border: '7px solid #d01320', 'border-radius': '13px' });  
                 iwCloseBtn.mouseout(function () {  
                   $(this).css({ opacity: '1' });  
                 });  
                 map.setCenter(marker.getPosition());  
                 iwOuter.parent().children(':nth-child(1)').children(':nth-child(3)').children(':nth-child(1)').children(':nth-child(1)').css({ 'border-color': '#d01320', 'border-style': 'solid', 'border-width': '0 0 0 1px' });  
                 iwOuter.parent().children(':nth-child(1)').children(':nth-child(3)').children(':nth-child(2)').children(':nth-child(1)').css({ 'border-color': '#d01320', 'border-style': 'solid', 'border-width': '0 1px 0 0' });  
               }  
             })(marker));  
           } else {              
             GetLocations(48.864716, 2.349014, 0);  
           }  
         } else {            
           GetLocations(48.864716, 2.349014, 0);  
         }  
       });  
     }  
           //common function : capitalize first letter of the words in a string  
     function capitalizeFirstLetter(string) {  
       return string.toLowerCase().replace(/\b[a-z]/g, function (letter) {  
         return letter.toUpperCase();  
       });  
     }  
           //common function : go to each store website  
     function fnGoToResellerSite(lbDomain) {  
       lbDomain = addhttp(lbDomain);        
       window.open(lbDomain, '_blank');  
     }  
           //common function : get geolocation of the user and load the store list  
     function getLocation(adPostCode) {  
       if (adPostCode && adPostCode.length > 0) {  
         GetLocations(0, 0, adPostCode);  
       }  
       else {  
         if (navigator.geolocation) {  
           var timeoutVal = 10 * 1000 * 1000;  
           navigator.geolocation.getCurrentPosition(showPosition, showDefault, { enableHighAccuracy: true, timeout: timeoutVal, maximumAge: 0 });  
         } else {  
           GetLocations(48.864716, 2.349014, 0);  
         }  
       }  
     }  
     function showPosition(position) {  
       GetLocations(position.coords.latitude, position.coords.longitude, 0);  
     }  
     function showDefault(error) {  
       GetLocations(48.864716, 2.349014, 0);  
     }  
     function geolocateme() {  
       getLocation('');  
     }  
           //common function : search by postcode  
     function GoToPostCode() {  
       var txtadPostCode = $("#txtadPostCode").val();  
       if (txtadPostCode)  
         getLocation(txtadPostCode);  
     }  
   </script>  


Step 9. Run your project. :)




Leave a comment if you need any help..

And try this, it will be fun.

Happy coding.. :)

Wednesday, September 21, 2016

Using Google MAPs to show your store locations - Part 2

If you are a beginner, I hope you already have a bit of an idea about how to use Google Map API after reading the previous post.

Let's directly go in to a bit detailed version of how a dynamic ecommerce store locator is developed.
First you need to get the Geolocation of the user. For that you can use the HTML5 navigator.geolocation function.
 navigator.geolocation.getCurrentPosition(showPosition, showDefault, { enableHighAccuracy: true, timeout: timeoutVal, maximumAge: 0 });  

The "showPosition" and "showDefault" are two functions.
- showPosition - get the current location and find the latitude and longitude.
- showDefault - when a user reject sharing the geolocation or if the browser does not support geolocation, we can use this method with predefined latitude and longitude to center the map.

 function getLocation() {  
   if (navigator.geolocation) {  
     var timeoutVal = 10 * 1000 * 1000;  
     navigator.geolocation.getCurrentPosition(showPosition, showDefault, {  
       enableHighAccuracy: true,  
       timeout: timeoutVal,  
       maximumAge: 0  
     });  
   } else {  
     GetLocations(48.864716, 2.349014, 0);  
   }  
 }  
 function showPosition(position) {  
   GetLocations(position.coords.latitude, position.coords.longitude, 0);  
 }  
 function showDefault(error) {  
   GetLocations(48.864716, 2.349014, 0);  
 }  

GetLocations is a function that works with picking up store locations depending on coordinates.

 position.coords.latitude and position.coords.longitude will provide the user's current latitude and longitude. If user block the geolocation, the default is used as Paris city in France. You may choose where ever possible by changing the values.

So, read the links below;

http://www.w3schools.com/html/html5_geolocation.asp
https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/getCurrentPosition

See you in Part 3.

Happy Coding... :)



Tuesday, September 20, 2016

Using Google MAPs to show your store locations - Part 1

If you have a commerce website that needs to show the store locations, Google Maps is the best tool to use and its free too.
You may need to follow few steps first to get a key to use for your code.

Click Here to get the key.

Create a project and get a key. Keep it saved because it's what you are going to use.



You can always use the documentation here.

Basically you can show  a static location as below;

 <!DOCTYPE html>  
 <html>  
  <head>  
   <meta name="viewport" content="initial-scale=1.0, user-scalable=no">  
   <meta charset="utf-8">  
   <title>Simple markers</title>  
   <style>  
    html, body {  
     height: 100%;  
     margin: 0;  
     padding: 0;  
    }  
    #map {  
     height: 100%;  
    }  
   </style>  
  </head>  
  <body>  
   <div id="map"></div>  
   <script>  
    function initMap() {  
     var myLatLng = {lat: -25.363, lng: 131.044};  
     var map = new google.maps.Map(document.getElementById('map'), {  
      zoom: 4,  
      center: myLatLng  
     });  
     var marker = new google.maps.Marker({  
      position: myLatLng,  
      map: map,  
      title: 'Hello World!'  
     });  
    }  
   </script>  
   <script async defer  
   src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">  
   </script>  
  </body>  
 </html>  

This is a sample you can follow as per Google Map Documentation. But What if we need more. Different locations, and more dynamics.

It will be our next post. So, wait for it. :)

Happy Coding...!






Friday, August 12, 2016

Classic ASP - Create Folder Structure

It is common that we have almost forgotten classic asp but what if you got some modification to do. Here is how we can create a folder structure if not exists...
   Set FS = Server.CreateObject("Scripting.FileSystemObject")       
   'Create folder if not exists  
   dim pathCounter  
   dim arrUploadPath
   dim newPath  
   newPath = ""  
   pathCounter=0  
   arrUploadPath = Split(uploadPath,"\")  
   For Each item in arrUploadPath  
     If Trim(item) <> "" Then  
       newPath = newPath + item + "\"  
       If pathCounter <> 0 Then          
         If Not FS.FolderExists(newPath) Then              
          FS.CreateFolder(newPath)            
         End If  
       End If  
       pathCounter = pathCounter + 1    
     End If         
   Next   



Monday, July 25, 2016

summernote editor for email editor

I found this amazing editor at http://summernote.org that accepts copy paste of images. I was looking for such editor to avoid re-inventing the wheel so that it can be used for an email application. This fits well and it is easy to use too. First, you may download the summernote editor here.

Lets implement summernote editor first.

1. link the js and css file.

 <link href="/script/summernote/summernote.css" rel="stylesheet" type="text/css" />  
 <script src="/script/summernote/summernote.js" type="text/javascript"></script>  

2. Add the editor textarea tag.
 <textarea id="txtSNBody" name="txtDescriptionIE9" runat="server" rows="15" cols="80" clientidmode="Static" style="width: 100%"></textarea>  

3. Convert it to Summernote Editor
 var f = jQuery.noConflict(); // To avoid JQuery conflict  
        f(document).ready(function () {  
             f('#txtSNBody').summernote({  
                  height: 300,         // set editor height  
                  minHeight: null,       // set minimum height of editor  
                  maxHeight: null,  
                  width: 150, // set width  
                  toolbar: [  
               // [groupName, [list of button]]  
               ['Insert', ['picture', 'link', 'video', 'table', 'hr', 'style', 'ol', 'ul', 'paragraph', 'height', 'fullscreen', 'codeview', 'undo', 'redo', 'help']],  
               ['style', ['fontname', 'fontsize', 'color', 'bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'clear']]                
                  ],  
                  defaultFontName: 'Arial',  
                  callbacks: {  
                       onKeyup: function (e) {  
                            DrafttxtSNBody(f('#txtSNBody').summernote('code')); // This function saves the email as a draft asynchronously using jquery ajax  
                       }  
                  }  
             });  
             f('.note-toolbar').css('font-size', '11px'); // Set toolbar font size  
        });  

4. Now the editor will looks like this;
(The content is blurred using a photo editor)

5. Now you can use this as a standard email editor page that support HTML for the body. Even this editor support copy paste of images. But it uses Base64 encoding that is not understood by most browsers and email clients as valid inline images. So you will notice the red cross marks that says no valid images attached to the body.





6. To avoid this, We can write an email handler class. We discussed one here and lets modify it to cater the Base64 Encoded images. The following is a public class that you can use to send emails.

 public class EmailHelper  
   {  
     private MailMessage Message = null;  
     private SmtpClient smtpClient = null;  
     public MailAddress FromAddress { get; set; }  
     public string Subject { get; set; }  
     public string Body { get; set; }  
     public bool has64BaseImages { get; set; }  
     public EmailHelper()  
     {  
       smtpClient = new SmtpClient();  
       smtpClient.Host = ConfigurationManager.AppSettings["smtpHost"];  
       smtpClient.UseDefaultCredentials = false;  
       //smtpClient.EnableSsl = true;  // Enable this if SSL is needed 
       smtpClient.Credentials = new NetworkCredential(ConfigurationManager.AppSettings["userName"], ConfigurationManager.AppSettings["password"]);  
       smtpClient.Port = Convert.ToInt32(ConfigurationManager.AppSettings["port"]);  
       Message = new MailMessage();  
     }  
     public EmailHelper(string host, int port, string userName, string password, bool ssl)  
       : this()  
     {  
       smtpClient.Host = host;  
       smtpClient.Port = port;  
       smtpClient.EnableSsl = ssl;  
       smtpClient.Credentials = new NetworkCredential(userName, password);  
     }  
     public void AddToAddress(string email, string name = null)  
     {  
       if (!string.IsNullOrEmpty(email))  
       {  
         email = email.Replace(",", ";");  
         string[] emailList = email.Split(';');  
         for (int i = 0; i < emailList.Length; i++)  
         {  
           if (!string.IsNullOrEmpty(emailList[i]))  
             Message.To.Add(new MailAddress(emailList[i].Trim(), name));  
         }  
       }  
     }  
     public void AddCcAddress(string email, string name = null)  
     {  
       if (!string.IsNullOrEmpty(email))  
       {  
         email = email.Replace(",", ";");  
         string[] emailList = email.Split(';');  
         for (int i = 0; i < emailList.Length; i++)  
         {  
           if (!string.IsNullOrEmpty(emailList[i]))  
             Message.CC.Add(new MailAddress(emailList[i].Trim(), name));  
         }  
       }  
     }  
     public void AddBccAddress(string email, string name = null)  
     {  
       if (!string.IsNullOrEmpty(email))  
       {  
         email = email.Replace(",", ";");  
         string[] emailList = email.Split(';');  
         for (int i = 0; i < emailList.Length; i++)  
         {  
           if (!string.IsNullOrEmpty(emailList[i]))  
             Message.Bcc.Add(new MailAddress(emailList[i].Trim(), name));  
         }  
       }  
     }  
     public void AddAttachment(string file, string mimeType)  
     {  
       Attachment attachment = new Attachment(file, mimeType);  
       Message.Attachments.Add(attachment);  
     }  
     public void AddAttachment(Attachment objAttachment)  
     {  
       Message.Attachments.Add(objAttachment);  
     }  
     public void SendMail()  
     {  
       try  
       {  
         string imgTempFolder = new Random().Next().ToString();  
         string imgSavePath = HttpContext.Current.Server.MapPath(@"~\App_Code\GBL\EmailHelper\" + imgTempFolder + @"\"); // You can have your own path  
         string msg = "<html><body>" + Body + "</html></body>";  
         foreach (Match m in Regex.Matches(msg, "<img.+?src=[\"'](.+?)[\"'].+?>", RegexOptions.IgnoreCase | RegexOptions.Multiline))  
         {  
           string src = m.Groups[1].Value;  
           if (src.StartsWith("data:image/png;base64"))  
           {  
             has64BaseImages = true;  
             break;  
           }  
         }  
         if (has64BaseImages)  // If Base64 found let them attach as LinkedResources 
         {  
           if (!Directory.Exists(imgSavePath))  
             Directory.CreateDirectory(imgSavePath);  
           Dictionary<int, string> dicImgs = new Dictionary<int, string>();  
           Dictionary<int, LinkedResource> dicImgLR = new Dictionary<int, LinkedResource>();  
           int c = 1;  
           foreach (Match m in Regex.Matches(msg, "<img.+?src=[\"'](.+?)[\"'].+?>", RegexOptions.IgnoreCase | RegexOptions.Multiline))  
           {  
             string src = m.Groups[1].Value;  
             if (!src.StartsWith("data:image/png;base64"))  
               continue;  
             int i = new Random().Next();  
             byte[] bytes = Convert.FromBase64String(src.Split(',')[1]);  
             Image image;  
             using (MemoryStream ms = new MemoryStream(bytes))  
             {  
               image = Image.FromStream(ms);  
             }  
             image.Save(imgSavePath + i.ToString() + ".png");  
             dicImgs.Add(c, imgSavePath + i.ToString() + ".png");  
             string mediaType = MediaTypeNames.Image.Jpeg;  
             LinkedResource ilImg = new LinkedResource(imgSavePath + i.ToString() + ".png");  
             ilImg.ContentId = c.ToString();  
             ilImg.ContentType.MediaType = mediaType;  
             ilImg.TransferEncoding = TransferEncoding.Base64;  
             ilImg.ContentType.Name = ilImg.ContentId;  
             ilImg.ContentLink = new Uri("cid:" + ilImg.ContentId);  
             dicImgLR.Add(c, ilImg);  
             src = src.Replace(src, "cid:" + c);  
             c++;  
           }  
           AlternateView htmlView = AlternateView.CreateAlternateViewFromString(msg, Encoding.UTF8, MediaTypeNames.Text.Html);  
           foreach (var item in dicImgLR)  
           {  
             htmlView.LinkedResources.Add(item.Value);  
           }  
           Message.AlternateViews.Add(htmlView);  
         }  
         if (FromAddress == null || (FromAddress != null && FromAddress.Address.Equals("")))  
         {  
           throw new Exception("From address not defined");  
         }  
         else  
         {  
           if (string.IsNullOrEmpty(FromAddress.DisplayName))  
             FromAddress = new MailAddress(FromAddress.Address, string.Empty);  
           Message.From = FromAddress;  
         }  
         if (Message.To.Count <= 0)  
         { throw new Exception("To address not defined"); }  
         Message.Subject = Subject;  
         Message.IsBodyHtml = true;  
         if (!has64BaseImages)  
           Message.Body = Body;  
         Message.BodyEncoding = Encoding.UTF8;  
         Message.SubjectEncoding = Encoding.UTF8;  
         smtpClient.Send(Message);  
       }  
       catch (Exception)  
       {  
         throw new Exception("Email failed to send");  
       }  
     }  
     public static string GetFileMimeType(string fileName)  
     {  
       string fileExt = Path.GetExtension(fileName.ToLower());  
       string mimeType = string.Empty;  
       switch (fileExt)  
       {  
         case ".htm":  
         case ".html":  
           mimeType = "text/html";  
           break;  
         case ".xml":  
           mimeType = "text/xml";  
           break;  
         case ".jpg":  
         case ".jpeg":  
           mimeType = "image/jpeg";  
           break;  
         case ".gif":  
           mimeType = "image/gif";  
           break;  
         case ".png":  
           mimeType = "image/png";  
           break;  
         case ".bmp":  
           mimeType = "image/bmp";  
           break;  
         case ".pdf":  
           mimeType = "application/pdf";  
           break;  
         case ".doc":  
           mimeType = "application/msword";  
           break;  
         case ".docx":  
           mimeType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";  
           break;  
         case ".xls":  
           mimeType = "application/x-msexcel";  
           break;  
         case ".xlsx":  
           mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";  
           break;  
         case ".csv":  
           mimeType = "application/csv";  
           break;  
         case ".ppt":  
           mimeType = "application/vnd.ms-powerpoint";  
           break;  
         case ".pptx":  
           mimeType = "application/vnd.openxmlformats-officedocument.presentationml.presentation";  
           break;  
         case ".rar":  
           mimeType = "application/x-rar-compressed";  
           break;  
         case ".zip":  
           mimeType = "application/x-zip-compressed";  
           break;  
         default:  
           mimeType = "text/plain";  
           break;  
       }  
       return mimeType;  
     }  
   }  

7. Call this class as below to send email.
 EmailHelper emailHelper = new EmailHelper();  
 emailHelper.FromAddress = new System.Net.Mail.MailAddress("From@domain.com");  
 emailHelper.AddToAddress("To@domain.com");  
 emailHelper.AddCcAddress("Cc@domain.com");  
 emailHelper.AddCcAddress("Bcc@domain.com");  
 emailHelper.AddBccAddress(txtEmailBcc.Text.Trim());  
 emailHelper.AddAttachment("FilePath", EmailHelper.GetFileMimeType(item.Value.Value));  
 emailHelper.Subject = "Subject";  
 msgBody = txtEmailBody.InnerText.Trim();  // The summernote editor
 emailHelper.Body = msgBody;  
 emailHelper.SendMail();  

8. There is no 8th step. This is it. Try it in your application and copy paste the images to body as you wish and send as inline attachments.

Happy coding... And if any issue, just comment.