Bubble Sort Algorithm

HTML
<div class="panel-body">

  <div id="item-1" class="fruit-block peaches">
    <img src="https://resultswebsitedesign.com/path/red-peaches175x153.jpg">
    <div class="product-info-block">
      <h3>Our Finest Peaches</h3>
      <p class="product-description" data-fruit-name="peaches" data-size="6">Our peaches are grown...</p>
    </div>
    <span class="plus-or-minus icon-plus-circled"></span>
  </div>

  <div id="item-2" class="fruit-block blueberries">
    <img src="https://resultswebsitedesign.com/wp-content/path/blueberries175x153.jpg">
    <div class="product-info-block">
      <h3>Our Finest Blueberries</h3>
      <p class="product-description" data-fruit-name="blueberries" data-size="2">Our Blueberries radiate...</p>
    </div>
    <span class="plus-or-minus icon-plus-circled"></span>
  </div>

  <div id="item-3" class="fruit-block strawberries">
    <img src="https://resultswebsitedesign.com/path/strawberries175x153.jpg">
    <div class="product-info-block">
      <h3>Our Finest Strawberries</h3>
      <p class="product-description" data-fruit-name="strawberries" data-size="4">Our juicy and fresh...</p>
    </div>
    <span class="plus-or-minus icon-plus-circled"></span>
  </div>

  <div id="item-4" class="fruit-block elderberries">
    <img src="https://resultswebsitedesign.com/path/elderberries175x153.jpg">
    <div class="product-info-block">
      <h3>Our Finest Elderberries</h3>
      <p class="product-description" data-fruit-name="elderberries" data-size="1">Our signature elderberries...</p>
    </div>
    <span class="plus-or-minus icon-plus-circled"></span>
  </div>

  <div id="item-5" class="fruit-block apricots">
    <img src="https://resultswebsitedesign.com/path/apricots175x153.jpg">
    <div class="product-info-block">
      <h3>Our Finest Apricots</h3>
      <p class="product-description" data-fruit-name="apricots" data-size="5">Our plump apricots...</p>
    </div>
    <span class="plus-or-minus icon-plus-circled"></span>
  </div>

  <div id="item-6" class="fruit-block cherries">
    <img src="https://resultswebsitedesign.com/path/cherries175x153.jpg">
    <div class="product-info-block">
      <h3>Our Finest Cherries</h3>
      <p class="product-description" data-fruit-name="cherries" data-size="3">Deep red and delicious...</p>
    </div>
    <span class="plus-or-minus icon-plus-circled"></span>
  </div>

</div>
JavaScript
//ititialize click event for "largest-to-smallest"
$('.largest-to-smallest').click(function () {
  largestToSmallest = true;
  sortBySize();
});

//ititialize click event for "smallest to largest"
$('.smallest-to-largest').click(function () {
  smallestToLargest = true;
  sortBySize();
});

//ititialize click event for sorting alphabetically
$('.alphabetical').click(function () {
  alphabetize();
});

//initialize global variables to be used by sorting functions
var largestToSmallest = false;
var smallestToLargest = false;
var numberOfItems = document.getElementsByClassName('panel-body')[0].childElementCount;

//function to sort by size uses Bubble Sort algorithm
function sortBySize() {

  //Bubble Sort algorithm must run number of iterations equal to 1 less than number of items sorted to sort fully 
  for (i = 0; i < numberOfItems - 1; i++) {

    //compare each adjacent set of items, and move the larger item after the smaller item.  Number of comparisons required is one less than the number of items.
    for (j = 0; j < numberOfItems - 1; j++) {

      var $currentItem = $('.fruit-block:eq(' + j + ')');
      var $nextItem = $('.fruit-block:eq(' + (j + 1) + ')');

      //access the "data-size" attribute stored on the relevant fruit's HTML element
      var sizeOfCurrentItem = $currentItem.find('.product-description').get(0).getAttribute('data-size');
      var sizeOfNextItem = $nextItem.find('.product-description').get(0).getAttribute('data-size');

      //if "largest-to-smallest" was clicked, put larger of the two "fruit-block" compared first
      if (largestToSmallest) {

        if (sizeOfCurrentItem < sizeOfNextItem) {
          $($currentItem).insertAfter($nextItem);
        }
      }

      //if "smallest-to-largest" was clicked, put smaller of the two "fruit-block" compared first
      if (smallestToLargest) {

        if (sizeOfCurrentItem > sizeOfNextItem) {
          $($currentItem).insertAfter($nextItem);
        }
      }
    }
  }
  largestToSmallest = false;
  smallestToLargest = false;
}

//function to sort alphabetically
function alphabetize() {

  var alphabeticalArray = [];

  //cycle through each "fruit-block" 
  for (i = 0; i < numberOfItems; i++) {

    var $currentItem = $('.fruit-block:eq(' + i + ')');

    var $elementWithFruitName = $($currentItem).find('.product-description');
    var elementWithFruitName = $elementWithFruitName.get(0);

    //grab the "data-fruit-name" attribute for the current fruit being looped through
    var nameInDataAttribute = elementWithFruitName.getAttribute('data-fruit-name');

    //push fruit name coupled with the id of the larger "fruit-block" as an array of two items into the larger alphabeticalArray 
    alphabeticalArray.push([nameInDataAttribute, $($elementWithFruitName).parents('.fruit-block').attr('id')]);

  }

  //Now array is completed that contains pairs of [friut name, element id for that fruit block]
  //Sort this array alphabetically 
  alphabeticalArray.sort();

  //cycle through the alphabetized array
  for (i = 0; i < numberOfItems; i++) {

    //append the element id that is paired with each fruit as last on the page within the ".panel-body" container
    //the resulting order is aphabetical
    $(".panel-body").append($('#' + alphabeticalArray[i][1]));

  }
}

Animated Underscores

JavaScript
 jQuery(document).ready(function () {
     /*CSS transition on width of toggled class*/
     //toggle class with changed width
     jQuery(".width-parent").hover(
         //in
         function () {
             jQuery('.width-child').toggleClass('width-child-big width-child-small');

         },
         //out
         function () {
             jQuery('.width-child').toggleClass('width-child-big width-child-small');

         });
     /*CSS keyframe animation*/
     //remove class that hides .keyframe underline animation after the first requisite animation is complete.  This prevents the underline animation from being visible on page load, but allows it to happen thereafter on hover.
     setTimeout(function () {
         jQuery('.keyframe').removeClass('keyframe-temp-color');
     }, 1100);
 });
jQuery(window).on("load resize", function () {
     /*jQuery animation from center point*/
     //needs to run on load to get correct width measurement
     jQuery(".js-first").hover(
         //in 
         function () {
            var maxWidth = Math.round(jQuery('.js-first').width());
             jQuery('.js-second').animate({
                 width: maxWidth,
                 right: 0
             });
         },
         //out
         function () {
             jQuery('.js-second').animate({
                 width: 0,
                 right: '50%'
             });
         });
 });
CSS
/*heading text with changing colors*/
.see-through {
    background: url(https://resultswebsitedesign.com/wp-content/uploads/2017/10/green2-1000x100.jpg) center top;
    /* if we can clip, do it */
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    /* fallback text color, which needs to work on the background for IE*/
    color: black;
    animation: hue 10s infinite;
    animation-delay: 3s;
}
/*color cycling animation in title text: credit animate.css website*/
@-webkit-keyframes hue {
    from {
        -webkit-filter: hue-rotate(0deg);
    }
    to {
        -webkit-filter: hue-rotate(-360deg);
    }
}
.rotate,
.scale,
.width-parent,
.keyframe,
.js-container {
    position: relative;
    display: inline-block;
}
.rotate::after,
.scale::after,
.keyframe::after {
    left: 0;
    top: 28px;
    position: absolute;
    content: "";
    height: 2px;
}
.rotate::after {
    width: 100%;
    background: black;
    transform: rotateY(270deg);
    transition: transform 1s ease-out;
}
.rotate:hover::after {
    transform: rotateY(180deg);
}
.scale::after {
    width: 100%;
    background: black;
    transform: scale(0);
    transition: transform 1s cubic-bezier(0.14, 0.77, 0.38, 0.97);
}
.scale:hover::after {
    transform: scale(1);
}
.keyframe::after {
    left: 50%;
    background: black;
    animation: shrink 1s;
}
/*temp bkgrnd color of .keyframe underline is transparent until the initial requisite animation completes.  This class is then removed*/
.keyframe-temp-color::after {
    background: transparent;
}
.keyframe:hover::after {
    animation: grow 1s;
}
@keyframes shrink {
    from {
        left: 0;
        width: 100%;
    }
    to {
        left: 50%;
        width: 0;
    }
}
@keyframes grow {
    from {
        left: 50%;
        width: 0;
    }
    to {
        left: 0;
        width: 100%;
    }
}
.width-child {
    position: absolute;
    height: 2px;
    background: black;
    left: 0;
    bottom: 2px;
    transition: all 1s;
}
.width-child-small {
    width: 0;
    left: 50%;
}
.width-child-big {
    width: 100%;
    left: 0;
}
.js-second {
    width: 0;
    height: 2px;
    position: absolute;
    background: black;
    right: 50%;
    bottom: 8px;
}
HTML
<div class="main-container">
    <h2 class="underline-title see-through">Expanding Underline from Center Point: 5 Approaches</h2>

    <p class="underlines-description">blah blah blah.</p>

    <h3 class="rotate">CSS transform: rotate.</h3>
    <br>
    <h3 class="scale">CSS transform: scale.</h3>
    <br>
    <h3 class="width-parent">CSS transition on width & position.<span class="width-child width-child-small"></span></h3>
    <br>
    <h3 class="keyframe keyframe-temp-color">CSS keyframe animation.</h3>
    <br>
    <div class="js-container">
        <h3 class="js-first">jQuery animation.</h3>
        <div class="js-second"></div>
    </div>
</div>

Local Weather App

JavaScript
//get date object
var date = new Date();
var hour = date.getHours();

jQuery(document).ready(function () {

  function getLocation() {
    //credit to W3schools.com for geolocation code
    //if a geolocation object exists...
    if (navigator.geolocation) {
      //call the object's getCurrentPosition() method; once a position is obtained, execute the callback function showPosition, and in the event a geolocation error occurs, execute the callback function showError
      navigator.geolocation.getCurrentPosition(showPosition, showError);
    }
    //if a geolocation object does not exist...
    else {
      jQuery('#details-container').css('display', 'block');
      jQuery('.weather-title').html('<span>Geolocation is not supported by your browser.<span>');
      jQuery('#veil').css('display', 'none');
    }
  }

  //the callback function which uses the geolocation object to display the weather
  function showPosition(position) {

    jQuery('#details-container').css('display', 'block');

    var lat = position.coords.latitude;
    var lon = position.coords.longitude;

    var weatherURL = "https://cors-anywhere.herokuapp.com/http://api.openweathermap.org/data/2.5/weather?lat=" + lat + "&lon=" + lon + "&APPID=KEYGOESHERE";

    //get weather object from open weather api
    jQuery.getJSON(weatherURL, function (json) {

      jQuery('#toggle-temp').addClass('wpforms-submit').css('display', 'block');

      jQuery('.weather-title').html('<span> Current Weather Report for ' + json["name"] + ':' + '</span>');

      jQuery('.conditions').html('<span>' + json["weather"][0]["description"] + '</span>');

      var weatherID = json["weather"][0]["id"];
      var baseURL = "https://openweathermap.org/img/w/";

      //if it is night based on the date object, do the following...
      if ((hour >= 0 && hour <= 5) || (hour >= 18 && hour <= 23)) {
        console.log("It's night (b/t midnight and 5:59am or b/t 6pm and 11:59pm)");

        //display a semi-transparent black layer over the weather image for night effect
        jQuery('#veil').css('display', 'block');

        //dispay a different weather background image and weather icon for each of six weather categories
        switch (true) {
        case (weatherID >= 200 && weatherID <= 232): //thunderstorm
          jQuery('#weatherIcon').attr('src', baseURL + "11n.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/thunderstorm1080x720.jpg)');
          break;
        case ((weatherID >= 300 && weatherID <= 321) || (weatherID >= 500 && weatherID <= 531)): //"drizzle" or "rain" respectively, using same pic
          jQuery('#weatherIcon').attr('src', baseURL + "09n.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/rain1080x760.jpg)');
          break;
        case (weatherID >= 600 && weatherID <= 622): //snow
          jQuery('#weatherIcon').attr('src', baseURL + "13n.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/snow1080x810.jpg)');
          break;
        case (weatherID >= 701 && weatherID <= 781): //mist, smoke, haze, sand/dust whirls, fog, dust, volcanic ash, squalls, tornado
          jQuery('#weatherIcon').attr('src', baseURL + "50n.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/windmill1080x810.jpg)');
          break;
        case (weatherID === 800): //clear
          jQuery('#weatherIcon').attr('src', baseURL + "01n.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/clear1080x720.jpg)');
          break;
        case (weatherID >= 801 && weatherID <= 804): //clouds
          jQuery('#weatherIcon').attr('src', baseURL + "03n.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/cloudy1080x720.jpg)');
          break;
        }

        //if it is day based on the date object, do the following...
      } else {
        console.log("it's day");

        //dispay a different weather background image and weather icon for each of six weather categories
        switch (true) {
        case (weatherID >= 200 && weatherID <= 232): //thunderstorm
          jQuery('#weatherIcon').attr('src', baseURL + "11d.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/thunderstorm1080x720.jpg)');
          break;
        case ((weatherID >= 300 && weatherID <= 321) || (weatherID >= 500 && weatherID <= 531)): //"drizzle" or "rain" respectively, using same pic
          jQuery('#weatherIcon').attr('src', baseURL + "09d.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/rain1080x760.jpg)');
          break;
        case (weatherID >= 600 && weatherID <= 622): //snow
          jQuery('#weatherIcon').attr('src', baseURL + "13d.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/snow1080x810.jpg)');
          break;
        case (weatherID >= 701 && weatherID <= 781): //mist, smoke, haze, sand/dust whirls, fog, dust, volcanic ash, squalls, tornado
          jQuery('#weatherIcon').attr('src', baseURL + "50d.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/windmill1080x810.jpg)');
          break;
        case (weatherID === 800): //clear
          jQuery('#weatherIcon').attr('src', baseURL + "01d.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/sunny1080x723.jpg)');
          break;
        case (weatherID >= 801 && weatherID <= 804): //clouds
          jQuery('#weatherIcon').attr('src', baseURL + "03d.png");
          jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/05/cloudy1080x720.jpg)');
          break;
        }
      }

      //convert source Kelvin temp to Fahrenheit and Celsius
      var kelvinTemp = json["main"]["temp"];
      var fahrTemp = Math.round(((kelvinTemp - 273.15) * (9 / 5)) + 32);
      var celsTemp = Math.round(kelvinTemp - 273.15);

      //display Fahrenheit temp by default
      jQuery('#temp-report').html("Temperature: " + fahrTemp + "°" + " F");

      //when the toggle-temp button is clicked, check to see if it reads Celsius or Fahrenheit
      jQuery('button#toggle-temp').click(function () {

        //if the button reads "Celsius"...
        if (jQuery('button#toggle-temp:contains(Celsius)').length !== 0) {
          //display the temp in Celsius
          jQuery('#temp-report').html('Temperature: ' + celsTemp + '°' + ' C');
          //make the button text read "to Fahrenheit"
          jQuery('button#toggle-temp').html('to Fahrenheit');
        }
        //if the button reads "Fahrenheit"...
        else if (jQuery('button#toggle-temp:contains(Fahrenheit)').length !== 0) {
          //display the temp in Fahrenheit
          jQuery('#temp-report').html('Temperature: ' + fahrTemp + '°' + ' F');
          //make the button text read "to Celsius"
          jQuery('button#toggle-temp').html('to Celsius');
        }
      });
    });
  }
  getLocation();

  //callback function which handles getGeolocation() errors    
  function showError(error) {
    //credit to W3schools.com for error handling
    jQuery('#toggle-temp').css('display', 'none');
    jQuery('#details-container').css('display', 'block');
    switch (error.code) {
    case error.PERMISSION_DENIED:
      jQuery('.weather-title').html('<span>Your settings denied the request for geolocation.  Please allow geolocation in your browser and/or OS settings so your local weather may be displayed.<span>');
      jQuery('#veil').css('display', 'none');
      break;
    case error.POSITION_UNAVAILABLE:
      jQuery('.weather-title').html('<span>Location information is unavailable, so the weather for your location cannot be displayed.<span>');
      jQuery('#veil').css('display', 'none');
      break;
    case error.TIMEOUT:
      jQuery('.weather-title').html('<span>The request to get your location timed out, so weather for your location cannot be displayed.<span>');
      jQuery('#veil').css('display', 'none');
      break;
    case error.UNKNOWN_ERROR:
      jQuery('.weather-title').html('<span>An unknown error occurred, so weather for your location cannot be displayed. <span>');
      //    jQuery('#weather-report').css('background-image', 'url(https://resultswebsitedesign.com/wp-content/uploads/2017/06/geolocation1080x720.jpg)');
      jQuery('#veil').css('display', 'none');
      break;
    }
  }

  //prevent default api service failure message from flashing before a successful api call can complete and populate the widget
  setTimeout(function () {

    //detect if .weather-title has been populated due to successful api call or geolocation error info
    if (jQuery('.weather-title').text().length === 0) {

      jQuery('.weather-title').html('<span>An API service required to fetch the weather for your location is temporarily unavailable.  Please try again later.<span>');
    }
  }, 1000);
});
CSS
  .weather-title {
    text-align: center;
    padding-top: 15px;
  }  
  .conditions {
    text-align: center;
    text-transform: capitalize;
  } 
  .flex-container {
    display: flex;
    justify-content: center;
    width: 100%;
  } 
  #weather-report {
    max-width: 1080px;
    width: 100%;
    margin: 0 auto;
    padding: 0 15px;
    min-height: 720px;
    position: relative;
    border-radius: 10px;
    background-position: center;
  } 
  #veil,
  #default-background {
    width: 100%;
    min-height: 720px;
    position: absolute;
    top: 0;
    left: 0;
    border-radius: 10px;
  }  
  #veil {
    background-color: rgba(0, 0, 0, .5);
    z-index: 1;
    display: none;
  }  
  #default-background {
    z-index: -1;
    background: url(https://resultswebsitedesign.com/wp-content/uploads/2017/06/geolocation1080x720.jpg) center;
    display: block;
  }
  #details-container {
    /*prevent display until it is known whether geolocation is allowed*/
    display: none;
    position: relative;
    /*position weather details in layer above veil*/
    z-index: 2;
    max-width: 500px;
    background: rgba(255, 255, 255, .5);
    padding: 0 10px;
    margin: 0 auto;
    border-radius: 10px;
    top: 15px;
  } 
  #toggle-temp {
    /*prevent display until it is known whether geolocation is allowed*/
    display: none;
  }