Swap templates-sdk and templates-sdk-dev files to enable redesign builds by default.

Change-Id: I9eabbbcd823fb29bd2209172c458cb9dad5f24d2
diff --git a/tools/droiddoc/templates-sdk/assets/js/docs.js b/tools/droiddoc/templates-sdk/assets/js/docs.js
index 7f4be4e..ca64217 100644
--- a/tools/droiddoc/templates-sdk/assets/js/docs.js
+++ b/tools/droiddoc/templates-sdk/assets/js/docs.js
@@ -82,7 +82,7 @@
          .after('<hr/>');
 
   // set up the search close button
-  $('.search .close').click(function() {
+  $('#search-close').click(function() {
     $searchInput = $('#search_autocomplete');
     $searchInput.attr('value', '');
     $(this).addClass("hide");
@@ -92,32 +92,6 @@
     hideResults();
   });
 
-  // Set up quicknav
-  var quicknav_open = false;
-  $("#btn-quicknav").click(function() {
-    if (quicknav_open) {
-      $(this).removeClass('active');
-      quicknav_open = false;
-      collapse();
-    } else {
-      $(this).addClass('active');
-      quicknav_open = true;
-      expand();
-    }
-  })
-
-  var expand = function() {
-   $('#header-wrap').addClass('quicknav');
-   $('#quicknav').stop().show().animate({opacity:'1'});
-  }
-
-  var collapse = function() {
-    $('#quicknav').stop().animate({opacity:'0'}, 100, function() {
-      $(this).hide();
-      $('#header-wrap').removeClass('quicknav');
-    });
-  }
-
 
   //Set up search
   $("#search_autocomplete").focus(function() {
@@ -180,73 +154,71 @@
 
   // Highlight the header tabs...
   // highlight Design tab
-  if ($("body").hasClass("design")) {
-    $("#header li.design a").addClass("selected");
-    $("#sticky-header").addClass("design");
+  var urlSegments = pagePathOriginal.split('/');
+  var navEl = $(".dac-nav-list");
+  var subNavEl = navEl.find(".dac-nav-secondary");
+  var parentNavEl;
 
+  if ($("body").hasClass("design")) {
+    navEl.find("> li.design > a").addClass("selected");
   // highlight About tabs
   } else if ($("body").hasClass("about")) {
-    var rootDir = pagePathOriginal.substring(1,pagePathOriginal.indexOf('/', 1));
-    if (rootDir == "about") {
-      $("#nav-x li.about a").addClass("selected");
-    } else if (rootDir == "wear") {
-      $("#nav-x li.wear a").addClass("selected");
-    } else if (rootDir == "tv") {
-      $("#nav-x li.tv a").addClass("selected");
-    } else if (rootDir == "auto") {
-      $("#nav-x li.auto a").addClass("selected");
+    if (urlSegments[1] == "about" || urlSegments[1] == "wear" || urlSegments[1] == "tv" || urlSegments[1] == "auto") {
+      navEl.find("> li.home > a").addClass('has-subnav');
+      subNavEl.find("li." + urlSegments[1] + " > a").addClass("selected");
+    } else {
+      navEl.find("> li.home > a").addClass('selected');
     }
   // highlight Develop tab
   } else if ($("body").hasClass("develop") || $("body").hasClass("google")) {
-    $("#header li.develop a").addClass("selected");
-    $("#sticky-header").addClass("develop");
+    parentNavEl = navEl.find("> li.develop > a");
+    parentNavEl.addClass('has-subnav');
+
     // In Develop docs, also highlight appropriate sub-tab
-    var rootDir = pagePathOriginal.substring(1,pagePathOriginal.indexOf('/', 1));
-    if (rootDir == "training") {
-      $("#nav-x li.training a").addClass("selected");
-    } else if (rootDir == "guide") {
-      $("#nav-x li.guide a").addClass("selected");
-    } else if (rootDir == "reference") {
+    if (urlSegments[1] == "training") {
+      subNavEl.find("li.training > a").addClass("selected");
+    } else if (urlSegments[1] == "guide") {
+      subNavEl.find("li.guide > a").addClass("selected");
+    } else if (urlSegments[1] == "reference") {
       // If the root is reference, but page is also part of Google Services, select Google
       if ($("body").hasClass("google")) {
-        $("#nav-x li.google a").addClass("selected");
+        subNavEl.find("li.google > a").addClass("selected");
       } else {
-        $("#nav-x li.reference a").addClass("selected");
+        subNavEl.find("li.reference > a").addClass("selected");
       }
-    } else if ((rootDir == "tools") || (rootDir == "sdk")) {
-      $("#nav-x li.tools a").addClass("selected");
+    } else if ((urlSegments[1] == "tools") || (urlSegments[1] == "sdk")) {
+      subNavEl.find("li.tools > a").addClass("selected");
     } else if ($("body").hasClass("google")) {
-      $("#nav-x li.google a").addClass("selected");
+      subNavEl.find("li.google > a").addClass("selected");
     } else if ($("body").hasClass("samples")) {
-      $("#nav-x li.samples a").addClass("selected");
+      subNavEl.find("li.samples > a").addClass("selected");
+    } else {
+      parentNavEl.removeClass('has-subnav').addClass("selected");
     }
-
   // highlight Distribute tab
   } else if ($("body").hasClass("distribute")) {
-    $("#header li.distribute a").addClass("selected");
-    $("#sticky-header").addClass("distribute");
+    parentNavEl = navEl.find("> li.distribute > a");
+    parentNavEl.addClass('has-subnav');
 
-    var baseFrag = pagePathOriginal.indexOf('/', 1) + 1;
-    var secondFrag = pagePathOriginal.substring(baseFrag, pagePathOriginal.indexOf('/', baseFrag));
-    if (secondFrag == "users") {
-      $("#nav-x li.users a").addClass("selected");
-    } else if (secondFrag == "engage") {
-      $("#nav-x li.engage a").addClass("selected");
-    } else if (secondFrag == "monetize") {
-      $("#nav-x li.monetize a").addClass("selected");
-    } else if (secondFrag == "analyze") {
-      $("#nav-x li.analyze a").addClass("selected");
-    } else if (secondFrag == "tools") {
-      $("#nav-x li.disttools a").addClass("selected");
-    } else if (secondFrag == "stories") {
-      $("#nav-x li.stories a").addClass("selected");
-    } else if (secondFrag == "essentials") {
-      $("#nav-x li.essentials a").addClass("selected");
-    } else if (secondFrag == "googleplay") {
-      $("#nav-x li.googleplay a").addClass("selected");
+    if (urlSegments[2] == "users") {
+      subNavEl.find("li.users > a").addClass("selected");
+    } else if (urlSegments[2] == "engage") {
+      subNavEl.find("li.engage > a").addClass("selected");
+    } else if (urlSegments[2] == "monetize") {
+      subNavEl.find("li.monetize > a").addClass("selected");
+    } else if (urlSegments[2] == "analyze") {
+      subNavEl.find("li.analyze > a").addClass("selected");
+    } else if (urlSegments[2] == "tools") {
+      subNavEl.find("li.disttools > a").addClass("selected");
+    } else if (urlSegments[2] == "stories") {
+      subNavEl.find("li.stories > a").addClass("selected");
+    } else if (urlSegments[2] == "essentials") {
+      subNavEl.find("li.essentials > a").addClass("selected");
+    } else if (urlSegments[2] == "googleplay") {
+      subNavEl.find("li.googleplay > a").addClass("selected");
+    } else {
+      parentNavEl.removeClass('has-subnav').addClass("selected");
     }
-  } else if ($("body").hasClass("about")) {
-    $("#sticky-header").addClass("about");
   }
 
   // set global variable so we can highlight the sidenav a bit later (such as for google reference)
@@ -392,13 +364,12 @@
 
     var $olClasses  = $('<ol class="class-list"></ol>');
     var $liClass;
-    var $imgIcon;
     var $h2Title;
     var $pSummary;
     var $olLessons;
     var $liLesson;
     $classLinks.each(function(index) {
-      $liClass  = $('<li></li>');
+      $liClass  = $('<li class="clearfix"></li>');
       $h2Title  = $('<a class="title" href="'+$(this).attr('href')+'"><h2>' + $(this).html()+'</h2><span></span></a>');
       $pSummary = $('<p class="description">' + $classDescriptions[index] + '</p>');
 
@@ -407,18 +378,14 @@
       $lessons = $(this).closest('li').find('ul li a');
 
       if ($lessons.length) {
-        $imgIcon = $('<img src="'+toRoot+'assets/images/resource-tutorial.png" '
-            + ' width="64" height="64" alt=""/>');
         $lessons.each(function(index) {
           $olLessons.append('<li><a href="'+$(this).attr('href')+'">' + $(this).html()+'</a></li>');
         });
       } else {
-        $imgIcon = $('<img src="'+toRoot+'assets/images/resource-article.png" '
-            + ' width="64" height="64" alt=""/>');
         $pSummary.addClass('article');
       }
 
-      $liClass.append($h2Title).append($imgIcon).append($pSummary).append($olLessons);
+      $liClass.append($h2Title).append($pSummary).append($olLessons);
       $olClasses.append($liClass);
     });
     $('.jd-descr').append($olClasses);
@@ -504,15 +471,6 @@
   po.src = 'https://apis.google.com/js/plusone.js';
   var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
 
-
-  // Revise the sidenav widths to make room for the scrollbar
-  // which avoids the visible width from changing each time the bar appears
-  var $sidenav = $("#side-nav");
-  var sidenav_width = parseInt($sidenav.innerWidth());
-
-  $("#devdoc-nav  #nav").css("width", sidenav_width - 4 + "px"); // 4px is scrollbar width
-
-
   $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller
 
   if ($(".scroll-pane").length > 1) {
@@ -586,6 +544,15 @@
       });
     });
   }
+
+  // Responsive testing
+  var responsiveParam = location.href.match(/[?&]responsive=?(|true|false)/);
+  if (responsiveParam) {
+    localStorage['test-responsive'] = ['', 'true'].indexOf(responsiveParam) > -1;
+  }
+  if (localStorage['test-responsive']) {
+    $(document.body).addClass('responsive');
+  }
 });
 // END of the onload event
 
@@ -738,21 +705,28 @@
 
 /** Create the list of breadcrumb links in the sticky header */
 function buildBreadcrumbs() {
-  var $breadcrumbUl =  $("#sticky-header ul.breadcrumb");
+  var $breadcrumbUl =  $(".dac-header-crumbs");
+  var primaryNavLink = ".dac-nav-list > .dac-nav-item > .dac-nav-link";
+
   // Add the secondary horizontal nav item, if provided
-  var $selectedSecondNav = $("div#nav-x ul.nav-x a.selected").clone().removeClass("selected");
+  var $selectedSecondNav = $(".dac-nav-secondary .dac-nav-link.selected").clone()
+    .attr('class', 'dac-header-crumbs-link');
+
   if ($selectedSecondNav.length) {
-    $breadcrumbUl.prepend($("<li>").append($selectedSecondNav))
+    $breadcrumbUl.prepend($('<li class="dac-header-crumbs-item">').append($selectedSecondNav));
   }
+
   // Add the primary horizontal nav
-  var $selectedFirstNav = $("div#header-wrap ul.nav-x a.selected").clone().removeClass("selected");
+  var $selectedFirstNav = $(primaryNavLink + ".selected, " + primaryNavLink + ".has-subnav").clone()
+    .attr('class', 'dac-header-crumbs-link');
+
   // If there's no header nav item, use the logo link and title from alt text
   if ($selectedFirstNav.length < 1) {
-    $selectedFirstNav = $("<a>")
+    $selectedFirstNav = $('<a class="dac-header-crumbs-link">')
         .attr('href', $("div#header .logo a").attr('href'))
         .text($("div#header .logo img").attr('alt'));
   }
-  $breadcrumbUl.prepend($("<li>").append($selectedFirstNav));
+  $breadcrumbUl.prepend($('<li class="dac-header-crumbs-item">').append($selectedFirstNav));
 }
 
 
@@ -824,7 +798,7 @@
 function updateSideNavPosition() {
   var newLeft = $(window).scrollLeft() - navBarLeftPos;
   $('#devdoc-nav').css({left: -newLeft});
-  $('#devdoc-nav .totop').css({left: -(newLeft - parseInt($('#side-nav').css('margin-left')))});
+  $('#devdoc-nav .totop').css({left: -(newLeft - parseInt($('#side-nav').css('padding-left')))});
 }
 
 // TODO: use $(document).ready instead
@@ -1068,7 +1042,7 @@
 /* Sets the vertical scoll position at which the sticky bar should appear.
    This method is called to reset the position when search results appear or hide */
 function setStickyTop() {
-  stickyTop = $('#header-wrapper').outerHeight() - $('#sticky-header').outerHeight();
+  stickyTop = $('#header-wrapper').outerHeight() - $('#header > .dac-header-inner').outerHeight();
 }
 
 /*
@@ -1078,8 +1052,7 @@
 
   setStickyTop();
   var hiding = false;
-  var $stickyEl = $('#sticky-header');
-  var $menuEl = $('.menu-container');
+  var $headerEl = $('#header');
   // Exit if there's no sidenav
   if ($('#side-nav').length == 0) return;
   // Exit if the mouse target is a DIV, because that means the event is coming
@@ -1120,16 +1093,14 @@
         .css({'width':'auto','margin':''})
         .prependTo('#side-nav');
     // delay hide the sticky
-    $menuEl.removeClass('sticky-menu');
-    $stickyEl.fadeOut(250);
+    $headerEl.removeClass('is-sticky');
     hiding = false;
 
     // update the sidenaav position for side scrolling
     updateSideNavPosition();
   } else if (!sticky && shouldBeSticky) {
     sticky = true;
-    $stickyEl.fadeIn(10);
-    $menuEl.addClass('sticky-menu');
+    $headerEl.addClass('is-sticky');
 
     // make the sidenav fixed
     var width = $('#devdoc-nav').width();
@@ -1142,8 +1113,7 @@
     updateSideNavPosition();
 
   } else if (hiding && top < 15) {
-    $menuEl.removeClass('sticky-menu');
-    $stickyEl.hide();
+    $headerEl.removeClass('is-sticky');
     hiding = false;
   }
   resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance
@@ -1841,12 +1811,11 @@
     // if there are api results
     if ((gMatches.length > 0) || (gGoogleMatches.length > 0)) {
       // reveal suggestion list
-      $('.suggest-card.dummy').show();
       $('.suggest-card.reference').show();
       var listIndex = 0; // list index position
 
       // reset the lists
-      $(".search_filtered_wrapper.reference li").remove();
+      $(".suggest-card.reference li").remove();
 
       // ########### ANDROID RESULTS #############
       if (gMatches.length > 0) {
@@ -1876,13 +1845,12 @@
       }
     } else {
       $('.suggest-card.reference').hide();
-      $('.suggest-card.dummy').hide();
     }
 
     // ########### JD DOC RESULTS #############
     if (gDocsMatches.length > 0) {
         // reset the lists
-        $(".search_filtered_wrapper.docs li").remove();
+        $(".suggest-card:not(.reference) li").remove();
 
         // determine google results to show
         // NOTE: The order of the conditions below for the sugg.type MUST BE SPECIFIC:
@@ -1947,7 +1915,7 @@
         }
 
     } else {
-      $('.search_filtered_wrapper.docs .suggest-card:not(.dummy)').hide(300);
+      $('.suggest-card:not(.reference)').hide(300);
     }
 }
 
@@ -1971,14 +1939,14 @@
 
     // show/hide the close button
     if (text != '') {
-        $(".search .close").removeClass("hide");
+        $("#search-close").removeClass("hide");
     } else {
-        $(".search .close").addClass("hide");
+        $("#search-close").addClass("hide");
     }
     // 27 = esc
     if (e.keyCode == 27) {
         // close all search results
-        if (kd) $('.search .close').trigger('click');
+        if (kd) $('#search-close').trigger('click');
         return true;
     }
     // 13 = enter
@@ -2536,7 +2504,7 @@
 {
     if (!focused) {
         if(obj.value == ""){
-          $(".search .close").addClass("hide");
+          $("#search-close").addClass("hide");
         }
         $(".suggest-card").hide();
     }
@@ -2553,7 +2521,7 @@
 
 function hideResults() {
   $("#searchResults").slideUp('fast', setStickyTop);
-  $(".search .close").addClass("hide");
+  $("#search-close").addClass("hide");
   location.hash = '';
 
   $("#search_autocomplete").val("").blur();
@@ -2670,7 +2638,7 @@
   } else {
     // first time loading search results for this page
     $('#searchResults').slideDown('slow', setStickyTop);
-    $(".search .close").removeClass("hide");
+    $("#search-close").removeClass("hide");
     loadSearchResults();
   }
 }, true);
@@ -2714,7 +2682,7 @@
   searchControl.execute(query);
   $('#searchResults').slideDown('slow', setStickyTop);
   $("#search_autocomplete").focus();
-  $(".search .close").removeClass("hide");
+  $("#search-close").removeClass("hide");
 
   updateResultTitle(query);
 });
@@ -3536,6 +3504,10 @@
   var addedPageResources = {};
 
   $(document).ready(function() {
+    // Need to initialize hero carousel before other sections for dedupe
+    // to work correctly.
+    $('[data-carousel-query]').dacCarouselQuery();
+
     $('.resource-widget').each(function() {
       initResourceWidget(this);
     });
@@ -3545,8 +3517,8 @@
     showing lines that are cut off. This works with the css ellipsis
     classes to fade last text line and apply an ellipsis char. */
 
-    //card text currently uses 15px line height.
-    var lineHeight = 15;
+    //card text currently uses 20px line height.
+    var lineHeight = 20;
     $('.card-info .text').ellipsisfade(lineHeight);
   });
 
@@ -3562,11 +3534,10 @@
         isCarousel = $widget.hasClass('resource-carousel-layout'),
         isStack = $widget.hasClass('resource-stack-layout');
 
-    // find size of widget by pulling out its class name
-    var sizeCols = 1;
+    // remove illegal col-x class which is not relevant anymore thanks to responsive styles.
     var m = $widget.get(0).className.match(/\bcol-(\d+)\b/);
-    if (m) {
-      sizeCols = parseInt(m[1], 10);
+    if (m && !$widget.is('.cols > *')) {
+      $widget.removeClass('col-' + m[1]);
     }
 
     var opts = {
@@ -3576,7 +3547,6 @@
       sortOrder: $widget.data('sortorder'),
       query: $widget.data('query'),
       section: $widget.data('section'),
-      sizeCols: sizeCols,
       /* Added by LFL 6/6/14 */
       resourceStyle: $widget.data('resourcestyle') || 'card',
       stackSort: $widget.data('stacksort') || 'true'
@@ -3604,7 +3574,7 @@
   /* Initializes a Resource Carousel Widget */
   function drawResourcesCarouselWidget($widget, opts, resources) {
     $widget.empty();
-    var plusone = true; //always show plusone on carousel
+    var plusone = false; // stop showing plusone buttons on cards
 
     $widget.addClass('resource-card slideshow-container')
       .append($('<a>').addClass('slideshow-prev').text('Prev'))
@@ -3642,7 +3612,7 @@
   function drawResourcesStackWidget($widget, opts, resources, sections) {
     // Don't empty widget, grab all items inside since they will be the first
     // items stacked, followed by the resource query
-    var plusone = true; //by default show plusone on section cards
+    var plusone = false; // stop showing plusone buttons on cards
     var cards = $widget.find('.resource-card').detach().toArray();
     var numStacks = opts.numStacks || 1;
     var $stacks = [];
@@ -3737,22 +3707,33 @@
 
     return $el;
   }
+  
+  function createResponsiveFlowColumn(cardSize) {
+    var cardWidth = parseInt(cardSize.match(/(\d+)/)[1], 10);
+    var column = $('<div>').addClass('col-' + (cardWidth / 3) + 'of6');
+    if (cardWidth < 9) {
+      column.addClass('col-tablet-1of2');
+    } else if (cardWidth > 9 && cardWidth < 18) {
+      column.addClass('col-tablet-1of1');
+    }
+    if (cardWidth < 18) {
+      column.addClass('col-mobile-1of1')
+    }
+    return column;
+  }
 
   /* Initializes a flow widget, see distribute.scss for generating accompanying css */
   function drawResourcesFlowWidget($widget, opts, resources) {
-    $widget.empty();
+    $widget.empty().addClass('cols');
     var cardSizes = opts.cardSizes || ['6x6'];
     var i = 0, j = 0;
-    var plusone = true; // by default show plusone on resource cards
+    var plusone = false; // stop showing plusone buttons on cards
 
     while (i < resources.length) {
       var cardSize = cardSizes[j++ % cardSizes.length];
       cardSize = cardSize.replace(/^\s+|\s+$/,'');
-      // Some card sizes do not get a plusone button, such as where space is constrained
-      // or for cards commonly embedded in docs (to improve overall page speed).
-      plusone = !((cardSize == "6x2") || (cardSize == "6x3") ||
-                  (cardSize == "9x2") || (cardSize == "9x3") ||
-                  (cardSize == "12x2") || (cardSize == "12x3"));
+      
+      var column = createResponsiveFlowColumn(cardSize).appendTo($widget);
 
       // A stack has a third dimension which is the number of stacked items
       var isStack = cardSize.match(/(\d+)x(\d+)x(\d+)/);
@@ -3763,7 +3744,7 @@
         // Create a stack container which should have the dimensions defined
         // by the product of the items inside.
         $stackDiv = $('<div>').addClass('resource-card-stack resource-card-' + isStack[1]
-            + 'x' + isStack[2] * isStack[3]) .appendTo($widget);
+            + 'x' + isStack[2] * isStack[3]) .appendTo(column);
       }
 
       // Build each stack item or just a single item
@@ -3785,7 +3766,7 @@
           stackCount = 0;
         }
 
-        $card.appendTo($stackDiv || $widget);
+        $card.appendTo($stackDiv || column);
 
       } while (++i < resources.length && stackCount > 0);
     }
@@ -3800,6 +3781,10 @@
   }
 
   function buildResourceList(opts) {
+    return $.queryResources(opts);
+  }
+
+  $.queryResources = function(opts) {
     var maxResults = opts.maxResults || 100;
 
     var query = opts.query || '';
@@ -3848,8 +3833,9 @@
 
       // add to list of already added indices
       for (var j = 0; j < resources.length; j++) {
-        // console.log(resources[j].title);
-        addedResourceIndices[resources[j].index] = 1;
+        if (resources[j]) {
+          addedResourceIndices[resources[j].index] = 1;
+        }
       }
 
       // concat to final results list
@@ -3891,7 +3877,7 @@
 
   function getResourceNotAlreadyAddedFilter(addedResourceIndices) {
     return function(resource) {
-      return !addedResourceIndices[resource.index];
+      return resource && !addedResourceIndices[resource.index];
     };
   }
 
@@ -4155,7 +4141,7 @@
             $this.parent().siblings().each(function ()
             {
               if ($(this).is(":visible")) {
-                var h = $(this).height();
+                var h = $(this).outerHeight(true);
                 remainingHeight = remainingHeight - h;
               }
             });
@@ -4354,3 +4340,467 @@
     }
   }
 })();
+
+(function($) {
+  'use strict';
+
+  /**
+   * Toggle Floating Label state.
+   * @param {HTMLElement} el - The DOM element.
+   * @param options
+   * @constructor
+   */
+  function FloatingLabel(el, options) {
+    this.el = $(el);
+    this.options = $.extend({}, FloatingLabel.DEFAULTS_, options);
+    this.group = this.el.closest('.dac-form-input-group');
+    this.input = this.group.find('.dac-form-input');
+
+    this.checkValue_ = this.checkValue_.bind(this);
+    this.checkValue_();
+
+    this.input.on('focus', function() {
+      this.group.addClass('dac-focused');
+    }.bind(this));
+    this.input.on('blur', function() {
+      this.group.removeClass('dac-focused');
+      this.checkValue_();
+    }.bind(this));
+    this.input.on('keyup', this.checkValue_);
+  }
+
+  /**
+   * The label is moved out of the textbox when it has a value.
+   */
+  FloatingLabel.prototype.checkValue_ = function() {
+    if (this.input.val().length) {
+      this.group.addClass('dac-has-value');
+    } else {
+      this.group.removeClass('dac-has-value');
+    }
+  };
+
+  /**
+   * jQuery plugin
+   * @param  {object} options - Override default options.
+   */
+  $.fn.dacFloatingLabel = function(options) {
+    return this.each(function() {
+      new FloatingLabel(this, options);
+    });
+  };
+
+  $(document).on('ready.aranja', function() {
+    $('.dac-form-floatlabel').each(function() {
+      $(this).dacFloatingLabel($(this).data());
+    });
+  });
+})(jQuery);
+
+/* global toRoot, CAROUSEL_OVERRIDE */
+(function($) {
+  // Ordering matters
+  var TAG_MAP = [
+    {from: 'developerstory', to: 'Android Developer Story'},
+    {from: 'googleplay', to: 'Google Play'}
+  ];
+
+  function DacCarouselQuery(el) {
+    this.el = $(el);
+
+    var opts = this.el.data();
+    opts.maxResults = parseInt(opts.maxResults || '100', 10);
+    opts.query = opts.carouselQuery;
+    var resources = $.queryResources(opts);
+
+    this.el.empty();
+    $(resources).map(function() {
+      var resource = $.extend({}, this, CAROUSEL_OVERRIDE[this.url]);
+      var slide = $('<article class="dac-expand dac-hero">');
+      var image = cleanUrl(resource.heroImage || resource.image);
+      var fullBleed = image && !resource.heroColor;
+
+      // Configure background
+      slide.css({
+        backgroundImage: fullBleed ? 'url(' + image + ')' : '',
+        backgroundColor: resource.heroColor || ''
+      });
+
+      // Should copy be inverted
+      slide.toggleClass('dac-invert', resource.heroInvert || fullBleed);
+      slide.toggleClass('dac-darken', fullBleed);
+
+      var cols = $('<div class="cols dac-hero-content">');
+
+      // inline image column
+      var rightCol = $('<div class="col-1of2 col-push-1of2 dac-hero-figure">')
+        .appendTo(cols);
+
+      if (!fullBleed && image) {
+        rightCol.append($('<img>').attr('src', image));
+      }
+
+      // info column
+      $('<div class="col-1of2 col-pull-1of2">')
+        .append($('<div class="dac-hero-tag">').text(formatTag(resource)))
+        .append($('<h1 class="dac-hero-title">').text(formatTitle(resource)))
+        .append($('<p class="dac-hero-description">').text(resource.summary))
+        .append($('<a class="dac-hero-cta">')
+          .text(formatCTA(resource))
+          .attr('href', cleanUrl(resource.url))
+          .prepend($('<span class="dac-sprite dac-auto-chevron">'))
+        )
+        .appendTo(cols);
+
+      slide.append(cols.wrap('<div class="wrap">').parent());
+      return slide[0];
+    }).prependTo(this.el);
+
+    // Pagination element.
+    this.el.append('<div class="dac-hero-carousel-pagination"><div class="wrap" data-carousel-pagination>');
+
+    this.el.dacCarousel();
+  }
+
+  function cleanUrl(url) {
+    if (url && url.indexOf('//') === -1) {
+      url = toRoot + url;
+    }
+    return url;
+  }
+
+  function formatTag(resource) {
+    // Hmm, need a better more scalable solution for this.
+    for (var i = 0, mapping; mapping = TAG_MAP[i]; i++) {
+      if (resource.tags.indexOf(mapping.from) > -1) {
+        return mapping.to;
+      }
+    }
+    return resource.type;
+  }
+
+  function formatTitle(resource) {
+    return resource.title.replace(/android developer story: /i, '');
+  }
+
+  function formatCTA(resource) {
+    return resource.type === 'youtube' ? 'Watch the video' : 'Learn more';
+  }
+
+  // jQuery plugin
+  $.fn.dacCarouselQuery = function() {
+    return this.each(function() {
+      var el = $(this);
+      var data = el.data('dac.carouselQuery');
+
+      if (!data) { el.data('dac.carouselQuery', (data = new DacCarouselQuery(el))); }
+    });
+  };
+
+  // Data API
+  $(function() {
+    $('[data-carousel-query]').dacCarouselQuery();
+  });
+})(jQuery);
+
+(function($) {
+  /**
+   * A CSS based carousel, inspired by SequenceJS.
+   * @param {jQuery} el
+   * @param {object} options
+   * @constructor
+   */
+  function DacCarousel(el, options) {
+    this.el = $(el);
+    this.options = options = $.extend({}, DacCarousel.OPTIONS, this.el.data(), options || {});
+    this.frames = this.el.find(options.frameSelector);
+    this.count = this.frames.size();
+    this.current = options.start;
+
+    this.initPagination();
+    this.initEvents();
+    this.initFrame();
+  }
+
+  DacCarousel.OPTIONS = {
+    auto:      true,
+    autoTime:  10000,
+    autoMinTime: 5000,
+    btnPrev:   '[data-carousel-prev]',
+    btnNext:   '[data-carousel-next]',
+    frameSelector: 'article',
+    loop:      true,
+    start:     0,
+    pagination: '[data-carousel-pagination]'
+  };
+
+  DacCarousel.prototype.initPagination = function() {
+    this.pagination = $([]);
+    if (!this.options.pagination) { return; }
+
+    var pagination = $('<ul class="dac-pagination">');
+    var parent = this.el;
+    if (typeof this.options.pagination === 'string') { parent = this.el.find(this.options.pagination); }
+
+    if (this.count > 1) {
+      for (var i = 0; i < this.count; i++) {
+        var li = $('<li class="dac-pagination-item">').text(i);
+        if (i === this.options.start) { li.addClass('active'); }
+        li.click(this.go.bind(this, i));
+
+        pagination.append(li);
+      }
+      this.pagination = pagination.children();
+      parent.append(pagination);
+    }
+  };
+
+  DacCarousel.prototype.initEvents = function() {
+    var that = this;
+
+    this.el.hover(function() {
+      that.pauseRotateTimer();
+    }, function() {
+      that.startRotateTimer();
+    });
+
+    $(this.options.btnPrev).click(function(e) {
+      e.preventDefault();
+      that.prev();
+    });
+
+    $(this.options.btnNext).click(function(e) {
+      e.preventDefault();
+      that.next();
+    });
+  };
+
+  DacCarousel.prototype.initFrame = function() {
+    this.frames.removeClass('active').eq(this.options.start).addClass('active');
+  };
+
+  DacCarousel.prototype.startRotateTimer = function() {
+    if (!this.options.auto || this.rotateTimer) { return; }
+    this.rotateTimer = setTimeout(this.next.bind(this), this.options.autoTime);
+  };
+
+  DacCarousel.prototype.pauseRotateTimer = function() {
+    clearTimeout(this.rotateTimer);
+    this.rotateTimer = null;
+  };
+
+  DacCarousel.prototype.prev = function() {
+    this.go(this.current - 1);
+  };
+
+  DacCarousel.prototype.next = function() {
+    this.go(this.current + 1);
+  };
+
+  DacCarousel.prototype.go = function(next) {
+    // Figure out what the next slide is.
+    while (this.count > 0 && next >= this.count) { next -= this.count; }
+    while (next < 0) { next += this.count; }
+
+    // Cancel if we're already on that slide.
+    if (next === this.current) { return; }
+
+    // Prepare next slide.
+    this.frames.eq(next).removeClass('out');
+
+    // Recalculate styles before starting slide transition.
+    var that = this;
+    resolveStyles(this.el[0], function() {
+      // Update pagination
+      that.pagination.removeClass('active').eq(next).addClass('active');
+
+      // Transition out current frame
+      that.frames.eq(that.current).toggleClass('active out');
+
+      // Transition in a new frame
+      that.frames.eq(next).toggleClass('active');
+
+      that.current = next;
+    });
+  };
+
+  // Helper
+  function resolveStyles(el, callback) {
+    /*jshint expr:true*/
+    el.offsetTop;
+    callback();
+  }
+
+  // jQuery plugin
+  $.fn.dacCarousel = function() {
+    this.each(function() {
+      var $el = $(this);
+      $el.data('dac-carousel', new DacCarousel(this));
+    });
+    return this;
+  };
+
+  // Data API
+  $(function() {
+    $('[data-carousel]').dacCarousel();
+  });
+})(jQuery);
+
+(function($) {
+  'use strict';
+
+  /**
+   * Toggle the visabilty of the mobile navigation.
+   * @param {HTMLElement} el - The DOM element.
+   * @param options
+   * @constructor
+   */
+  function ToggleModal(el, options) {
+    this.el = $(el);
+    this.options = $.extend({}, ToggleModal.DEFAULTS_, options);
+    this.el.on('click', this.clickHandler_.bind(this));
+  }
+
+  ToggleModal.DEFAULTS_ = {
+    toggleClass: 'dac-modal-open'
+  };
+
+  /**
+   * The actual toggle logic.
+   * @param event
+   * @private
+   */
+  ToggleModal.prototype.clickHandler_ = function(event) {
+    event.preventDefault();
+    //TODO: Toggle a class on the modal itself
+    $('body').toggleClass(this.options.toggleClass);
+    $('.dac-modal-dimmer').toggleClass('dac-active');
+    $('.dac-modal-window').toggleClass('dac-active');
+  };
+
+  /**
+   * jQuery plugin
+   * @param  {object} options - Override default options.
+   */
+  $.fn.dacToggleModal = function(options) {
+    return this.each(function() {
+      new ToggleModal(this, options);
+    });
+  };
+
+  /**
+   * Data Attribute API
+   */
+  $(document).on('ready.aranja', function() {
+    $('[data-modal-toogle]').each(function() {
+      $(this).dacToggleModal($(this).data());
+    });
+  });
+})(jQuery);
+
+(function($) {
+  'use strict';
+
+  /**
+   * Toggle the visabilty of the mobile navigation.
+   * @param {HTMLElement} el - The DOM element.
+   * @param options
+   * @constructor
+   */
+  function ToggleNav(el, options) {
+    this.el = $(el);
+    this.options = $.extend({}, ToggleNav.DEFAULTS_, options);
+    this.options.target = [this.options.navigation];
+
+    if (this.options.body) {this.options.target.push('body')}
+    if (this.options.dimmer) {this.options.target.push(this.options.dimmer)}
+
+    this.el.on('click', this.clickHandler_.bind(this));
+  }
+
+  /**
+   * ToggleNav Default Settings
+   * @type {{body: boolean, dimmer: string, navigation: string, toggleClass: string}}
+   * @private
+   */
+  ToggleNav.DEFAULTS_ = {
+    body: true,
+    dimmer: '.dac-nav-dimmer',
+    navigation: '[data-dac-nav]',
+    toggleClass: 'dac-nav-open'
+  };
+
+  /**
+   * The actual toggle logic.
+   * @param event
+   * @private
+   */
+  ToggleNav.prototype.clickHandler_ = function(event) {
+    event.preventDefault();
+    $(this.options.target.join(', ')).toggleClass(this.options.toggleClass);
+  };
+
+  /**
+   * jQuery plugin
+   * @param  {object} options - Override default options.
+   */
+  $.fn.dacToggleMobileNav = function(options) {
+    return this.each(function() {
+      new ToggleNav(this, options);
+    });
+  };
+
+  /**
+   * Data Attribute API
+   */
+  $(window).on('load.aranja', function() {
+    $('[data-dac-toggle-nav]').each(function() {
+      $(this).dacToggleMobileNav($(this).data());
+    });
+  });
+})(jQuery);
+
+(function($) {
+  'use strict';
+
+  /**
+   * Submit the newsletter form to a Google Form.
+   * @param {HTMLElement} el - The Form DOM element.
+   * @constructor
+   */
+  function NewsletterForm(el) {
+    this.el = $(el);
+    this.url = this.el.attr('action');
+    this.el.on('submit', this.submitHandler_.bind(this));
+  }
+
+  /**
+   * Close the modal when the form is sent.
+   * @private
+   */
+  NewsletterForm.prototype.submitHandler_ = function() {
+    //TODO: Close the modal with an event and let modal.js handle this
+    $('body').removeClass('dac-modal-open');
+    $('.dac-modal-dimmer').removeClass('dac-active');
+    $('.dac-modal-window').removeClass('dac-active');
+  };
+
+  /**
+   * jQuery plugin
+   * @param  {object} options - Override default options.
+   */
+  $.fn.dacNewsletterForm = function(options) {
+    return this.each(function() {
+      new NewsletterForm(this, options);
+    });
+  };
+
+  /**
+   * Data Attribute API
+   */
+  $(document).on('ready.aranja', function() {
+    $('[data-newsletter-form]').each(function() {
+      $(this).dacNewsletterForm();
+    });
+  });
+})(jQuery);