Simple numbered markers with Leaflet.js

I thought I’d look up how to create markers that are numbered with the excellent Leaflet.js. Perhaps surprisingly there is no built in method, but looking round the Web there are a few suggested ways of doing it. These all seemed rather over-engineered though so I decided to engage brain rather than just blindly copying. The following method works, and is a lot less complicated than anything else I’ve seen out there.

I wanted to achieve this (yes I know grey is not a good choice in this case, but it is what the user wanted):
map

To get markers like this first of all copy the Leaflet.js default marker image, which in 0.7.3 is here -> http://cdn.leafletjs.com/leaflet-0.7.3/images/marker-icon.png . I simply modified this using Paint.Net to be solid grey. Put the final image into your website/application.

Create a CSS class like this, obviously substituting your image path/name and font colour:

.number-icon
{
	background-image: url("images/number-marker-icon.png");
	text-align:center;
	color:White;	
}

Then when creating your marker you need to add this code, putting the number in the ‘html’ parameter:

      var numberIcon = L.divIcon({
            className: "number-icon",
            iconSize: [25, 41],
            iconAnchor: [10, 44],
            popupAnchor: [3, -40],
            html: variable_containing_the_number        
      });

      var marker = new L.marker([lat, long],
                            {
                                
                                icon: numberIcon
                                
                            });

And that’s all there is to it. Not quite sure why there are so many other elaborate methods out there, but maybe they work for use cases other than the one I had too.

Submitting a multipart AJAX form with CKEditor textarea

OK, the subject of this post is pretty niche, but that’s why I am posting about it because I do it so little I’d only forget about it for the next time!

With ASP.NET MVC if you want to allow a file upload on a form submitted by AJAX then you have to intercept the form submit event and do the submit it yourself via Javascript, rather than using MVC’s helpers. This is detailed in this useful Stackoverflow answer: How to do a aspnet mvc ajax form post with multipart form data

What the post doesn’t mention (as it wasn’t asked for!) was that if your form contains an instance of the popular rich text editor CKEditor then this code alone will not transfer the data the editor contains to the form. I think this must be because the CKEditor is waiting for the submit event to be triggered before it does the copy into the field.

It took a bit of digging, as I have not had to look at the CKEditor API before, but if you take the code from the above link as a start point, then add the following code to somewhere between the event.preventDefault() call and the ajax() call, it seems to work OK.


            for (instance in CKEDITOR.instances) {
                CKEDITOR.instances[instance].updateElement();
            }

IE8 clips the text from a max-widthed drop-down box – fix!

OK, Windows XP only has about 6 months to live from the date of this post, and so IE8 (which is XP only) will die out sooner rather than later, but if you are in the unfortunate position of having to try and support ancient browsers then you will have almost certainly come across the problem with fixed-width or max-width drop-down lists. If the width of your options exceeds the width (or max width) of the drop-down box then IE8 just clips the text, which may well mean that your users can’t read it. Another useful feature from IE.

There is a suggested solution here for fixed width drop-downs: http://jquerybyexample.blogspot.com/2012/05/fix-for-ie-select-dropdown-with-fixed.html, which is useful however does not quite address the problem of drop-down boxes with no fixed width defined, but which do have a max-width defined.

The solution is a modification of the above link. Firstly wrap your drop down in a div with a width the same as the max-width of the drop-down, and an overflow value of hidden. The example below shows a Razor ASP.NET drop down, but this will work with HTML too.

  <div style="width:400px;overflow:hidden;">
            @Html.DropDownList("Selection", Model.ChoiceList, new { id = "ddlChoose", @class="ddlClass", style = "max-width:400px; text-overflow: ellipses; " }) 
  </div>

Then in the jQuery $(document).ready() method put the following code on the change, blur, mousedown and mouseup events for your drop-down. In this example I’ve done the element selection by class, but obviously you can use ID if you want. I have used the jQuery ‘live’ method as my drop-downs were not necessarily generated on page load, however you can just use the mousedown() etc methods if you are not doing anything fancy.

$(document).ready(function () {

    /* Begin functions for IE8 drop-down boxes */

    $(".ddlClass").live("mousedown", function () {
        SetToAutoWidth($(this), true, 400);
    });

    $(".ddlClass").live("change", function () {
       ResetToFixedWidth($(this), true, 400);
    });
    $(".ddlClass").live("blur", function () {
       ResetToFixedWidth($(this), true, 400);
    });

    $(".ddlClass").live("mouseup", function () {
       ResetToFixedWidth($(this), true, 400);
   });

  
    /* End functions for IE8 drop-down boxes */

});

This final bit of jQuery contains the methods that actually do the work. Note that you could probably make the FindTextWidth() method more efficient by only running it on page load, and persisting the div (as mentioned in the stackoverflow reply I took this from).

// Return the width (in pixels) of the passed string
// From here: http://stackoverflow.com/questions/118241/calculate-text-width-with-javascript and slightly modified
function FindTextWidth(textToMeasure, fontFamily, fontSize){
    var o = $('<div>' + textToMeasure + '</div>').css({ 'position': 'absolute', 'float': 'left', 'white-space': 'nowrap', 'visibility': 'hidden', 'font-family': fontFamily, 'font-size': fontSize }).appendTo($('body'));
    var w = o.width();

    o.remove();
    return w;
}

// Look through all the options on the drop-down. If any are longer than the passed width value then expand the box.
// Params: 
// ddl - the dropdown list object
// maxWidthFlag - if true then set the max-width, else set the width
// width - the option width value over which the functionality is invoked.
function SetToAutoWidth(ddl, maxWidthFlag, width) {
    if ($.browser.msie && $.browser.version.substring(0, 2) === "8.") { // IE8 only

        var ID = $(ddl).attr("id");
        var ff = $(ddl).css("font-family");
        var fs = $(ddl).css("font-size");

        $("#" + ID + " > option").each(function () { // For each option in the list...

            var t = $(this).text(); // Get the text
            var w = FindTextWidth(t, ff, fs); // Find the width in pixels

            if (w >= width) { // If the width is greater than the passed value
                if (maxWidthFlag === true) {
                    $(this).parent().css("max-width", ""); // Remove the max-width style
                }
                else {
                    $(this).parent().css("width", "auto"); // Set the width style to auto
                }

            }
        });
    }
}

// Params: 
// ddl - the dropdown list object
// maxWidthFlag - if true then set the max-width, else set the width
// width - the option width value over which the functionality is invoked.
function ResetToFixedWidth(ddl, maxWidthFlag, width) {
    if ($.browser.msie && $.browser.version.substring(0, 2) === "8.") { // IE8 only

        if (maxWidthFlag === true){
             $(ddl).css("max-width", width + "px");
        }
        else{
            $(ddl).css("width", width + "px");
        }
    }
}

Note that this still does not get around the problem of the greater-than-the-max-width selected option overflowing the main drop-down box and overwriting the down-arrow. If anyone has a solution for that that doesn’t involve adding an image to it please say!

Bug/feature in jQuery tablesorter pager

I’ve just come across a feature/bugette of the otherwise excellent jQuery tablesorter.pager plugin which is worth making a note of:

If your table has no rows and you try to make the call to the plugin then it appears to throw a wobbly and possibly an exception too. If you are doing this within an ‘OnSuccess’ event from an MVC Ajax.BeginForm() call then it appears to cancel out of the call and possibly messes up your screen too, depending on what else you are doing in this call.

To get around it I simply returned a different PartialView that didn’t contain the table, and then in the OnSuccess event checked to see if the table existed:

 

if ($("#tblSearchResults").length > 0) {
        $("#tblSearchResults").tablesorter();
        $("#tblSearchResults").tablesorterPager({ container: $("#pager") });
    }

Another way might be to tag individual rows with a class name, and see if any instances of that class exist on the page. The above way suited me better this time.

jQuery UI tab not sizing to content

I found a quirk in jQuery UI. If the contents of your tab are styled with the CSS attribute float: then the tab does not resize to fit the content. This can be fixed quite simply by adding an additional div with a clear:both style after it. This is an a example:

<div id="tabs" style="display:block">
    <ul>
        <li><a href="#tabs-1">Tab 1</a></li>
        <li><a href="#tabs-2">Tab 2</a></li>
        <li><a href="#tabs-3">Tab 3</a></li>
    </ul>
    <div id="tabs-1" style="width:100%;  display:block; ">
         <div style="width:40%; position:relative; display:inline-block; float:right;"> 
         <div style="width:40%; position:relative; display:inline-block; float:left;"> 
         <div style="width:100%; clear:both"></div>
    </div>
    <div id="tabs-2" style="width:100%; display:block; ">

     Content of tab 4
   
    </div>
    <div id="tabs-3" style="width:100%; display:block;">
 
     Content of tab 3
    </div>

</div>  

I’m just mentioning it here as the only other place I could find that had anything about this said that jQuery tabs could not support floating content.

This applies to jQuery UI 1.8.11 (and presumably above!).

ASP.NET MVC Input button not submitting in Internet Explorer

If you have a piece of code that disables your submit button when you click it, such as the following:

   <script type="text/javascript">

        function delCheck() {
            if (confirm("Are you sure you want to delete?") == true) {

                
                $('#btnSubmit').attr("disabled", "disabled");
                return true;
            }
            else
                return false;
        }
    </script>

<% using (Html.BeginForm("Delete", "MyController"))
   { %>
           <input type="submit" value="Submit" title="Submit" name="btnSubmit" id="btnSubmit" onclick="return delCheck()" /> 
  
<%} %>

Then you will find in MVC that this does not submit when the user is using IE. Internet Explorer does not seem to like the fact that you have disabled the button (this is the case up to IE8, I’ve not checked IE9). All other browsers are OK.

If you need to prevent the user pressing it again then try making it invisible instead, which seems to work OK.

Increasing the security of AJAX requests from the browser

Just a quickie.

I’ve a situation where I need to use AJAX to get a list of items for a particular user.

The for the request is in a hidden field (i.e. fully publicly viewable) in the DOM

e.g. http://www.example.com/users/alexhardman/items

The problem with using the username here is that it is human readable which makes it very easy to hack by changing on or more of the characters.

To increase the securing I’ve added a guid row to my user table which will be used to retrieve users.

e.g. http://www.example.com/items/for/7275670d-f06d-4be2-b260-4c8e094ead6c

This makes it infinitely more difficult to hack the url and return information for a user other than the one given in the url.

e.g.