Achievements

JavaScript code for the Achievements Drupal module.

HTML

<div class="achievement-notification element-hidden">Lorem ipsum 1</div>
<div class="achievement-notification element-hidden">Lorem ipsum 2</div>
<div class="achievement-notification element-hidden">Lorem ipsum 3</div>
<div class="achievement-notification element-hidden">Lorem ipsum 4</div>
<div class="achievement-notification element-hidden">Lorem ipsum 5</div>
<div class="achievement-notification element-hidden">Lorem ipsum 6</div>
<div class="achievement-notification element-hidden">Lorem ipsum 7</div>
<div class="achievement-notification element-hidden">Lorem ipsum 8</div>

CSS

/**
 * Single achievement full display.
 */
.achievement {
  border: 1px solid #bbb;
  height: 86px;
  margin: 0.8em auto;
}

.achievement-hidden,
.achievement-locked {
  filter: alpha(opacity=50);
  opacity: 0.5;
}

.achievement-image {
  float: left;
  margin: 0.6em;
}

.achievement-body {
  padding: 0.6em;
}

.achievement-title {
  font-size: 17px;
  font-weight: bold;
}

.achievement-points-box {
  background-color: #ddd;
  border-left: 1px solid #bbb;
  font-family: Verdana, Arial, sans-serif;
  float: right;
  margin-left: 0.6em;
  text-align: center;
  height: 86px;
  width: 86px;
}

.achievement-points-box .achievement-points {
  font-size: 28px;
  font-weight: bold;
  margin-top: 2px;
}

.achievement-points-box .achievement-unlocked-stats {
  font-size: 11px;
}

/**
 * Single achievement notification display.
 */
.achievement-notification-dialog {
  border-color: #00c325;
  margin: 0.6em;
  padding: 0;
  position: fixed;
}

.achievement-notification-dialog .ui-dialog-titlebar {
  display: none;
}

.achievement-notification {
  background: #b8ffa9 !important;
}

.achievement-notification .achievement-body {
  margin-top: 1em;
}

.achievement-notification img {
  display: block;
}

.achievement-notification .achievement-points-box {
  border: 1px solid #1CF608;
  background: #79F66A;
  margin-top: 0.6em;
  height: 70px;
  width: 70px;
}

.achievement-notification .achievement-body {
  text-align: center;
}

/**
 * Stats line on the user's achievement page.
 */
.achievement-stats {
  margin: 1em;
  text-align: center;
}

/**
 * Columns on the achievement leaderboards.
 */
.achievement-leaderboard .achievement-leaderboard-rank {
  width: 12px;
}

.achievement-leaderboard .achievement-leaderboard-points,
.achievement-leaderboard .achievement-leaderboard-unlocks {
  width: 50px;
}

.achievement-leaderboard .achievement-leaderboard-latest {
  width: 275px;
}

.achievement-leaderboard-current-user {
  font-weight: bold;
}

.achievement-leaderboard...

JavaScript

jQuery(function($) {
    var height = 104, margin = 10, timeout,
      notifications = $('.achievement-notification').dialog({
        dialogClass:    'achievement-notification-dialog',
        autoOpen:       false,
        show:           'fade',
        hide:           'fade',
        closeOnEscape:  false,
        draggable:      false,
        resizable:      false,
        height:         height,
        width:          500,
        position:       ['right', 'bottom'],
        closeText:      '',
        close:          onClose
      });

    function showDialogs() {
      var length = notifications.length;

      notifications.eq(length - 1).bind('dialogopen', function() {
        var i, notification, top;

        for (i = 0; i < length; i += 1) {
          notification = notifications.eq(i).dialog('widget');
          if (i === 0) {
            top = parseFloat(notification.css('top'));
          }
          else {
            top -= height + margin;
            notification.css('top', top + 'px');
          }
        }

        // the longer the list, longer the onscreen time.
        timeout = setTimeout(closeDialog, 5000 + (length * 500));
      });

      notifications.dialog('open').hover(
        function () {
          clearTimeout(timeout);
        },
        function () {
          // the longer the list, longer the onscreen time.
          timeout = setTimeout(closeDialog, 1500 + (notifications.length * 500));
        }
      );
    }

    function onClose() {
      var i, length, properties, widget;
      notifications = notifications.not(notifications[0]);
      length = notifications.length;
      
      function close() {
         timeout = setTimeout(closeDialog, 1500);
      }

      if (length) {
        properties = {
          top: '+=' + (height + margin)
        };
        for (i = 0; i < length; i += 1) {
          widget = notifications.eq(i).dialog('widget');
          if (i === 0) {
            widget.animate(properties, close);
...