Showing posts with label js. Show all posts
Showing posts with label js. Show all posts

Sunday, January 12, 2014

Character Count

Character Count

Character count for textarea with alert and cut-off. Based on experiment by Jason Saba.



<div class="wrapper">
  <h1>Textarea Character Count</h1>
  <textarea name="the-textarea" id="the-textarea" maxlength="140" placeholder="Enter Your Text Here"></textarea>
  <div id="the-count">
    <span id="current">0</span>
    <span id="maximum">/ 140</span>
  </div>
</div>

<script class="cssdeck" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>

@import url(http://fonts.googleapis.com/css?family=Open+Sans:300,400,700,300italic);

*, *:before, *:after { box-sizing: border-box; }
html { font-size: 100%;  }
body { 
  font-family: 'Open Sans', sans-serif;
  font-size: 16px;
  background: tomato;
  color: #fff;
}

.wrapper {
  max-width: 65%;
  margin: auto;
}


h1 { 
  color: #fff; 
  margin: 3rem 0 1rem 0; 
  padding: 0;
  font-size: 1.5rem;
  font-family: 'Open Sans', sans-serif;
  font-weight: 400;
  display: block;
  text-align: Center;
}

textarea {
  width: 100%;
  min-height: 100px;
  resize: none;
  border: 1px solid #ddd;
  outline: none;
  padding: 0.5rem;
  color: #666;
  box-shadow: inset 0 0 0.25rem #ddd;
  &:focus {
    outline: none;
    border: 1px solid darken(#ddd, 5%);
    box-shadow: inset 0 0 0.5rem darken(#ddd, 5%);
  }
  &[placeholder] { 
    font-style: italic;
    font-size: 0.875rem;
  }
}

#the-count {
  float: right;
  padding: 0.1rem 0 0 0;
  font-size: 0.875rem;
}

$('textarea').keyup(function() {
    
  var characterCount = $(this).val().length,
      current = $('#current'),
      maximum = $('#maximum'),
      theCount = $('#the-count');
    
  current.text(characterCount);

  
  /*This isn't entirely necessary, just playin around*/
  if (characterCount < 70) {
    current.css('color', '#fff');
    current.css('font-weight', 'normal');
  }
  if (characterCount > 70 && characterCount < 90) {
    current.css('color', '#eee');
    current.css('font-weight', 'normal');
  }
  if (characterCount > 90 && characterCount < 100) {
    current.css('color', '#793535');
    current.css('font-weight', 'normal');
  }
  if (characterCount > 100 && characterCount < 120) {
    current.css('color', '#841c1c');
    current.css('font-weight', 'normal');
  }
  if (characterCount > 120 && characterCount < 139) {
    current.css('color', '#8f0001');
    current.css('font-weight', 'bold');
  }
  
  if (characterCount == 140) {
    maximum.css('color', '#8f0001');
    current.css('color', '#8f0001');
    theCount.css('font-weight','bold');
  } else {
    maximum.css('color','#fff');
    theCount.css('font-weight','normal');
  }
  
      
});

Friday, January 10, 2014

Sticky Table Headers & Columns

Sticky Table Headers & Columns

A tutorial on how to create sticky headers and columns for tables using jQuery. The solution is an alternative to other sticky table header approaches and it addresses the overflowing table problem including adding support for biaxial headers.

Sticky table headers are no longer a stranger to an average website user — unlike on paper when a reader's eyes can comfortably jump in saccades between top of a lengthy table and the rows of interest, the landscape orientation of most devices makes vertically-long tables hard to read. However, this very conundrum presents itself as a rich ground for UI experimentation that is not available to the printed media.

Sticky table headers, as their name implies, remains affixed to the top of the viewport even when the original table headers are scrolled out of view. They help to clarify the representation and purpose of data in columns when the visual reference to original table headers was lost. Besides that, the aid in orienting users in a sea of tabulated information, therefore avoiding the need to repeatedly and frustratingly, scroll between the top of the table where the header resides and the region of interest further down, typically lying out of the viewport.

There have been a handful of scripts and jQuery plugins written for the purpose of re-establishing the flow and ease of reading tables. While their implementation is flawless and efficient, they might not be an all-encompassing panacea for long tables. In some cases, tables have to obey certain layout rules that are not accounted for by the aforementioned plugins — such as tables that are forced to overflow due to dimension restrictions (e.g. to fit within a viewport).

While this tutorial does not try to serve as an all-encompassing panacea to the decidedly sticky problem with sticky table headers, it addresses more possible layout scenarios.

A Pure CSS-Based Solution with position: sticky?

Last September, a somewhat promising solution surfaced — a new possible value for the CSS position property is supported in the latest nightly build of WebKit or Chrome Canary. position: sticky sounded like a very promising new JS-free solution to the old and nuance problems of rigid table headers and beyond — its implementation can be also extremely useful in scenarios where a site navigation or a HTML5 app toolbar has to remain in view to the user at all times regardless of his/her scroll position along the document's y-axis.

Moreover, the sticky property value is supported in barely 6% of all global visits, making it a poor candidate for choice of implementation. Although it will not break layouts as browsers are dictated by W3C directive to ignore properties values that are unrecognized, invalid or illegal, it is not an ideal candidate when cross-browser functionality is desired.

The jQuery Based Solution

The jQuery-based solution is rather straight-forward. Before we move on with the JS itself, we should come to a common consensus how a semantically valid table should look like in the markup:

<table>
    <thead>
        <tr>
            <th></th>
            <!-- more columns are possible -->
    </tr>
    </thead>
    <tbody>
        <tr>
            <td></td>
            <!-- more columns are possible -->
        </tr>
        <!-- more rows are possible -->
    </tbody>
    <tfoot><!-- optional -->
        <tr>
            <td></td>
        </tr>
    </tfoot>
</table>

What do we want to achieve?

We should enumerate the expectations of this script. It would be great if the script can accommodate various table layouts and situations:

  • Basic usage: Sticky table header only
  • Biaxial table headers
  • Wide tables:
    • Horizontal overflow: If there is a row header, we should introduce a sticky table column, too
    • Vertical overflow: Covered in basic usage
    • Biaxial overflow: Introduce sticky table header and column

Some CSS groundwork

Despite choosing to work with a JS-based solution, we will still have to rely on CSS for the basic styling of the headers. The important things is that we have to position the sticky header absolutely within a common parent with its full-fledge, original table sibling. The CSS is rather straight forward:

.sticky-wrap {
    overflow-x: auto;
    position: relative;
    margin-bottom: 1.5em;
    width: 100%;
}
.sticky-wrap .sticky-thead,
.sticky-wrap .sticky-col,
.sticky-wrap .sticky-intersect {
    opacity: 0;
    position: absolute;
    top: 0;
    left: 0;
    transition: all .125s ease-in-out;
    z-index: 50;
    width: auto; /* Prevent table from stretching to full size */
}
    .sticky-wrap .sticky-thead {
        box-shadow: 0 0.25em 0.1em -0.1em rgba(0,0,0,.125);
        z-index: 100;
        width: 100%; /* Force stretch */
    }
    .sticky-wrap .sticky-intersect {
        opacity: 1;
        z-index: 150;
    }
    .sticky-wrap .sticky-intersect th {
        background-color: #666;
        color: #eee;
    }
.sticky-wrap td,
.sticky-wrap th {
    box-sizing: border-box;
}

Note: It is extremely important that you port the styles for your <table> elements over to .sticky-wrap. Although margins of pixel values can be easily calculated and applied to the new wrapper element, automatic margins are difficult to deal with (it is not possible to fetch the value of auto with jQuery in a straightforward manner) and it is easier if we simply apply the margins and width of tables to the wrapper element itself.

Let's say you have the following styles for your table:

table {
    margin: 0 auto 1.5em;
    width: 75%;
}

You can simply add the lines to ".sticky-wrap", too:

.sticky-wrap {
    overflow-x: auto; /* Allows wide tables to overflow its containing parent */
    position: relative;
    margin: 0 auto 1.5em;
    width: 75%;
}

I shall walk you through the steps that will, with a dozens of lines of JavaScript, create functional sticky table headers. For the ease of presentation, the script is presented in a logical flow towards problem solving — declaration of variables with the var statement can definitely be concatenated for a more compact and compressed script, but at the sake of logical flow and readability, therefore I have chosen not to adopt the latter approach.

We shall execute our function for every single instance of table selected for upon DOM ready. Moreover, we will also want to check if the selected tables contain the <thead> element and that the <thead> element is not empty and contains at least one <th> child. If the aforementioned criteria are not satisfied, our function will simply skip that instance of <table> and move on to the next.

$(function () {
    // Here we select for <table> elements universally,
    // but you can definitely fine tune your selector
    $('table').each(function () {
        if($(this).find('thead').length > 0 && $(this).find('th').length > 0) {
            // Rest of our script goes here
        }
    });
});

Step 1: Clone the <thead> element

Before we start, we will want to close the table head and declare some shorthand variables for ease of use:

// Declare variables and shorthands
    var $t     = $(this),
        $w     = $(window),
        $thead = $(this).find('thead').clone(),
        $col   = $(this).find('thead, tbody').clone();

Step 2: Wrap table and append new tables

In order to extend compatibility towards tables that have excessive width along the x-axis (e.g. having too many columns, or columns that are necessarily yet excessively wide), we wrap the table elements in a <div> element that is allowed to overflow along the x-axis. The width and margin properties are reset for the table so as to allow proper display within the wrapper.

// Wrap table
$t
.addClass('sticky-enabled')
.css({
    margin: 0,
    width: '100%';
})
.wrap('<div class="sticky-wrap" />');

// Check if table is set to overflow in the y-axis
if($t.hasClass('overflow-y')) $t.removeClass('overflow-y').parent().addClass('overflow-y');

// Create new sticky table head (basic)
$t.after('<table class="sticky-head" />')

// If <tbody> contains <th>, then we create sticky column and intersect (advanced)
if($t.find('tbody th').length > 0) {
    $t.after('<table class="sticky-col" /><table class="sticky-intersect" />');
}
// Create shorthand for things
var $stickyHead  = $(this).siblings('.sticky-thead'),
    $stickyCol   = $(this).siblings('.sticky-col'),
    $stickyInsct = $(this).siblings('.sticky-intersect'),
    $stickyWrap  = $(this).parent('.sticky-wrap');

Step 3: Inserting cloned table contents

The trick now is to insert contents cloned from our original table into the newly created tables that will serve as our sticky elements:

  1. Sticky header will receive all contents from the cloned <thead> element
  2. Sticky column will receive contents from the first <th> from <thead> and all the subsequent <th> from <tbody>. This is assuming that each row only contains one table header cell.
  3. Sticky intersect will receive content from the top left most cell in the table

// Sticky header gets all content from <thead>
$stickyHead.append($thead);

// Sticky column gets content from the first <th> of both <thead> and <tbody>
$stickyCol
.append($col)
    .find('thead th:gt(0)').remove()
    .end()
    .find('tbody td').remove();

// Sticky intersect gets content from the first <th> in <thead>
$stickyInsct.html('<thead><tr><th>'+$t.find('thead th:first-child').html()+'</th></tr></thead>');

Step 4: Functions

Here comes the most important part of our jQuery script — we decide what functions are needed for sticky headers to work and we declare them with the var statement to allow for easy callback. Two functions immediately come to mind:

  1. A function to determine the widths of individual <th> elements in the cloned header. Since we only cloned the <thead> element, the computed width of the cloned header will not be the same as the actual header itself, since the content of <tbody> itself, which may or may not influence the final width of each individual columns, is not included.
  2. A function to position the sticky header, so that we can update the vertical offset of the cloned header that is absolutely positioned when the scroll event is fired.
  3. A function to position the sticky column, so that we can update the horizontal offset when the parent element is overflowing.
  4. A function to calculate allowance — this feature is explained later in greater detail.

You may ask, why do I have to calculate the vertical offset of the header instead of simply using position: fixed? I, too, have contemplated over this issue, but it came to my realization that if we are allowing the table to overflow along the x-axis, the fixed positioning option has to go out of the window, because it will not scroll with the table in the event of a horizontal overflow.

// Function 1: setWidths()
// Purpose: To set width of individually cloned element
var setWidths = function () {
        $t
        .find('thead th').each(function (i) {
            $stickyHead.find('th').eq(i).width($(this).width());
        })
        .end()
        .find('tr').each(function (i) {
            $stickyCol.find('tr').eq(i).height($(this).height());
        });

        // Set width of sticky table head
        $stickyHead.width($t.width());

        // Set width of sticky table col
        $stickyCol.find('th').add($stickyInsct.find('th')).width($t.find('thead th').width())

    },
// Function 2: repositionStickyHead()
// Purpose: To position the cloned sticky header (always present) appropriately
    repositionStickyHead = function () {
        // Return value of calculated allowance
        var allowance = calcAllowance();

        // Check if wrapper parent is overflowing along the y-axis
        if($t.height() > $stickyWrap.height()) {
            // If it is overflowing
            // Position sticky header based on wrapper's scrollTop()
            if($stickyWrap.scrollTop() > 0) {
                // When top of wrapping parent is out of view
                $stickyHead.add($stickyInsct).css({
                    opacity: 1,
                    top: $stickyWrap.scrollTop()
                });
            } else {
                // When top of wrapping parent is in view
                $stickyHead.add($stickyInsct).css({
                    opacity: 0,
                    top: 0
                });
            }
        } else {
            // If it is not overflowing (basic layout)
            // Position sticky header based on viewport scrollTop()
            if($w.scrollTop() > $t.offset().top && $w.scrollTop() < $t.offset().top + $t.outerHeight() - allowance) {                 // When top of viewport is within the table, and we set an allowance later
                // Action: Show sticky header and intersect, and set top to the right value
                $stickyHead.add($sticktInsct).css({
                    opacity: 1,
                   top: $w.scrollTop() - $t.offset().top
                });
             } else {
                 // When top of viewport is above or below table
                 // Action: Hide sticky header and intersect
                 $sticky.add($stickInsct).css({
                     opacity: 0,
                     top: 0
                 });
             }
        }
    },
// Function 3: repositionStickyCol()
// Purpose: To position the cloned sticky column (if present) appropriately
    repositionStickyCol = function () {
        if($stickyWrap.scrollLeft() > 0) {
            // When left of wrapping parent is out of view
            // Show sticky column and intersect
            $stickyCol.add($stickyInsct).css({
                opacity: 1,
                left: $stickyWrap.scrollLeft()
            });
        } else {
            // When left of wrapping parent is in view
            // Hide sticky column but not the intersect
            // Reset left position
            $stickyCol
            .css({ opacity: 0 })
            .add($stickyInsct).css({ left: 0 });
        }
    },
// Function 4: calcAllowance()
// Purpose: Return value of calculated allowance
     calcAllowance = function () {
         var a = 0;

         // Get sum of height of last three rows
         $t.find('tbody tr:lt(3)').each(function () {
             a += $(this).height();
         });

         // Set fail safe limit (last three row might be too tall)
         // Set arbitrary limit at 0.25 of viewport height, or you can use an arbitrary pixel value
         if(a > $w.height()*0.25) {
            a = $w.height()*0.25;
        }

        // Add height of sticky header itself
        a += $sticky.height();

        return a;
    };
}

Now, you may ask, what is allowance? What do we need it for? The basis of the allowance is simple — we do not want the sticky table header to follow us all the way to the end of the table, do we? It is unnecessary and run the risk of obfuscating the last table row. While this feature is optional (thus allowance is set to 0, see above), I highly recommend allowing at least one table row of height remaining. The height can be computed from the table itself, or you can set a fixed height.

As far as my experience go, I realize that I do not need the header much after the last three rows of the table is shown — that is because by then our eyes would have probably moved away from the table into the content below. This threshold is arbitrary and it is up to you to decide.

// Calculate allowance
// We allow the last three rows to be shown without the need for the sticky header to remain visible
$t.find('tbody tr:lt(4)').each(function () {
    allowance += $(this).height();
});

Step 5: Fire away, fire away!

Now we are done declaring all the functions we need for the correct styling and positioning of the sticky header. All is left is to bind event handlers to the $(window) object (previously abbreviated as $w for your convenience) and trigger the right function. Here is the game plan:

  1. When the DOM is ready, perform initial round of width calculations
  2. When all resources are loaded, perform second round of width calculations. This is important especially when your table contains resources that are loaded after DOM ready event, such as images, @font-face and more, which will influence how table column widths are computed.
  3. When the parent wrapper is scrolled, but this only happens if the content is overflowing. In the event of a scrolling event is detected, we want to reposition the sticky column
  4. When the viewport is resized, we want to recompute widths and reposition the sticky header
  5. When the window is scrolled, we want to reposition the sticky header

This can be easily summarized with the code below. Do note that the resize and scroll events are debounced and throttled respectively using Bel Alman's jQuery throttle+debounce plugin.

// #1: When DOM is ready (remember, we have wrapped this entire script in $(function(){...});
setWidths();

// #2: Listen to scrolling event on the parent wrapper (will fire if there is an overflow)
$t.parent('.sticky-wrap').scroll($.throttle(250, function() {
    repositionStickyHead();
    repositionStickyCol();
}));

// Now we bind events to the $(window) object
$w
// #3: When all resources are loaded
.load(setWidths)
// #4: When viewport is resized
// (we debounce this so successive resize event is coalesced into one event)
.resize($.throttle(250, function () {
    setWidths();
    repositionStickyHead();
    repositionStickyCol();
})
// #5: When the window is scrolled
// (we throttled this so scroll event is not fired too often)
.scroll($.throttle(250, repositionStickyHead);

And voila, you're done!

Discussion

No tutorial is complete without a discussion — be it addressing potential drawbacks on the technicalities of implementation, or the explanation of my strategy in contrary to common expectations.

Why don't you use position: fixed?

Fixed positioning is a very tantalizing alternative, mainly because of the two advantages it confers:

  1. No calculations are needed for the sticky table header's vertical offset, because fixed position will cause the element to be positioned absolutely within the viewport and out of the document flow.
  2. Avoids the stuttering effect of the sticky table header playing catch up, as the scroll event is throttled and therefore the calculations are performed at fixed time intervals and not on the fly. It may appear less responsive to user movement and therefore less natural.

However, the issue with fixed positioning is that we are effectively removing the element from the document flow. In the event when the table width exceeds that of its containing and a horizontal overflow is absolutely necessary, the fixed position header will not scroll with the table because it is detached from the document layout. This is one of the major drawbacks with many jQuery plugins out there that offers sticky table header functionality and this tutorial was written partially to address this issue.

Why don't you use position: sticky?

The new position attribute, position: sticky, is only available to the latest version of WebKit browsers and require vendor prefixes. It is not supported in Firefox, Internet Explorer and Opera, therefore risking alienating a huge user base (~95%) due to lack of support. It is not official and standardized as of yet, so I would rather err on the side of caution and choose a more cumbersome but cross-browser friendly JS-based solution.

View Demo

Thursday, January 09, 2014

jQuery and CSS3 Magnifying Glass for Images

jQuery and CSS3 Magnifying Glass for Images
Have you ever want to add a super cool effect to your site of product images and couldn't find a perfect match? I bet these magnifying glass effect should fits in any layout.

These magnifying glass is created using CSS3 box-shadow and border-radius properties. jQuery is used to position it at the cursor coordinates and change the background-position accordingly. Moving the cursor away from the image gently fades out the magnifying glass bringing the image back to the default state. The idea of this post is generated from the walkthrough of Thecodeplayer.

View Demo

<img class="magniflier" src="image.jpg" width="160"/>

Having the class magniflier is important, as it is what our Javascript code is going to check for and we have set a value of 160 to scale down the image size before the hovering.

.glass {
  width: 170px;
  height: 170px;
  position: absolute;
  border-radius: 50%;
  cursor: crosshair;
  
  /* Multiple box shadows to achieve the glass effect */
  box-shadow:
    0 0 0 7px rgba(255, 255, 255, 0.85),
    0 0 7px 7px rgba(0, 0, 0, 0.25), 
    inset 0 0 40px 2px rgba(0, 0, 0, 0.25);
    display: none;
}

The glass effect is simply achieved with basic CSS3 shadows and rounded corners and we have set the display to none so as to keep the glass invisible until it's hovered-on.

$(function() {

  var native_width = 0;
  var native_height = 0;
  var mouse = {x: 0, y: 0};
  var magnify;
  var cur_img;

  var ui = {
    magniflier: $('.magniflier')
  };

  // Connecting to the magnifying glass
  if (ui.magniflier.length) {
    var div = document.createElement('div');
    div.setAttribute('class', 'glass');
    ui.glass = $(div);

    $('body').append(div);
  }

  
  // All the magnifying will happen on "mousemove"

  var mouseMove = function(e) {
    var $el = $(this);

    // Container offset relative to document
    var magnify_offset = cur_img.offset();

    // Mouse position relative to container
    // pageX/pageY - container's offsetLeft/offetTop
    mouse.x = e.pageX - magnify_offset.left;
    mouse.y = e.pageY - magnify_offset.top;
    
    // The Magnifying glass should only show up when the mouse is inside
    // It is important to note that attaching mouseout and then hiding
    // the glass wont work cuz mouse will never be out due to the glass
    // being inside the parent and having a higher z-index (positioned above)
    if (
      mouse.x < cur_img.width() &&
      mouse.y < cur_img.height() &&
      mouse.x > 0 &&
      mouse.y > 0
      ) {

      magnify(e);
    }
    else {
      ui.glass.fadeOut(100);
    }

    return;
  };

  var magnify = function(e) {

    // The background position of div.glass will be
    // changed according to the position
    // of the mouse over the img.magniflier
    //
    // So we will get the ratio of the pixel
    // under the mouse with respect
    // to the image and use that to position the
    // large image inside the magnifying glass

    var rx = Math.round(mouse.x/cur_img.width()*native_width - ui.glass.width()/2)*-1;
    var ry = Math.round(mouse.y/cur_img.height()*native_height - ui.glass.height()/2)*-1;
    var bg_pos = rx + "px " + ry + "px";
    
    // Calculate pos for magnifying glass
    //
    // Easy Logic: Deduct half of width/height
    // from mouse pos.

    // var glass_left = mouse.x - ui.glass.width() / 2;
    // var glass_top  = mouse.y - ui.glass.height() / 2;
    var glass_left = e.pageX - ui.glass.width() / 2;
    var glass_top  = e.pageY - ui.glass.height() / 2;
    //console.log(glass_left, glass_top, bg_pos)
    // Now, if you hover on the image, you should
    // see the magnifying glass in action
    ui.glass.css({
      left: glass_left,
      top: glass_top,
      backgroundPosition: bg_pos
    });

    return;
  };

  $('.magniflier').on('mousemove', function() {
    ui.glass.fadeIn(100);
    
    cur_img = $(this);

    var large_img_loaded = cur_img.data('large-img-loaded');
    var src = cur_img.data('large') || cur_img.attr('src');

    // Set large-img-loaded to true
    // cur_img.data('large-img-loaded', true)

    if (src) {
      ui.glass.css({
        'background-image': 'url(' + src + ')',
        'background-repeat': 'no-repeat'
      });
    }

    // When the user hovers on the image, the script will first calculate
    // the native dimensions if they don't exist. Only after the native dimensions
    // are available, the script will show the zoomed version.
    //if(!native_width && !native_height) {

      if (!cur_img.data('native_width')) {
        // This will create a new image object with the same image as that in .small
        // We cannot directly get the dimensions from .small because of the
        // width specified to 200px in the html. To get the actual dimensions we have
        // created this image object.
        var image_object = new Image();

        image_object.onload = function() {
          // This code is wrapped in the .load function which is important.
          // width and height of the object would return 0 if accessed before
          // the image gets loaded.
          native_width = image_object.width;
          native_height = image_object.height;

          cur_img.data('native_width', native_width);
          cur_img.data('native_height', native_height);

          //console.log(native_width, native_height);

          mouseMove.apply(this, arguments);

          ui.glass.on('mousemove', mouseMove);
        };


        image_object.src = src;
        
        return;
      } else {

        native_width = cur_img.data('native_width');
        native_height = cur_img.data('native_height');
      }
    //}
    //console.log(native_width, native_height);

    mouseMove.apply(this, arguments);

    ui.glass.on('mousemove', mouseMove);
  });

  ui.glass.on('mouseout', function() {
    ui.glass.off('mousemove', mouseMove);
  });

});

Conclusion

Read through every attribution for better understanding of what operation each line performed.

  • Use the class magniflier to enable the effect on any image.
  • Attach data-large="image.jpg" to the HTML markup if you want to use different image for the zoomed version.

Now you have a simple-to-use magnifying glass plugin for your next project.

Thursday, January 09, 2014

45 Useful JavaScript Tips, Tricks and Best Practices

45 Useful JavaScript Tips, Tricks and Best Practices
As you know, JavaScript is the number one programming language in the world, the language of the web, of mobile hybrid apps (like PhoneGap or Appcelerator), of the server side (like NodeJS or Wakanda) and has many other implementations. It's also the starting point for many new developers to the world of programming, as it can be used to display a simple alert in the web browser but also to control a robot (using nodebot, or nodruino). The developers who master JavaScript and write organized and performant code have become the most sought after in the job market.

Friday, December 13, 2013

Colorpeek, Part 2: Building Your First Chrome Extension

Building Your First Chrome Extension

The following is a guest post by Tyler Sticka. Tyler created a tool called Colorpeek. Yesterday we looked at the what and why of things. Today we'll look at how he built the Chrome Extension, which will serve as a great tutorial on how you can get started building your own Chrome Extensions.

Saturday, December 07, 2013

Device State Detection with CSS Media Queries and JavaScript

Device State Detection with CSS Media Queries and JavaScript

Being able to detect device state at any given moment is important for any number of reasons and so it's important that web app CSS and JavaScript are in sync with each other. In working on the Mozilla Developer Networks' redesign, I found that our many media queries, although helpful, sometimes left JavaScript in the dark about the device state. Is the user viewing the site in desktop, tablet, or phone screen size? Easy from a CSS perspective but CSS doesn't directly speak with JavaScript. I've created a system based on media queries and z-index which can tell me which media query the user is viewing the site in at any given time, so that I can make adjustments to dynamic functionality whenever I want!

Wednesday, December 04, 2013

Javascript Hacks for Hipsters

Javascript Hacks for Hipsters
Javascript is so much fun, except when it's not.

There's always the fear of runtime errors that keeps us thinking all the time while writing code. It makes us better coders - we have no other option than to visualize every line of code as if it's running as we write it.

That's why it's so important to have tidy code. Small code. Pretty code. Code you just fall in love with. Otherwise, Javascript will scare you away.

Tuesday, November 26, 2013

Creating a Mobile HTML5 Application with App Framework

HTML5 Application with App Framework

App Framework is a JavaScript library for mobile HTML5 app development. It allows you to build simple, rich and full HTML5/JavaScript mobile applications. This short tutorial is an introduction to the App Framework and it presents the basic concepts and its main concepts.

Wednesday, November 20, 2013

21 JavaScript Parts I Struggle To Remember

21 JavaScript Parts I Struggle To Remember
This article is a review of the JavaScript ES3 parts that, for whatever reason, fade over time in my mind or I outright forget about. Some of the parts mentioned are quirks and some are just plain language realities that I personally find difficult to keep straight.

The eluding parts I discuss here are not focused on method nuances that can be resolved by referring to a JavaScript reference. I have tried to mainly focus on the parts of JavaScript that cannot easily be found in a language reference (i.e the difference between apply() and call()).

Friday, October 18, 2013

Why (and How) you Should Probably Use Web Notifications

Web Notifications

Web notifications are a way to show users some sort of message in a browser standardized way. With Chrome 29, Google has fully implemented the Chrome Notification Center on Windows, Mac and Chrome OS, which makes the idea of using notifications a lot more enticing.

Sunday, October 06, 2013

Working with IndexedDB

Working with IndexedDB
One of the more interesting developments in web standards lately is the Indexed Database (IndexedDB for short) specification. For a fun time you can read the spec yourself. In this tutorial I'll be explaining this feature and hopefully giving you some inspiration to use this powerful feature yourself.

Overview

In a nutshell, IndexedDB provides a way for you to store large amounts of data on your user's browser. Any application that needs to send a lot of data over the wire could greatly benefit from being able to store that data on the client instead. Of course storage is only part of the equation. IndexedDB also provides a powerful indexed based searching API to retrieve the data you need.

Saturday, October 05, 2013

A preview of the new dialog element

dialog element

The <dialog> element originally entered the HTML5 scene as a way to markup conversations but it was cut from the spec back in 2009. However now it's back, and it has a brand new role.

The new <dialog> element makes it really easy for developers to create popup dialogs and modals for their web applications. Before now this required using a JavaScript plugin. However popup dialogs have become so popular that the Chrome team have decided to create a native implementation of this UI component.

Thursday, October 03, 2013

Animated border menus

Animated border menus

A tutorial on how to create a off-canvas icon navigation with an animated border effect. The menu effect is inspired by CreativeDash's bounce menu for mobile apps.

Thursday, October 03, 2013

Write your CSS with JavaScript

Write your CSS with JavaScript

Sometimes programming is just using the right tool. This may be a framework, library or as it happens in my case CSS preprocessor. You probably don't realize it, but LESS or SASS have a lot of constraints. I managed to change that by writing my own CSS preprocessor. I stopped writing CSS and moved everything into the JavaScript world. This article is about AbsurdJS: a small Node.js module, which changed my workflow completely.

Sunday, September 29, 2013

An introduction to the Page Visibility API

Page Visibility API

The days of browsing the web using a single window (or tab) are long gone. Most of us now browse with multiple windows and/or tabs open at the same time. As developers we have never had a way of telling whether our web page is visible to the user or if it's buried away amongst a stack of inactive tabs. This is all changing due to the introduction of the Page Visibility API.

Sunday, September 29, 2013

Reading files using the HTML5 FileReader API

HTML5 FileReader API

HTML5 saw the introduction of a number of new APIs that can be used to handle files in the browser. These APIs make it much easier to accomplish tasks like reading and writing files or uploading a file created using JavaScript.

Sunday, September 29, 2013

Controlling CSS Animations and Transitions with JavaScript

Controlling CSS Animations and Transitions with JavaScript

Web designers sometimes believe that animating in CSS is more difficult than animating in JavaScript. While CSS animation does have some limitations, most of the time it's more capable than we give it credit for! Not to mention, typically more performant.

Tuesday, August 20, 2013

Introduction to Animating in HTML

Animating in HTML

Over the last few years, designers have begun to use a lot of animations directly within HTML. That's kind of cool, as you don't need a plugin in order to see their work. There are several ways to make animations in HTML and in this article I will summarize a lot of examples and techniques for creating animations directly in HTML using both JavaScript and CSS.

Tuesday, July 09, 2013

Expanding Search Bar Deconstructed

Expanding Search Bar

Summarized, this is what we want the search component to do:

  • Initially, we only want to show a button with a search icon.
  • When clicking on the icon, we want a search input to slide out.
  • The component should be fluid, meaning that we can use it in a responsive context.
  • When we type something we want to be able to submit the form by either hitting enter or clicking on the search icon.

Thursday, May 16, 2013

Promise-Based Validation

Promise-Based Validation

The concept of "Promises" has changed the way we write asynchronous JavaScript. Over the past year, many frameworks have incorporated some form of the Promise pattern to make asynchronous code easier to write, read and maintain. For example, jQuery added $.Deferred() and NodeJS has the Q and jspromise modules that work on both client and server. Client-side MVC frameworks, such as EmberJS and AngularJS, also implement their own versions of Promises.