Frage

I've created a very simple greasemonkey script based on Jquery - sort DIV's by innerHTML of children to add buttons to the results panel on www.oldmapsonline.org to enable sorting by date and by scale. This seems to work fine, except for scale sorting on records where there is no scale in the html.

// ==UserScript==
// @name       Sort oldmapsonline.org records
// @namespace  http://www.whatsthatpicture.com/
// @version    0.1
// @description  A simple tool to add a sort option (by date and by scale)
// @match      http://www.oldmapsonline.org/*
// @copyright  2014, James Morley @jamesinealing
// @require    http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js

// ==/UserScript==

// create html buttons and insert in place of search header text
var links = 'Sort: <a href="#" id="datesort">Date</a> <a href="#" id="scalesort">Scale</a>';
$( "#instant-search-header" ).html( links );

//add two event handlers for the sort buttons
$( "#scalesort" ).click(function() {
    sortUsingNestedText($('#sidecanvas'), "div", "span.mapscale");
});
$( "#datesort" ).click(function() {
    sortUsingNestedText($('#sidecanvas'), "div", "span.year");
});

// sorting function adapted from https://stackoverflow.com/questions/7831712/jquery-sort-divs-by-innerhtml-of-children
function sortUsingNestedText(parent, childSelector, keySelector) {
  var items = parent.children(childSelector).sort(function(a, b) {
    var vA = parseInt($(keySelector, a).text().replace('1:','').replace(' ','')); // the replace actions removes spaces and the '1:' in the scale, parsInt makes sure it's a number
    var vB = parseInt($(keySelector, b).text().replace('1:','').replace(' ',''));
    return (vA < vB) ? -1 : (vA > vB) ? 1 : 0;
  });
parent.append(items);
};

You can see a sample page at http://www.oldmapsonline.org/#bbox=169.619637,-46.121916,171.816902,-44.130108&q=&datefrom=1730&dateto=1750 which contains the block to sort something like this

<div id="sidecanvas" class="content" style="-webkit-user-select: none;">
  <div class="item clearFix" id="4638.003"><img src="/img/75/rumsey/4638.003.jpg">
    <div class="info">
      <h2 class="title"><span class="editions"></span><span class="maintitle">L'Hemisphere Meridional.</span></h2>
      <p class="details"><span class="mapscale"> 1:37 000 000</span><span class="author"><span class="year">1742</span> - Lisle, Guillaume de, 1675-1726</span></p>
    </div>
  </div>
  <div class="item ...
  ...
  </div>
</div>

For records where there is no scale the html is <span class="mapscale"></span> which seems to stop it sorting correctly (even though it doesn't throw any errors).

Where there is a scale present for all entries (e.g. http://www.oldmapsonline.org/#bbox=150.326271,-28.645704,153.9188,-26.336192&q=&datefrom=1825&dateto=1825) it appears to work fine.

Any ideas how I can allow for this? I guess just iterating through the values first and setting empty ones to 9999999999 would work, and it would also have the benefit of ensuring that they get placed last in the sort order. But I was wondering if there's something more elegant?

Edit: replacing the $( "#scalesort" ).click(function() { ... block with the following code did the trick

$( "#scalesort" ).click(function() { 
    // first we check for items with no scale set, and set a very high number to make sure they get sorted last
    $('.mapscale').each(function(index) {
        var scale = $( this ).text();
        if (scale == '') { $( this ).text('9999999999')};
    });
    //then we call the sort function
    sortUsingNestedText($('#sidecanvas'), "div", "span.mapscale");
    //then we scrub the high values so they don't get displayed
    $('.mapscale').each(function(index) {
        var scale = $( this ).text();
        if (scale == '9999999999') { $( this ).text('')};
    });

});

but there's something in me that says there must be a more elegant answer?

War es hilfreich?

Lösung

The problem is that vA and vB could either or both result in NaN. I haven't found any '<' or '>' statement where comparing against NaN returns true. (MDN says, "NaN is not equal to anything, including NaN").

You can simply replace your NaN with the high value you used in the solution you posted, or you could do something more creative using NaN values.

function sortUsingNestedText(parent, childSelector, keySelector) {
  var items = parent.children(childSelector).sort(function(a, b) {
    var vA = parseInt($(keySelector, a).text().replace('1:','').replace(' ','')); // the   replace actions removes spaces and the '1:' in the scale, parsInt makes sure it's a number
    var vB = parseInt($(keySelector, b).text().replace('1:','').replace(' ',''));
    if (isNaN(vA)) { vA = 9999999999; }
    if (isNaN(vB)) { vB = 9999999999; }
    return (vA < vB) ? -1 : (vA > vB) ? 1 : 0;
});

Or maybe something like this:

function sortUsingNestedText(parent, childSelector, keySelector) {
  var items = parent.children(childSelector).sort(function(a, b) {
    var vA = parseInt($(keySelector, a).text().replace('1:','').replace(' ','')); // the   replace actions removes spaces and the '1:' in the scale, parsInt makes sure it's a number
    var vB = parseInt($(keySelector, b).text().replace('1:','').replace(' ',''));
    if (isNaN(vA) && !isNaN(vB)) { return 1; }
    if (isNaN(vB) && !isNaN(vA)) { return -1; }
    if (isNaN(vA) && isNaN(vB)) { return 0; }
    return (vA < vB) ? -1 : (vA > vB) ? 1 : 0;
});
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top