diff --git a/app/assets/javascripts/admin/all.js b/app/assets/javascripts/admin/all.js
index 050f01aecd..76a286cc43 100644
--- a/app/assets/javascripts/admin/all.js
+++ b/app/assets/javascripts/admin/all.js
@@ -14,6 +14,8 @@
//= require jquery.powertip
//= require jquery.cookie
//= require jquery.jstree/jquery.jstree
+//= require jquery.vAlign
+//= require jquery.horizontalNav
//= require angular
//= require angular-resource
//= require angular-animate
@@ -25,8 +27,13 @@
//= require lodash.underscore.js
// spree
+//= require spree
+//= require admin/spree-select2
//= require admin/spree_backend
//= require modernizr
+//= require spin
+//= require jquery.adaptivemenu
+//= require equalize
//= require css_browser_selector_dev
//= require responsive-tables
//= require admin/spree_paypal_express
diff --git a/app/assets/javascripts/admin/spree/base.js.erb b/app/assets/javascripts/admin/spree/base.js.erb
new file mode 100644
index 0000000000..b9ba57d9ff
--- /dev/null
+++ b/app/assets/javascripts/admin/spree/base.js.erb
@@ -0,0 +1,228 @@
+//= require_self
+//= require admin/handlebar_extensions
+//= require admin/variant_autocomplete
+
+/**
+This is a collection of javascript functions and whatnot
+under the spree namespace that do stuff we find helpful.
+Hopefully, this will evolve into a propper class.
+**/
+
+jQuery(function($) {
+ // Make main menu use full width
+ mainMenu = $('.fullwidth-menu')
+ if (typeof mainMenu.horizontalNav === 'function' )
+ mainMenu.horizontalNav({
+ tableDisplay: false,
+ responsiveDelay: 0
+ });
+
+ // Vertical align of checkbox fields
+ if (typeof $('.field.checkbox label').vAlign === 'function' )
+ $('.field.checkbox label').vAlign()
+
+ // if (typeof Spree !== 'undefined') {
+ // $('.main-menu-wrapper ul').AdaptiveMenu({
+ // text: " " + Spree.translations.more + "",
+ // klass: "dropdown"
+ // });
+ // }
+
+ // Add some tips
+ if (typeof $('.with-tip').powerTip === 'function' ) {
+ $('.with-tip').powerTip({
+ smartPlacement: true,
+ fadeInTime: 50,
+ fadeOutTime: 50,
+ intentPollInterval: 300
+ });
+
+ $('.with-tip').on({
+ powerTipPreRender: function(){
+ $('#powerTip').addClass($(this).attr("data-action"));
+ $('#powerTip').addClass($(this).attr("data-tip-color"));
+ },
+ powerTipClose: function(){
+ $('#powerTip').removeClass($(this).attr("data-action"))
+ }
+ });
+ }
+
+ // Make flash messages dissapear
+ setTimeout('$(".flash").fadeOut()', 5000);
+
+ // Highlight hovered table column
+ $('table tbody tr td.actions a').hover(function(){
+ var tr = $(this).closest('tr');
+ var klass = 'highlight action-' + $(this).attr('data-action')
+ tr.addClass(klass)
+ tr.prev().addClass('before-' + klass);
+ }, function(){
+ var tr = $(this).closest('tr');
+ var klass = 'highlight action-' + $(this).attr('data-action')
+ tr.removeClass(klass)
+ tr.prev().removeClass('before-' + klass);
+ });
+
+ // Trunkate text in page_title that didn't fit
+ var truncate_elements = $('.truncate');
+
+ truncate_elements.each(function(){
+ $(this).trunk8();
+ });
+ $(window).resize(function (event) {
+ truncate_elements.each(function(){
+ $(this).trunk8();
+ })
+ });
+
+ // Make height of dt/dd elements the same
+ if (typeof $("dl").equalize === 'function' )
+ $("dl").equalize('outerHeight');
+});
+
+
+$.fn.visible = function(cond) { this[cond ? 'show' : 'hide' ]() };
+
+// Overriding a broken function in Spree. Bug report at
+// https://github.com/spree/spree/issues/4032
+show_flash_error = function(message) {
+ error_div = $('.flash.error');
+ if (error_div.length > 0) {
+ error_div.html(message);
+ error_div.show();
+ } else {
+ if ($("#content .toolbar").length > 0) {
+ $("#content .toolbar").before('
' + message + '
');
+ } else {
+ $("#progress").before('' + message + '
');
+ }
+ }
+}
+
+// Apply to individual radio button that makes another element visible when checked
+$.fn.radioControlsVisibilityOfElement = function(dependentElementSelector){
+ if(!this.get(0)){ return }
+ showValue = this.get(0).value;
+ radioGroup = $("input[name='" + this.get(0).name + "']");
+ radioGroup.each(function(){
+ $(this).click(function(){
+ $(dependentElementSelector).visible(this.checked && this.value == showValue)
+ });
+ if(this.checked){ this.click() }
+ });
+}
+
+$(document).ready(function() {
+ if (typeof Spree !== 'undefined') {
+ handle_date_picker_fields = function(){
+ $('.datepicker').datepicker({
+ dateFormat: Spree.translations.date_picker,
+ dayNames: Spree.translations.abbr_day_names,
+ dayNamesMin: Spree.translations.abbr_day_names,
+ monthNames: Spree.translations.month_names,
+ prevText: Spree.translations.previous,
+ nextText: Spree.translations.next,
+ showOn: "focus"
+ });
+
+ // Correctly display range dates
+ $('.date-range-filter .datepicker-from').datepicker('option', 'onSelect', function(selectedDate) {
+ $(".date-range-filter .datepicker-to" ).datepicker( "option", "minDate", selectedDate );
+ });
+ $('.date-range-filter .datepicker-to').datepicker('option', 'onSelect', function(selectedDate) {
+ $(".date-range-filter .datepicker-from" ).datepicker( "option", "maxDate", selectedDate );
+ });
+ }
+
+ handle_date_picker_fields();
+ }
+
+ $(".observe_field").on('change', function() {
+ target = $(this).attr("data-update");
+ ajax_indicator = $(this).attr("data-ajax-indicator") || '#busy_indicator';
+ $(target).hide();
+ $(ajax_indicator).show();
+ $.ajax({ dataType: 'html',
+ url: $(this).attr("data-base-url")+encodeURIComponent($(this).val()),
+ type: 'get',
+ success: function(data){
+ $(target).html(data);
+ $(ajax_indicator).hide();
+ $(target).show();
+ }
+ });
+ });
+
+ $('.spree_add_fields').click(function() {
+ var target = $(this).data("target");
+ var new_table_row = $(target + ' tr:visible:last').clone();
+ var new_id = new Date().getTime();
+ new_table_row.find("input, select").each(function () {
+ var el = $(this);
+ el.val("");
+ if (typeof el.attr("id") !== 'undefined') el.attr("id", el.attr("id").replace(/\d+/, new_id))
+ if (typeof el.attr("name") !== 'undefined') el.attr("name", el.attr("name").replace(/\d+/, new_id))
+ })
+ // When cloning a new row, set the href of all icons to be an empty "#"
+ // This is so that clicking on them does not perform the actions for the
+ // duplicated row
+ new_table_row.find("a").each(function () {
+ var el = $(this);
+ el.attr('href', '#');
+ })
+ $(target).prepend(new_table_row);
+ })
+
+ // Fix sortable helper
+ var fixHelper = function(e, ui) {
+ ui.children().each(function() {
+ $(this).width($(this).width());
+ });
+ return ui;
+ };
+
+ $('table.sortable').ready(function(){
+ var td_count = $(this).find('tbody tr:first-child td').length
+
+ if (typeof $('table.sortable tbody').sortable !== 'function' )
+ return
+
+ $('table.sortable tbody').sortable(
+ {
+ handle: '.handle',
+ helper: fixHelper,
+ placeholder: 'ui-sortable-placeholder',
+ update: function(event, ui) {
+ $("#progress").show();
+ positions = {};
+ $.each($('table.sortable tbody tr'), function(position, obj){
+ reg = /spree_(\w+_?)+_(\d+)/;
+ parts = reg.exec($(obj).attr('id'));
+ if (parts) {
+ positions['positions['+parts[2]+']'] = position;
+ }
+ });
+ $.ajax({
+ type: 'POST',
+ dataType: 'script',
+ url: $(ui.item).closest("table.sortable").data("sortable-link"),
+ data: positions,
+ success: function(data){ $("#progress").hide(); }
+ });
+ },
+ start: function (event, ui) {
+ // Set correct height for placehoder (from dragged tr)
+ ui.placeholder.height(ui.item.height())
+ // Fix placeholder content to make it correct width
+ ui.placeholder.html(" | | ")
+ },
+ stop: function (event, ui) {
+ // Fix odd/even classes after reorder
+ $("table.sortable tr:even").removeClass("odd even").addClass("even");
+ $("table.sortable tr:odd").removeClass("odd even").addClass("odd");
+ }
+
+ });
+ });
+});
diff --git a/app/assets/javascripts/admin/spree/progress.coffee b/app/assets/javascripts/admin/spree/progress.coffee
new file mode 100644
index 0000000000..edc20a541b
--- /dev/null
+++ b/app/assets/javascripts/admin/spree/progress.coffee
@@ -0,0 +1,27 @@
+$(document).ready ->
+ opts =
+ lines: 11
+ length: 2
+ width: 3
+ radius: 9
+ corners: 1
+ rotate: 0
+ color: '#fff'
+ speed: 0.8
+ trail: 48
+ shadow: false
+ hwaccel: true
+ className: 'spinner'
+ zIndex: 2e9
+ top: 'auto'
+ left: 'auto'
+
+ target = document.getElementById("spinner")
+
+ $(document).ajaxStart ->
+ $("#progress").fadeIn()
+ spinner = new Spinner(opts).spin(target)
+
+ $(document).ajaxStop ->
+ $("#progress").fadeOut()
+
diff --git a/app/assets/javascripts/admin/spree/spree-select2.js.erb b/app/assets/javascripts/admin/spree/spree-select2.js.erb
new file mode 100644
index 0000000000..30f4fc0794
--- /dev/null
+++ b/app/assets/javascripts/admin/spree/spree-select2.js.erb
@@ -0,0 +1,8 @@
+//= require select2
+jQuery(function($) {
+ // Make select beautiful
+ if (typeof $('select.select2').select2 === 'function' )
+ $('select.select2').select2({
+ allowClear: true
+ });
+})
diff --git a/app/assets/javascripts/admin/util.js.erb b/app/assets/javascripts/admin/util.js.erb
index 37ff1cb9ca..aabd313b0f 100644
--- a/app/assets/javascripts/admin/util.js.erb
+++ b/app/assets/javascripts/admin/util.js.erb
@@ -16,22 +16,6 @@ $(document).ready(function() {
});
});
-// Overriding a broken function in Spree. Bug report at
-// https://github.com/spree/spree/issues/4032
-show_flash_error = function(message) {
- error_div = $('.flash.error');
- if (error_div.length > 0) {
- error_div.html(message);
- error_div.show();
- } else {
- if ($("#content .toolbar").length > 0) {
- $("#content .toolbar").before('' + message + '
');
- } else {
- $("#progress").before('' + message + '
');
- }
- }
-}
-
$(document).ready(function(){
$('a.close').click(function(event){
event.preventDefault();
diff --git a/app/assets/stylesheets/admin/all.scss b/app/assets/stylesheets/admin/all.scss
index 50f6c25477..a3200f1d91 100644
--- a/app/assets/stylesheets/admin/all.scss
+++ b/app/assets/stylesheets/admin/all.scss
@@ -14,7 +14,6 @@
*= require_self
*/
-
//************************************************************************//
//************************************************************************//
@import 'globals/variables';
diff --git a/app/assets/stylesheets/admin/components/progress.scss b/app/assets/stylesheets/admin/components/progress.scss
new file mode 100644
index 0000000000..189689c764
--- /dev/null
+++ b/app/assets/stylesheets/admin/components/progress.scss
@@ -0,0 +1,38 @@
+@import 'admin/globals/variables';
+@import 'admin/globals/mixins';
+
+#progress {
+ display: none;
+ position: fixed;
+ top: 0;
+ z-index: 1000;
+ opacity: 0.8;
+ width: 100%;
+
+ .wrapper {
+ @include border-radius(10px);
+ top: -10px;
+ position: absolute;
+ left: 50%;
+ width: 200px;
+ margin-left: -100px;
+ padding: 11px 0;
+ background-color: $color-3;
+ color: $color-1;
+ text-align: center;
+ }
+
+ #spinner {
+ position: absolute;
+ top: 10px;
+ left: 50%;
+ margin-left: -5px;
+ }
+
+ .progress-message {
+ font-size: 120%;
+ font-weight: $font-weight-bold;
+ margin-top: 20px;
+ text-transform: uppercase;
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/admin/globals/functions.scss b/app/assets/stylesheets/admin/globals/functions.scss
new file mode 100644
index 0000000000..0abf3546f6
--- /dev/null
+++ b/app/assets/stylesheets/admin/globals/functions.scss
@@ -0,0 +1,25 @@
+// Make color very close to white
+@function very-light($color, $adjust: 3){
+ @if type-of($adjust) == 'number' and $adjust > 0 {
+ @for $i from 0 through 100 {
+ @if lighten($color, $i) == white and ($i - $adjust) > $adjust {
+ @return lighten($color, $i - $adjust);
+ }
+ }
+ }
+ @else {
+ @debug "Please correct $adjust value. It should be number and larger then 0. Currently it is '#{type-of($adjust)}' with value '#{$adjust}'"
+ }
+};
+
+// Quick fix for dynamic variables missing in SASS
+@function get-value($prop, $val, $search) {
+ $n1: index($prop, $search);
+ $n2: index($val, $search);
+
+ @if($n1) {
+ @return nth($val, $n1);
+ } @else {
+ @return nth($prop, $n2);
+ }
+}
diff --git a/app/assets/stylesheets/admin/plugins/select2.scss b/app/assets/stylesheets/admin/plugins/select2.scss
new file mode 100644
index 0000000000..d290394819
--- /dev/null
+++ b/app/assets/stylesheets/admin/plugins/select2.scss
@@ -0,0 +1,193 @@
+@import 'admin/globals/functions';
+@import 'admin/globals/variables';
+@import 'admin/globals/mixins';
+
+@import 'admin/shared/forms';
+
+@import 'admin/plugins/font-awesome';
+
+.select2-container {
+ &:hover .select2-choice, &.select2-container-active .select2-choice {
+ background-color: $color-sel-hover-bg !important;
+ border-color: $color-sel-hover-bg !important;
+ }
+ .select2-choice {
+ background-image: none !important;
+ background-color: $color-sel-bg;
+ border: none !important;
+ box-shadow: none !important;
+ @include border-radius($border-radius);
+ color: $color-1 !important;
+ font-size: 90%;
+ height: 31px;
+ line-height: inherit !important;
+ padding: 5px 15px 7px;
+
+ span {
+ display: block;
+ padding: 2px;
+ }
+
+ .select2-search-choice-close {
+ background-image: none !important;
+ font-size: 100% !important;
+ @extend .icon-remove;
+ @extend [class^="icon-"]:before;
+ margin-top: 2px;
+ }
+ }
+
+ &.select2-container-active {
+ .select2-choice {
+ box-shadow: none !important;
+ }
+
+ &.select2-dropdown-open .select2-choice div b {
+ @extend .icon-caret-up
+ }
+ }
+}
+
+.select2-drop {
+ border-color: $color-sel-hover-bg;
+ box-shadow: none !important;
+ z-index: 1000000;
+
+ &.select2-drop-above {
+ border-color: $color-sel-hover-bg;
+ }
+}
+
+.select2-search {
+ @extend .icon-search;
+
+ font-size: 100%;
+ color: darken($color-border, 15);
+ padding: 0 9px 0 0;
+
+ &:before {
+ @extend [class^="icon-"]:before;
+
+ position: absolute;
+ top: 13px;
+ left: 13px;
+ }
+
+ input {
+ @extend input[type="text"];
+
+ padding: 6px 0 6px 25px;
+ margin: 5px 0 0 5px;
+ font-family: $base-font-family;
+ font-size: 90%;
+ box-shadow: none;
+ background-image: none;
+ }
+}
+
+.select2-container .select2-choice .select2-arrow {
+ background-image: none;
+ background: transparent;
+ border: 0;
+
+ b {
+ padding-top: 7px;
+ display: block;
+ width: 100%;
+ height: 100%;
+ background: none;
+ font-family: FontAwesome;
+ font-weight: 200 !important;
+
+ &:before {
+ content: "\f0d7";
+ }
+ }
+}
+
+.select2-results {
+ padding-left: 0 !important;
+
+ li {
+ font-size: 85% !important;
+
+ &.select2-highlighted {
+ .select2-result-label {
+ &, h6 {
+ color: $color-1 !important;
+ }
+ }
+ }
+
+ .select2-result-label {
+ color: $color-body-text;
+ min-height: 22px;
+ clear: both;
+ overflow: auto;
+ }
+
+ &.select2-no-results, &.select2-searching {
+ padding: 5px;
+ background-color: transparent;
+ color: $color-body-text;
+ text-align: center;
+ font-weight: $font-weight-bold;
+ text-transform: uppercase;
+ }
+ }
+
+ .select2-highlighted {
+ background-color: $color-sel-bg;
+ }
+}
+
+.select2-container-multi {
+ &.select2-container-active, &.select2-dropdown-open {
+ .select2-choices {
+ border-color: $color-sel-hover-bg !important;
+ box-shadow: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+ }
+ .select2-choices {
+ @extend input[type="text"];
+ padding: 6px 3px 3px 3px;
+ box-shadow: none;
+ background-image: none !important;
+
+ .select2-search-choice {
+ @include border-radius($border-radius);
+ margin: 0 0 3px 3px;
+ background-image: none;
+ background-color: $color-sel-bg;
+ border: none;
+ box-shadow: none;
+ color: $color-1 !important;
+ font-size: 85%;
+
+ &:hover {
+ background-color: $color-sel-hover-bg;
+ }
+
+ .select2-search-choice-close {
+ background-image: none !important;
+ font-size: 85% !important;
+ @extend .icon-remove;
+ @extend [class^="icon-"]:before;
+ margin-left: 2px;
+ color: $color-1;
+ }
+ }
+ }
+}
+
+label .select2-container {
+ margin-top: -6px;
+ .select2-choice {
+ span {
+ text-transform: none;
+ font-weight: normal;
+ }
+ }
+}
diff --git a/vendor/assets/javascripts/equalize.js b/vendor/assets/javascripts/equalize.js
new file mode 100644
index 0000000000..776be00aef
--- /dev/null
+++ b/vendor/assets/javascripts/equalize.js
@@ -0,0 +1,41 @@
+/**
+ * equalize.js
+ * Author & copyright (c) 2012: Tim Svensen
+ * Dual MIT & GPL license
+ *
+ * Page: http://tsvensen.github.com/equalize.js
+ * Repo: https://github.com/tsvensen/equalize.js/
+ *
+ * The jQuery plugin for equalizing the height or width of elements.
+ *
+ * Equalize will accept any of the jQuery Dimension methods:
+ * height, outerHeight, innerHeight,
+ * width, outerWidth, innerWidth.
+ *
+ * EXAMPLE
+ * $('.parent').equalize(); // defaults to 'height'
+ * $('.parent').equalize('width'); // equalize the widths
+ */
+(function($, window, document, undefined) {
+
+ $.fn.equalize = function(equalize) {
+ var $containers = this, // this is the jQuery object
+ equalize = equalize || 'height',
+ type = (equalize.indexOf('eight') > 0) ? 'height' : 'width';
+
+ if (!$.isFunction($.fn[equalize])) { return false; }
+
+ return $containers.each(function() {
+ var $children = $(this).children(),
+ max = 0; // reset for each container
+
+ $children.each(function() {
+ var value = $(this)[equalize](); // call height(), outerHeight(), etc.
+ if (value > max) { max = value; } // update max
+ });
+
+ $children.css(type, max +'px'); // add CSS to children
+ });
+ };
+
+}(jQuery, window, document));
diff --git a/vendor/assets/javascripts/jquery.horizontalNav.js b/vendor/assets/javascripts/jquery.horizontalNav.js
new file mode 100755
index 0000000000..a008355a25
--- /dev/null
+++ b/vendor/assets/javascripts/jquery.horizontalNav.js
@@ -0,0 +1,141 @@
+/**
+ * jQuery Horizontal Navigation 1.0
+ * https://github.com/sebnitu/horizontalNav
+ *
+ * By Sebastian Nitu - Copyright 2012 - All rights reserved
+ * Author URL: http://sebnitu.com
+ */
+(function($) {
+
+ $.fn.horizontalNav = function(options) {
+
+ // Extend our default options with those provided.
+ var opts = $.extend({}, $.fn.horizontalNav.defaults, options);
+
+ return this.each(function () {
+
+ // Save our object
+ var $this = $(this);
+
+ // Build element specific options
+ // This lets me access options with this syntax: o.optionName
+ var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
+
+ // Save the wrapper. The wrapper is the element that
+ // we figure out what the full width should be
+ if ($this.is('ul')) {
+ var ul_wrap = $this.parent();
+ } else {
+ var ul_wrap = $this;
+ }
+
+ // let's append a clearfixing element to the ul wrapper
+ ul_wrap.css({ 'zoom' : '1' }).append('');
+ $('.clearHorizontalNav').css({
+ 'display' : 'block',
+ 'overflow' : 'hidden',
+ 'visibility' : 'hidden',
+ 'width' : 0,
+ 'height' : 0,
+ 'clear' : 'both'
+ });
+
+ // Grab elements we'll need and add some default styles
+ var ul = $this.is('ul') ? $this : ul_wrap.find('> ul'), // The unordered list element
+ li = ul.find('> li'), // All list items
+ li_last = li.last(), // Last list item
+ li_count = li.size(), // The number of navigation elements
+ li_a = li.find('> a'); // Remove padding from the links
+
+ // If set to responsive, re-construct after every browser resize
+ if ( o.responsive === true ) {
+ // Only need to do this for IE7 and below
+ // or if we set tableDisplay to false
+ if ( (o.tableDisplay != true) || ($.browser.msie && parseInt($.browser.version, 10) <= 7) ) {
+ resizeTrigger( _construct, o.responsiveDelay );
+ }
+ }
+
+ // Initiate the plugin
+ _construct();
+
+ // Returns the true inner width of an element
+ // Essentially it's the inner width without padding.
+ function trueInnerWidth(element) {
+ return element.innerWidth() - (
+ parseInt(element.css('padding-left')) + parseInt(element.css('padding-right'))
+ );
+ }
+
+ // Call funcion on browser resize
+ function resizeTrigger(callback, delay) {
+ // Delay before function is called
+ delay = delay || 100;
+ // Call function on resize
+ var resizeTimer;
+ $(window).resize(function() {
+ clearTimeout(resizeTimer);
+ resizeTimer = setTimeout(function() {
+ callback();
+ }, delay);
+ });
+ }
+
+ // The heavy lifting of this plugin. This is where we
+ // find and set the appropriate widths for list items
+ function _construct() {
+
+ if ( (o.tableDisplay != true) || ($.browser.msie && parseInt($.browser.version, 10) <= 7) ) {
+
+ // IE7 doesn't support the "display: table" method
+ // so we need to do it the hard way.
+
+ // Add some styles
+ ul.css({ 'float' : 'left' });
+ li.css({ 'float' : 'left', 'width' : 'auto' });
+ li_a.css({ 'padding-left' : 0, 'padding-right' : 0 });
+
+ // Grabbing widths and doing some math
+ var ul_width = trueInnerWidth(ul),
+ ul_width_outer = ul.outerWidth(true),
+ ul_width_extra = ul_width_outer - ul_width,
+
+ full_width = trueInnerWidth(ul_wrap),
+ extra_width = (full_width - ul_width_extra) - ul_width,
+ li_padding = Math.floor( extra_width / li_count );
+
+ // Cycle through the list items and give them widths
+ li.each(function(index) {
+ var li_width = trueInnerWidth( $(this) );
+ $(this).css({ 'width' : (li_width + li_padding) + 'px' });
+ });
+
+ // Get the leftover pixels after we set every itms width
+ var li_last_width = trueInnerWidth(li_last) + ( (full_width - ul_width_extra) - trueInnerWidth(ul) );
+ // I hate to do this but for some reason Firefox (v13.0) and IE are always
+ // one pixel off when rendering. So this is a quick fix for that.
+ if ($.browser.mozilla || $.browser.msie) {
+ li_last_width = li_last_width - 1;
+ }
+ // Add the leftovers to the last navigation item
+ li_last.css({ 'width' : li_last_width + 'px' });
+
+ } else {
+ // Every modern browser supports the "display: table" method
+ // so this is the best way to do it for them.
+ ul.css({ 'display' : 'table', 'float' : 'none', 'width' : '100%' });
+ li.css({ 'display' : 'table-cell', 'float' : 'none' });
+ }
+ }
+
+ }); // @end of return this.each()
+
+ };
+
+ $.fn.horizontalNav.defaults = {
+ responsive : true,
+ responsiveDelay : 100,
+ tableDisplay : true
+ };
+
+})(jQuery);
\ No newline at end of file
diff --git a/vendor/assets/javascripts/jquery.vAlign.js b/vendor/assets/javascripts/jquery.vAlign.js
new file mode 100644
index 0000000000..d0e2f08882
--- /dev/null
+++ b/vendor/assets/javascripts/jquery.vAlign.js
@@ -0,0 +1,11 @@
+(function ($) {
+ // VERTICALLY ALIGN FUNCTION
+ $.fn.vAlign = function() {
+ return this.each(function(i){
+ var ah = $(this).height();
+ var ph = $(this).parent().height();
+ var mh = Math.ceil((ph-ah) / 2);
+ $(this).css('margin-top', mh);
+ });
+ };
+})(jQuery);
\ No newline at end of file
diff --git a/vendor/assets/javascripts/spin.js b/vendor/assets/javascripts/spin.js
new file mode 100644
index 0000000000..2a8642f311
--- /dev/null
+++ b/vendor/assets/javascripts/spin.js
@@ -0,0 +1,319 @@
+//fgnass.github.com/spin.js#v1.2.6
+!function(window, document, undefined) {
+
+ /**
+ * Copyright (c) 2011 Felix Gnass [fgnass at neteye dot de]
+ * Licensed under the MIT license
+ */
+
+ var prefixes = ['webkit', 'Moz', 'ms', 'O'] /* Vendor prefixes */
+ , animations = {} /* Animation rules keyed by their name */
+ , useCssAnimations
+
+ /**
+ * Utility function to create elements. If no tag name is given,
+ * a DIV is created. Optionally properties can be passed.
+ */
+ function createEl(tag, prop) {
+ var el = document.createElement(tag || 'div')
+ , n
+
+ for(n in prop) el[n] = prop[n]
+ return el
+ }
+
+ /**
+ * Appends children and returns the parent.
+ */
+ function ins(parent /* child1, child2, ...*/) {
+ for (var i=1, n=arguments.length; i> 1) : parseInt(o.left, 10) + mid) + 'px',
+ top: (o.top == 'auto' ? tp.y-ep.y + (target.offsetHeight >> 1) : parseInt(o.top, 10) + mid) + 'px'
+ })
+ }
+
+ el.setAttribute('aria-role', 'progressbar')
+ self.lines(el, self.opts)
+
+ if (!useCssAnimations) {
+ // No CSS animation support, use setTimeout() instead
+ var i = 0
+ , fps = o.fps
+ , f = fps/o.speed
+ , ostep = (1-o.opacity) / (f*o.trail / 100)
+ , astep = f/o.lines
+
+ ;(function anim() {
+ i++;
+ for (var s=o.lines; s; s--) {
+ var alpha = Math.max(1-(i+s*astep)%f * ostep, o.opacity)
+ self.opacity(el, o.lines-s, alpha, o)
+ }
+ self.timeout = self.el && setTimeout(anim, ~~(1000/fps))
+ })()
+ }
+ return self
+ },
+
+ stop: function() {
+ var el = this.el
+ if (el) {
+ clearTimeout(this.timeout)
+ if (el.parentNode) el.parentNode.removeChild(el)
+ this.el = undefined
+ }
+ return this
+ },
+
+ lines: function(el, o) {
+ var i = 0
+ , seg
+
+ function fill(color, shadow) {
+ return css(createEl(), {
+ position: 'absolute',
+ width: (o.length+o.width) + 'px',
+ height: o.width + 'px',
+ background: color,
+ boxShadow: shadow,
+ transformOrigin: 'left',
+ transform: 'rotate(' + ~~(360/o.lines*i+o.rotate) + 'deg) translate(' + o.radius+'px' +',0)',
+ borderRadius: (o.corners * o.width>>1) + 'px'
+ })
+ }
+
+ for (; i < o.lines; i++) {
+ seg = css(createEl(), {
+ position: 'absolute',
+ top: 1+~(o.width/2) + 'px',
+ transform: o.hwaccel ? 'translate3d(0,0,0)' : '',
+ opacity: o.opacity,
+ animation: useCssAnimations && addAnimation(o.opacity, o.trail, i, o.lines) + ' ' + 1/o.speed + 's linear infinite'
+ })
+
+ if (o.shadow) ins(seg, css(fill('#000', '0 0 4px ' + '#000'), {top: 2+'px'}))
+
+ ins(el, ins(seg, fill(o.color, '0 0 1px rgba(0,0,0,.1)')))
+ }
+ return el
+ },
+
+ opacity: function(el, i, val) {
+ if (i < el.childNodes.length) el.childNodes[i].style.opacity = val
+ }
+
+ })
+
+ /////////////////////////////////////////////////////////////////////////
+ // VML rendering for IE
+ /////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Check and init VML support
+ */
+ ;(function() {
+
+ function vml(tag, attr) {
+ return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr)
+ }
+
+ var s = css(createEl('group'), {behavior: 'url(#default#VML)'})
+
+ if (!vendor(s, 'transform') && s.adj) {
+
+ // VML support detected. Insert CSS rule ...
+ sheet.addRule('.spin-vml', 'behavior:url(#default#VML)')
+
+ Spinner.prototype.lines = function(el, o) {
+ var r = o.length+o.width
+ , s = 2*r
+
+ function grp() {
+ return css(
+ vml('group', {
+ coordsize: s + ' ' + s,
+ coordorigin: -r + ' ' + -r
+ }),
+ { width: s, height: s }
+ )
+ }
+
+ var margin = -(o.width+o.length)*2 + 'px'
+ , g = css(grp(), {position: 'absolute', top: margin, left: margin})
+ , i
+
+ function seg(i, dx, filter) {
+ ins(g,
+ ins(css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx}),
+ ins(css(vml('roundrect', {arcsize: o.corners}), {
+ width: r,
+ height: o.width,
+ left: o.radius,
+ top: -o.width>>1,
+ filter: filter
+ }),
+ vml('fill', {color: o.color, opacity: o.opacity}),
+ vml('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change
+ )
+ )
+ )
+ }
+
+ if (o.shadow)
+ for (i = 1; i <= o.lines; i++)
+ seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)')
+
+ for (i = 1; i <= o.lines; i++) seg(i)
+ return ins(el, g)
+ }
+
+ Spinner.prototype.opacity = function(el, i, val, o) {
+ var c = el.firstChild
+ o = o.shadow && o.lines || 0
+ if (c && i+o < c.childNodes.length) {
+ c = c.childNodes[i+o]; c = c && c.firstChild; c = c && c.firstChild
+ if (c) c.opacity = val
+ }
+ }
+ }
+ else
+ useCssAnimations = vendor(s, 'animation')
+ })()
+
+ if (typeof define == 'function' && define.amd)
+ define(function() { return Spinner })
+ else
+ window.Spinner = Spinner
+
+}(window, document)