From 0f9e459bfb9f6237da7de2e8050ba1cf36825836 Mon Sep 17 00:00:00 2001 From: "stephen@cubedesigners.com" Date: Mon, 18 Jul 2016 18:23:47 +0000 Subject: [PATCH] WIP #554 @2 --- .../application/views/helpers/QuoteForm.php | 3 +- js/005-fancyselect.js | 212 ++++++++++++++++++ js/315-quote.js | 7 + less/003-mixins.less | 6 + less/005-fancyselect.less | 125 +++++++++++ less/315-quote.less | 7 - 6 files changed, 352 insertions(+), 8 deletions(-) create mode 100644 js/005-fancyselect.js create mode 100644 less/005-fancyselect.less diff --git a/framework/application/views/helpers/QuoteForm.php b/framework/application/views/helpers/QuoteForm.php index ceb9820..147d136 100644 --- a/framework/application/views/helpers/QuoteForm.php +++ b/framework/application/views/helpers/QuoteForm.php @@ -4,7 +4,8 @@ class Fluidbook_View_Helper_QuoteForm extends CubeIT_View_Helper_Abstract { public function quoteForm($formID = null) { - $this->headScript()->addScriptAndStyle('315-quote'); + $this->headScript()->addScriptAndStyle('005-fancyselect'); + $this->headScript()->addScriptAndStyle('315-quote'); $form = new Fluidbook_Form_RequestQuote(); diff --git a/js/005-fancyselect.js b/js/005-fancyselect.js new file mode 100644 index 0000000..083548a --- /dev/null +++ b/js/005-fancyselect.js @@ -0,0 +1,212 @@ +/* https://github.com/paulstraw/FancySelect */ +(function() { + var $; + + $ = window.jQuery || window.Zepto || window.$; + + $.fn.fancySelect = function(opts) { + var isiOS, settings; + if (opts == null) { + opts = {}; + } + settings = $.extend({ + forceiOS: false, + includeBlank: false, + optionTemplate: function(optionEl) { + return optionEl.text(); + }, + triggerTemplate: function(optionEl) { + return optionEl.text(); + } + }, opts); + isiOS = !!navigator.userAgent.match(/iP(hone|od|ad)/i); + return this.each(function() { + var copyOptionsToList, disabled, options, sel, trigger, updateTriggerText, wrapper; + sel = $(this); + if (sel.hasClass('fancified') || sel[0].tagName !== 'SELECT') { + return; + } + sel.addClass('fancified'); + sel.css({ + width: 1, + height: 1, + display: 'block', + position: 'absolute', + top: 0, + left: 0, + opacity: 0 + }); + sel.wrap('
'); + wrapper = sel.parent(); + if (sel.data('class')) { + wrapper.addClass(sel.data('class')); + } + wrapper.append('
'); + if (!(isiOS && !settings.forceiOS)) { + wrapper.append('
    '); + } + trigger = wrapper.find('.trigger'); + options = wrapper.find('.options'); + disabled = sel.prop('disabled'); + if (disabled) { + wrapper.addClass('disabled'); + } + updateTriggerText = function() { + var triggerHtml; + triggerHtml = settings.triggerTemplate(sel.find(':selected')); + return trigger.html(triggerHtml); + }; + sel.on('blur.fs', function() { + if (trigger.hasClass('open')) { + return setTimeout(function() { + return trigger.trigger('close.fs'); + }, 120); + } + }); + trigger.on('close.fs', function() { + trigger.removeClass('open'); + return options.removeClass('open'); + }); + trigger.on('click.fs', function() { + + // Close if it is already open + if(trigger.hasClass('open')) { + return trigger.trigger('close.fs'); + } + + var offParent, parent; + if (!disabled) { + trigger.toggleClass('open'); + if (isiOS && !settings.forceiOS) { + if (trigger.hasClass('open')) { + return sel.focus(); + } + } else { + if (trigger.hasClass('open')) { + parent = trigger.parent(); + offParent = parent.offsetParent(); + if ((parent.offset().top + parent.outerHeight() + options.outerHeight() + 20) > $(window).height() + $(window).scrollTop()) { + options.addClass('overflowing'); + } else { + options.removeClass('overflowing'); + } + } + options.toggleClass('open'); + if (!isiOS) { + return sel.focus(); + } + } + } + }); + sel.on('enable', function() { + sel.prop('disabled', false); + wrapper.removeClass('disabled'); + disabled = false; + return copyOptionsToList(); + }); + sel.on('disable', function() { + sel.prop('disabled', true); + wrapper.addClass('disabled'); + return disabled = true; + }); + sel.on('change.fs', function(e) { + if (e.originalEvent && e.originalEvent.isTrusted) { + return e.stopPropagation(); + } else { + return updateTriggerText(); + } + }); + sel.on('keydown', function(e) { + var hovered, newHovered, w; + w = e.which; + hovered = options.find('.hover'); + hovered.removeClass('hover'); + if (!options.hasClass('open')) { + if (w === 13 || w === 32 || w === 38 || w === 40) { + e.preventDefault(); + return trigger.trigger('click.fs'); + } + } else { + if (w === 38) { + e.preventDefault(); + if (hovered.length && hovered.index() > 0) { + hovered.prev().addClass('hover'); + } else { + options.find('li:last-child').addClass('hover'); + } + } else if (w === 40) { + e.preventDefault(); + if (hovered.length && hovered.index() < options.find('li').length - 1) { + hovered.next().addClass('hover'); + } else { + options.find('li:first-child').addClass('hover'); + } + } else if (w === 27) { + e.preventDefault(); + trigger.trigger('click.fs'); + } else if (w === 13 || w === 32) { + e.preventDefault(); + hovered.trigger('mousedown.fs'); + } else if (w === 9) { + if (trigger.hasClass('open')) { + trigger.trigger('close.fs'); + } + } + newHovered = options.find('.hover'); + if (newHovered.length) { + options.scrollTop(0); + return options.scrollTop(newHovered.position().top - 12); + } + } + }); + options.on('mousedown.fs', 'li', function(e) { + var clicked; + clicked = $(this); + sel.val(clicked.data('raw-value')); + if (!isiOS) { + sel.trigger('blur.fs').trigger('focus.fs'); + } + options.find('.selected').removeClass('selected'); + clicked.addClass('selected'); + trigger.addClass('selected'); + return sel.val(clicked.data('raw-value')).trigger('change.fs').trigger('blur.fs').trigger('focus.fs'); + }); + options.on('mouseenter.fs', 'li', function() { + var hovered, nowHovered; + nowHovered = $(this); + hovered = options.find('.hover'); + hovered.removeClass('hover'); + return nowHovered.addClass('hover'); + }); + options.on('mouseleave.fs', 'li', function() { + return options.find('.hover').removeClass('hover'); + }); + copyOptionsToList = function() { + var selOpts; + updateTriggerText(); + if (isiOS && !settings.forceiOS) { + return; + } + selOpts = sel.find('option'); + return sel.find('option').each(function(i, opt) { + var optHtml; + opt = $(opt); + if (!opt.prop('disabled') && (opt.val() || settings.includeBlank)) { + optHtml = settings.optionTemplate(opt); + if (opt.prop('selected')) { + return options.append("
  • " + optHtml + "
  • "); + } else { + return options.append("
  • " + optHtml + "
  • "); + } + } + }); + }; + sel.on('update.fs', function() { + wrapper.find('.options').empty(); + return copyOptionsToList(); + }); + return copyOptionsToList(); + }); + }; + +}).call(this); \ No newline at end of file diff --git a/js/315-quote.js b/js/315-quote.js index ef57c3e..58d9597 100644 --- a/js/315-quote.js +++ b/js/315-quote.js @@ -1,3 +1,10 @@ +registerLoader(load_quoteform, true); + +function load_quoteform() { + $('#requestQuote select').fancySelect(); +} + + function displayErrors() { var errors = []; diff --git a/less/003-mixins.less b/less/003-mixins.less index a0fe580..0b863ec 100644 --- a/less/003-mixins.less +++ b/less/003-mixins.less @@ -11,6 +11,12 @@ -moz-osx-font-smoothing: auto; } +.icon(@char) { + content: @char; + font-family: @icons; + .font-thinning(); +} + .button(@line-height: 54px, @horizontal-padding: 20px) { display: inline-block; border: 0; diff --git a/less/005-fancyselect.less b/less/005-fancyselect.less new file mode 100644 index 0000000..5dd410d --- /dev/null +++ b/less/005-fancyselect.less @@ -0,0 +1,125 @@ +@import "000-imports"; + +div.fancy-select { + position: relative; + font-weight: 300; + font-size: inherit; + + &.disabled { + opacity: 0.5; + } + + select:focus + div.trigger { + //box-shadow: 0 0 0 1px #aaa; // Outline box + } + + select:focus + div.trigger.open { + box-shadow: none; + } + + div.trigger { + box-sizing: content-box; // To match other input elements + cursor: pointer; + padding: 0 2.2em 0 0.4em; + line-height: 3.4; + min-height: 3.4em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + position: relative; + background: #fff; + border: 1px solid #000; + color: #aaa; // Placeholder text + z-index: 2; + transition: all 140ms ease-out; + + &.selected { + color: #323232; + } + + // Arrow + &:after { + .icon('V'); + display: block; + position: absolute; + top: 0; + right: 0; + bottom: 0; + color: #c2c4c7; + font-size: 1.7em; // Relative to select box font size + width: 2em; // Adjust to match font-size for arrow icon (3.4/1.7 = 2em) + line-height: 2em; + text-align: center; + } + + &.open { + box-shadow: none; + + &:after { + // adjustments to dropdown arrow when select is open + } + } + } + + ul.options { + list-style: none; + margin: 0; + position: absolute; + top: 105%; + left: 0; + visibility: hidden; + opacity: 0; + z-index: 1; + //max-height: 0; // Start hidden and expand up + max-height: 12.8em; + width: 100%; + overflow: auto; + background: #f8f8f8; + //border-top: 1px solid #7DD8D2; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + transition: all 150ms ease-out; + + &.open { + z-index: 10; + visibility: visible; + opacity: 1; + max-height: 12.8em; // Each item is 80% of 2em high. We want to show 8 so: 8*2*0.8 = 12.8 + + /* have to use a non-visibility transition to prevent this iOS issue (bug?): */ + /*http://stackoverflow.com/questions/10736478/css-animation-visibility-visible-works-on-chrome-and-safari-but-not-on-ios*/ + //transition: opacity, max-height 200ms ease-out; + } + + &.overflowing { + top: auto; + bottom: 110%; + + &.open { + //transition: opacity, max-height 300ms ease-out; + } + } + + li { + font-size: 80%; + line-height: 2; + padding: 0 12px; + color: #323232; + cursor: pointer; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + //transition: all 100ms ease-out; + + &.selected { + background: rgba(200,200,200,0.3); + color: #000; + } + + &.hover { + background: #ddd; + color: #000; + } + } + } + +} \ No newline at end of file diff --git a/less/315-quote.less b/less/315-quote.less index 81d2c86..e42444b 100644 --- a/less/315-quote.less +++ b/less/315-quote.less @@ -90,13 +90,6 @@ } } - select { - background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAICAYAAADuv08kAAAAnElEQVQoz2M4f/Hy8UNHjv8nhC9cunL4379/zAzUAt++f1c7cuzkN3yWAuW/ANUpM1AbPHn6rACfxU+fPc9hoAUABiHTxctXDmCz9NLlq3v+///PyEAr8P37D6Wjx09+RrYUyP/048cPeQZag2fPX2QgW/z8xctkBnoAUJBeunJtF8jSy1evb6NpEKMDYNDKnTpz7v7Pnz+laGkPAKftxKb2aSY8AAAAAElFTkSuQmCC'); - background-position: center right; - background-repeat: no-repeat; - padding-right: 40px; - } - textarea { line-height: 1.4; padding: 15px; -- 2.39.5