/*! * Mobiscroll v2.14.4 * http://mobiscroll.com * * Copyright 2010-2014, Acid Media * Licensed under the MIT license. * */ //core (function ($, undefined) { function testProps(props) { var i; for (i in props) { if (mod[props[i]] !== undefined) { return true; } } return false; } function testPrefix() { var prefixes = ['Webkit', 'Moz', 'O', 'ms'], p; for (p in prefixes) { if (testProps([prefixes[p] + 'Transform'])) { return '-' + prefixes[p].toLowerCase() + '-'; } } return ''; } function init(that, options, args) { var ret = that; // Init if (typeof options === 'object') { return that.each(function () { if (!this.id) { this.id = 'mobiscroll' + (++id); } if (instances[this.id]) { instances[this.id].destroy(); } new $.mobiscroll.classes[options.component || 'Scroller'](this, options); }); } // Method call if (typeof options === 'string') { that.each(function () { var r, inst = instances[this.id]; if (inst && inst[options]) { r = inst[options].apply(this, Array.prototype.slice.call(args, 1)); if (r !== undefined) { ret = r; return false; } } }); } return ret; } var id = +new Date(), instances = {}, extend = $.extend, mod = document.createElement('modernizr').style, has3d = testProps(['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']), hasFlex = testProps(['flex', 'msFlex', 'WebkitBoxDirection']), prefix = testPrefix(), pr = prefix.replace(/^\-/, '').replace(/\-$/, '').replace('moz', 'Moz'); $.fn.mobiscroll = function (method) { extend(this, $.mobiscroll.components); return init(this, method, arguments); }; $.mobiscroll = $.mobiscroll || { version: '2.14.4', util: { prefix: prefix, jsPrefix: pr, has3d: has3d, hasFlex: hasFlex, testTouch: function (e, elm) { if (e.type == 'touchstart') { $(elm).attr('data-touch', '1'); } else if ($(elm).attr('data-touch')) { $(elm).removeAttr('data-touch'); return false; } return true; }, objectToArray: function (obj) { var arr = [], i; for (i in obj) { arr.push(obj[i]); } return arr; }, arrayToObject: function (arr) { var obj = {}, i; if (arr) { for (i = 0; i < arr.length; i++) { obj[arr[i]] = arr[i]; } } return obj; }, isNumeric: function (a) { return a - parseFloat(a) >= 0; }, isString: function (s) { return typeof s === 'string'; }, getCoord: function (e, c) { var ev = e.originalEvent || e; return ev.changedTouches ? ev.changedTouches[0]['page' + c] : e['page' + c]; }, getPosition: function (t, vertical) { var style = window.getComputedStyle ? getComputedStyle(t[0]) : t[0].style, matrix, px; if (has3d) { $.each(['t', 'webkitT', 'MozT', 'OT', 'msT'], function (i, v) { if (style[v + 'ransform'] !== undefined) { matrix = style[v + 'ransform']; return false; } }); matrix = matrix.split(')')[0].split(', '); px = vertical ? (matrix[13] || matrix[5]) : (matrix[12] || matrix[4]); } else { px = vertical ? style.top.replace('px', '') : style.left.replace('px', ''); } return px; }, constrain: function (val, min, max) { return Math.max(min, Math.min(val, max)); } }, tapped: false, presets: { scroller: {}, numpad: {} }, themes: { listview: {}, menustrip: {} }, i18n: {}, instances: instances, classes: {}, components: {}, defaults: { theme: 'mobiscroll', context: 'body' }, userdef: {}, setDefaults: function (o) { extend(this.userdef, o); }, presetShort: function (name, c, p) { this.components[name] = function (s) { return init(this, extend(s, { component: c, preset: p === false ? undefined : name }), arguments); }; } }; })(jQuery); //widget (function ($, window, document, undefined) { var $activeElm, preventShow, extend = $.extend, ms = $.mobiscroll, instances = ms.instances, userdef = ms.userdef, util = ms.util, pr = util.jsPrefix, has3d = util.has3d, getCoord = util.getCoord, constrain = util.constrain, isString = util.isString, isOldAndroid = /android [1-3]/i.test(navigator.userAgent), animEnd = 'webkitAnimationEnd animationend', empty = function () { }, prevdef = function (ev) { ev.preventDefault(); }; ms.classes.Widget = function (el, settings, inherit) { var $ariaDiv, $ctx, $header, $markup, $overlay, $persp, $popup, $wnd, $wrapper, buttons, btn, doAnim, hasButtons, isModal, lang, modalWidth, modalHeight, posEvents, preset, preventPos, s, scrollLock, setReadOnly, theme, wasReadOnly, wndWidth, wndHeight, that = this, $elm = $(el), elmList = [], posDebounce = {}; function onBtnStart(ev) { // Can't call preventDefault here, it kills page scroll if (btn) { btn.removeClass('dwb-a'); } btn = $(this); // Active button if (!btn.hasClass('dwb-d') && !btn.hasClass('dwb-nhl')) { btn.addClass('dwb-a'); } if (ev.type === 'mousedown') { $(document).on('mouseup', onBtnEnd); } } function onBtnEnd(ev) { if (btn) { btn.removeClass('dwb-a'); btn = null; } if (ev.type === 'mouseup') { $(document).off('mouseup', onBtnEnd); } } function onWndKeyDown(ev) { if (ev.keyCode == 13) { that.select(); } else if (ev.keyCode == 27) { that.cancel(); } } function onShow(prevFocus) { if (!prevFocus) { $popup.focus(); } that.ariaMessage(s.ariaMessage); } function onHide(prevAnim) { var activeEl, value, type, focus = s.focusOnClose; $markup.remove(); if ($activeElm && !prevAnim) { setTimeout(function () { if (focus === undefined || focus === true) { preventShow = true; activeEl = $activeElm[0]; type = activeEl.type; value = activeEl.value; try { activeEl.type = 'button'; } catch (ex) { } $activeElm.focus(); activeEl.type = type; activeEl.value = value; } else if (focus) { // If a mobiscroll field is focused, allow show if (instances[$(focus).attr('id')]) { ms.tapped = false; } $(focus).focus(); } }, 200); } that._isVisible = false; event('onHide', []); } function onPosition(ev) { clearTimeout(posDebounce[ev.type]); posDebounce[ev.type] = setTimeout(function () { var isScroll = ev.type == 'scroll'; if (isScroll && !scrollLock) { return; } that.position(!isScroll); }, 200); } function show(beforeShow) { if (!ms.tapped) { if (beforeShow) { beforeShow(); } // Hide virtual keyboard if ($(document.activeElement).is('input,textarea')) { $(document.activeElement).blur(); } $activeElm = $elm; that.show(); } setTimeout(function () { preventShow = false; }, 300); // With jQuery < 1.9 focus is fired twice in IE } function event(name, args) { var ret; args.push(that); $.each([userdef, theme, preset, settings], function (i, v) { if (v && v[name]) { // Call preset event ret = v[name].apply(el, args); } }); return ret; } /** * Positions the scroller on the screen. */ that.position = function (check) { var w, l, t, anchor, aw, // anchor width ah, // anchor height ap, // anchor position at, // anchor top al, // anchor left arr, // arrow arrw, // arrow width arrl, // arrow left dh, scroll, sl, // scroll left st, // scroll top totalw = 0, minw = 0, css = {}, nw = Math.min($wnd[0].innerWidth || $wnd.innerWidth(), $persp.width()), //$persp.width(), // To get the width without scrollbar nh = $wnd[0].innerHeight || $wnd.innerHeight(); if ((wndWidth === nw && wndHeight === nh && check) || preventPos) { return; } if (that._isFullScreen || /top|bottom/.test(s.display)) { // Set width, if document is larger than viewport, needs to be set before onPosition (for calendar) $popup.width(nw); } if (event('onPosition', [$markup, nw, nh]) === false || !isModal) { return; } sl = $wnd.scrollLeft(); st = $wnd.scrollTop(); anchor = s.anchor === undefined ? $elm : $(s.anchor); // Set / unset liquid layout based on screen width, but only if not set explicitly by the user if (that._isLiquid && s.layout !== 'liquid') { if (nw < 400) { $markup.addClass('dw-liq'); } else { $markup.removeClass('dw-liq'); } } if (!that._isFullScreen && /modal|bubble/.test(s.display)) { $wrapper.width(''); $('.mbsc-w-p', $markup).each(function () { w = $(this).outerWidth(true); totalw += w; minw = (w > minw) ? w : minw; }); w = totalw > nw ? minw : totalw; $wrapper.width(w).css('white-space', totalw > nw ? '' : 'nowrap'); } modalWidth = that._isFullScreen ? nw : $popup.outerWidth(); modalHeight = that._isFullScreen ? nh : $popup.outerHeight(true); scrollLock = modalHeight <= nh && modalWidth <= nw; that.scrollLock = scrollLock; if (s.display == 'modal') { l = Math.max(0, sl + (nw - modalWidth) / 2); t = st + (nh - modalHeight) / 2; } else if (s.display == 'bubble') { scroll = true; arr = $('.dw-arrw-i', $markup); ap = anchor.offset(); at = Math.abs($ctx.offset().top - ap.top); al = Math.abs($ctx.offset().left - ap.left); // horizontal positioning aw = anchor.outerWidth(); ah = anchor.outerHeight(); l = constrain(al - ($popup.outerWidth(true) - aw) / 2, sl + 3, sl + nw - modalWidth - 3); // vertical positioning t = at - modalHeight; // above the input if ((t < st) || (at > st + nh)) { // if doesn't fit above or the input is out of the screen $popup.removeClass('dw-bubble-top').addClass('dw-bubble-bottom'); t = at + ah; // below the input } else { $popup.removeClass('dw-bubble-bottom').addClass('dw-bubble-top'); } // Calculate Arrow position arrw = arr.outerWidth(); arrl = constrain(al + aw / 2 - (l + (modalWidth - arrw) / 2), 0, arrw); // Limit Arrow position $('.dw-arr', $markup).css({ left: arrl }); } else { l = sl; if (s.display == 'top') { t = st; } else if (s.display == 'bottom') { t = st + nh - modalHeight; } } t = t < 0 ? 0 : t; css.top = t; css.left = l; $popup.css(css); // If top + modal height > doc height, increase doc height $persp.height(0); dh = Math.max(t + modalHeight, s.context == 'body' ? $(document).height() : $ctx[0].scrollHeight); $persp.css({ height: dh }); // Scroll needed if (scroll && ((t + modalHeight > st + nh) || (at > st + nh))) { preventPos = true; setTimeout(function () { preventPos = false; }, 300); $wnd.scrollTop(Math.min(t + modalHeight - nh, dh - nh)); } wndWidth = nw; wndHeight = nh; }; /** * Show mobiscroll on focus and click event of the parameter. * @param {jQuery} $elm - Events will be attached to this element. * @param {Function} [beforeShow=undefined] - Optional function to execute before showing mobiscroll. */ that.attachShow = function ($elm, beforeShow) { elmList.push($elm); if (s.display !== 'inline') { if (setReadOnly) { $elm.on('mousedown.dw', function (ev) { // Prevent input to get focus on tap (virtual keyboard pops up on some devices) ev.preventDefault(); }); } if (s.showOnFocus) { $elm.on('focus.dw', function () { if (!preventShow) { show(beforeShow); } }); } if (s.showOnTap) { that.tap($elm, function () { show(beforeShow); }); } } }; /** * Set button handler. */ that.select = function () { if (!isModal || that.hide(false, 'set') !== false) { that._fillValue(); event('onSelect', [that._value]); } }; /** * Cancel and hide the scroller instance. */ that.cancel = function () { if (!isModal || that.hide(false, 'cancel') !== false) { event('onCancel', [that._value]); } }; /** * Clear button handler. */ that.clear = function () { event('onClear', [$markup]); if (isModal && !that.live) { that.hide(false, 'clear'); } that.setValue(null, true); }; /** * Enables the scroller and the associated input. */ that.enable = function () { s.disabled = false; if (that._isInput) { $elm.prop('disabled', false); } }; /** * Disables the scroller and the associated input. */ that.disable = function () { s.disabled = true; if (that._isInput) { $elm.prop('disabled', true); } }; /** * Shows the scroller instance. * @param {Boolean} prevAnim - Prevent animation if true * @param {Boolean} prevFocus - Prevent focusing if true */ that.show = function (prevAnim, prevFocus) { // Create wheels var html; if (s.disabled || that._isVisible) { return; } if (doAnim !== false) { if (s.display == 'top') { doAnim = 'slidedown'; } if (s.display == 'bottom') { doAnim = 'slideup'; } } // Parse value from input that._readValue(); event('onBeforeShow', []); // Create wheels containers html = '
' + '
' + (isModal ? '
' : '') + // Overlay '' + // Popup (s.display === 'bubble' ? '
' : '') + // Bubble arrow '
' + // Popup content '
' + (s.headerText ? '
' + (isString(s.headerText) ? s.headerText : '') + '
' : '') + // Header '
'; // Wheel group container html += that._generateContent(); html += '
'; if (hasButtons) { html += '
'; $.each(buttons, function (i, b) { b = isString(b) ? that.buttons[b] : b; if (b.handler === 'set') { b.parentClass = 'dwb-s'; } if (b.handler === 'cancel') { b.parentClass = 'dwb-c'; } b.handler = isString(b.handler) ? that.handlers[b.handler] : b.handler; html += '
' + (b.text || '') + '
'; }); html += '
'; } html += '
'; $markup = $(html); $persp = $('.dw-persp', $markup); $overlay = $('.dwo', $markup); $wrapper = $('.dwwr', $markup); $header = $('.dwv', $markup); $popup = $('.dw', $markup); $ariaDiv = $('.dw-aria', $markup); that._markup = $markup; that._header = $header; that._isVisible = true; posEvents = 'orientationchange resize'; that._markupReady(); event('onMarkupReady', [$markup]); // Show if (isModal) { // Enter / ESC $(window).on('keydown', onWndKeyDown); // Prevent scroll if not specified otherwise if (s.scrollLock) { $markup.on('touchmove mousewheel DOMMouseScroll', function (ev) { if (scrollLock) { ev.preventDefault(); } }); } // Disable inputs to prevent bleed through (Android bug) if (pr !== 'Moz') { $('input,select,button', $ctx).each(function () { if (!this.disabled) { $(this).addClass('dwtd').prop('disabled', true); } }); } posEvents += ' scroll'; ms.activeInstance = that; $markup.appendTo($ctx); if (has3d && doAnim && !prevAnim) { $markup.addClass('dw-in dw-trans').on(animEnd, function () { $markup.off(animEnd).removeClass('dw-in dw-trans').find('.dw').removeClass('dw-' + doAnim); onShow(prevFocus); }).find('.dw').addClass('dw-' + doAnim); } } else if ($elm.is('div')) { $elm.html($markup); } else { $markup.insertAfter($elm); } event('onMarkupInserted', [$markup]); // Set position that.position(); $wnd.on(posEvents, onPosition); // Events $markup .on('selectstart mousedown', prevdef) // Prevents blue highlight on Android and text selection in IE .on('click', '.dwb-e', prevdef) .on('keydown', '.dwb-e', function (ev) { if (ev.keyCode == 32) { // Space ev.preventDefault(); ev.stopPropagation(); $(this).click(); } }); setTimeout(function () { // Init buttons $.each(buttons, function (i, b) { that.tap($('.dwb' + i, $markup), function (ev) { b = isString(b) ? that.buttons[b] : b; b.handler.call(this, ev, that); }, true); }); if (s.closeOnOverlay) { that.tap($overlay, function () { that.cancel(); }); } if (isModal && !doAnim) { onShow(prevFocus); } $markup .on('touchstart mousedown', '.dwb-e', onBtnStart) .on('touchend', '.dwb-e', onBtnEnd); that._attachEvents($markup); }, 300); event('onShow', [$markup, that._tempValue]); }; /** * Hides the scroller instance. */ that.hide = function (prevAnim, btn, force) { // If onClose handler returns false, prevent hide if (!that._isVisible || (!force && !that._isValid && btn == 'set') || (!force && event('onClose', [that._tempValue, btn]) === false)) { return false; } // Hide wheels and overlay if ($markup) { // Re-enable temporary disabled fields if (pr !== 'Moz') { $('.dwtd', $ctx).each(function () { $(this).prop('disabled', false).removeClass('dwtd'); }); } if (has3d && isModal && doAnim && !prevAnim && !$markup.hasClass('dw-trans')) { // If dw-trans class was not removed, means that there was no animation $markup.addClass('dw-out dw-trans').find('.dw').addClass('dw-' + doAnim).on(animEnd, function () { onHide(prevAnim); }); } else { onHide(prevAnim); } // Stop positioning on window resize $wnd.off(posEvents, onPosition); } if (isModal) { $(window).off('keydown', onWndKeyDown); delete ms.activeInstance; } }; that.ariaMessage = function (txt) { $ariaDiv.html(''); setTimeout(function () { $ariaDiv.html(txt); }, 100); }; /** * Return true if the scroller is currently visible. */ that.isVisible = function () { return that._isVisible; }; // Protected functions to override that.setValue = empty; that._generateContent = empty; that._attachEvents = empty; that._readValue = empty; that._fillValue = empty; that._markupReady = empty; that._processSettings = empty; // Generic widget functions /** * Attach tap event to the given element. */ that.tap = function (el, handler, prevent) { var startX, startY, moved; if (s.tap) { el.on('touchstart.dw', function (ev) { // Can't always call preventDefault here, it kills page scroll if (prevent) { ev.preventDefault(); } startX = getCoord(ev, 'X'); startY = getCoord(ev, 'Y'); moved = false; }).on('touchmove.dw', function (ev) { // If movement is more than 20px, don't fire the click event handler if (Math.abs(getCoord(ev, 'X') - startX) > 20 || Math.abs(getCoord(ev, 'Y') - startY) > 20) { moved = true; } }).on('touchend.dw', function (ev) { var that = this; if (!moved) { // preventDefault and setTimeout are needed by iOS ev.preventDefault(); //setTimeout(function () { handler.call(that, ev); //}, isOldAndroid ? 400 : 10); } // Prevent click events to happen ms.tapped = true; setTimeout(function () { ms.tapped = false; }, 500); }); } el.on('click.dw', function (ev) { if (!ms.tapped) { // If handler was not called on touchend, call it on click; handler.call(this, ev); } ev.preventDefault(); }); }; /** * Sets one ore more options. */ that.option = function (opt, value) { var obj = {}; if (typeof opt === 'object') { obj = opt; } else { obj[opt] = value; } that.init(obj); }; /** * Destroys the mobiscroll instance. */ that.destroy = function () { // Force hide without animation that.hide(true, false, true); // Remove all events from elements $.each(elmList, function (i, v) { v.off('.dw'); }); // Reset original readonly state if (that._isInput && setReadOnly) { el.readOnly = wasReadOnly; } event('onDestroy', []); // Delete scroller instance delete instances[el.id]; that = null; }; /** * Returns the mobiscroll instance. */ that.getInst = function () { return that; }; /** * Triggers a mobiscroll event. */ that.trigger = event; /** * Scroller initialization. */ that.init = function (ss) { that.settings = s = {}; // Update original user settings extend(settings, ss); extend(s, ms.defaults, that._defaults, userdef, settings); // Get theme defaults theme = ms.themes[s.theme] || ms.themes.mobiscroll; // Get language defaults lang = ms.i18n[s.lang]; event('onThemeLoad', [lang, settings]); extend(s, theme, lang, userdef, settings); preset = ms.presets[that._class][s.preset]; // Add default buttons s.buttons = s.buttons || (s.display !== 'inline' ? ['set', 'cancel'] : []); // Hide header text in inline mode by default s.headerText = s.headerText === undefined ? (s.display !== 'inline' ? '{value}' : false) : s.headerText; if (preset) { preset = preset.call(el, that); extend(s, preset, settings); // Load preset settings } if (!ms.themes[s.theme]) { s.theme = 'mobiscroll'; } that._isLiquid = (s.layout || (/top|bottom/.test(s.display) ? 'liquid' : '')) === 'liquid'; that._processSettings(); // Unbind all events (if re-init) $elm.off('.dw'); doAnim = isOldAndroid ? false : s.animate; buttons = s.buttons; isModal = s.display !== 'inline'; setReadOnly = s.showOnFocus || s.showOnTap; $wnd = $(s.context == 'body' ? window : s.context); $ctx = $(s.context); that.context = $wnd; that.live = true; // If no set button is found, live mode is activated $.each(buttons, function (i, b) { if (b === 'set' || b.handler === 'set') { that.live = false; return false; } }); that.buttons.set = { text: s.setText, handler: 'set' }; that.buttons.cancel = { text: (that.live) ? s.closeText : s.cancelText, handler: 'cancel' }; that.buttons.clear = { text: s.clearText, handler: 'clear' }; that._isInput = $elm.is('input'); hasButtons = buttons.length > 0; if (that._isVisible) { that.hide(true, false, true); } if (isModal) { that._readValue(); if (that._isInput && setReadOnly) { // Set element readonly, save original state if (wasReadOnly === undefined) { wasReadOnly = el.readOnly; } el.readOnly = true; } that.attachShow($elm); } else { that.show(); } //if (that._isInput) { $elm.on('change.dw', function () { if (!that._preventChange) { that.setVal($elm.val(), true, false); } that._preventChange = false; }); //} event('onInit', []); }; that.buttons = {}; that.handlers = { set: that.select, cancel: that.cancel, clear: that.clear }; that._value = null; that._isValid = true; that._isVisible = false; // Constructor if (!inherit) { instances[el.id] = that; that.init(settings); } }; ms.classes.Widget.prototype._defaults = { // Localization lang: 'en', setText: 'Set', selectedText: 'Selected', closeText: 'Close', cancelText: 'Cancel', clearText: 'Clear', // Options disabled: false, closeOnOverlay: true, showOnFocus: true, showOnTap: true, display: 'modal', scrollLock: true, tap: true, btnClass: 'dwb', btnWidth: true, focusOnClose: false // Temporary for iOS8 }; ms.themes.mobiscroll = { rows: 5, showLabel: false, headerText: false, btnWidth: false, selectedLineHeight: true, selectedLineBorder: 1, dateOrder: 'MMddyy', weekDays: 'min', checkIcon: 'ion-ios7-checkmark-empty', btnPlusClass: 'mbsc-ic mbsc-ic-arrow-down5', btnMinusClass: 'mbsc-ic mbsc-ic-arrow-up5', btnCalPrevClass: 'mbsc-ic mbsc-ic-arrow-left5', btnCalNextClass: 'mbsc-ic mbsc-ic-arrow-right5' }; // Prevent re-show on window focus $(window).on('focus', function () { if ($activeElm) { preventShow = true; } }); // Prevent standard behaviour on body click $(document).on('mouseover mouseup mousedown click', function (ev) { if (ms.tapped) { ev.stopPropagation(); ev.preventDefault(); return false; } }); })(jQuery, window, document); //scroller (function ($, window, document, undefined) { var move, ms = $.mobiscroll, classes = ms.classes, instances = ms.instances, util = ms.util, pr = util.jsPrefix, has3d = util.has3d, hasFlex = util.hasFlex, getCoord = util.getCoord, constrain = util.constrain, testTouch = util.testTouch; classes.Scroller = function (el, settings, inherit) { var $markup, btn, isScrollable, itemHeight, s, trigger, click, moved, start, startTime, stop, p, min, max, target, index, lines, timer, that = this, $elm = $(el), iv = {}, pos = {}, pixels = {}, wheels = []; // Event handlers function onStart(ev) { // Scroll start if (testTouch(ev, this) && !move && !click && !btn && !isReadOnly(this)) { // Prevent touch highlight ev.preventDefault(); // Better performance if there are tap events on document ev.stopPropagation(); move = true; isScrollable = s.mode != 'clickpick'; target = $('.dw-ul', this); setGlobals(target); moved = iv[index] !== undefined; // Don't allow tap, if still moving p = moved ? getCurrentPosition(target) : pos[index]; start = getCoord(ev, 'Y'); startTime = new Date(); stop = start; scroll(target, index, p, 0.001); if (isScrollable) { target.closest('.dwwl').addClass('dwa'); } if (ev.type === 'mousedown') { $(document).on('mousemove', onMove).on('mouseup', onEnd); } } } function onMove(ev) { if (move) { if (isScrollable) { // Prevent scroll ev.preventDefault(); ev.stopPropagation(); stop = getCoord(ev, 'Y'); if (Math.abs(stop - start) > 3 || moved) { scroll(target, index, constrain(p + (start - stop) / itemHeight, min - 1, max + 1)); moved = true; } } } } function onEnd(ev) { if (move) { var time = new Date() - startTime, val = constrain(p + (start - stop) / itemHeight, min - 1, max + 1), speed, dist, tindex, ttop = target.offset().top; // Better performance if there are tap events on document ev.stopPropagation(); if (has3d && time < 300) { speed = (stop - start) / time; dist = (speed * speed) / s.speedUnit; if (stop - start < 0) { dist = -dist; } } else { dist = stop - start; } tindex = Math.round(p - dist / itemHeight); if (!moved) { // this is a "tap" var idx = Math.floor((stop - ttop) / itemHeight), li = $($('.dw-li', target)[idx]), valid = li.hasClass('dw-v'), hl = isScrollable; if (trigger('onValueTap', [li]) !== false && valid) { tindex = idx; } else { hl = true; } if (hl && valid) { li.addClass('dw-hl'); // Highlight setTimeout(function () { li.removeClass('dw-hl'); }, 100); } } if (isScrollable) { calc(target, tindex, 0, true, Math.round(val)); } if (ev.type === 'mouseup') { $(document).off('mousemove', onMove).off('mouseup', onEnd); } move = false; } } function onBtnStart(ev) { btn = $(this); // +/- buttons if (testTouch(ev, this)) { step(ev, btn.closest('.dwwl'), btn.hasClass('dwwbp') ? plus : minus); } if (ev.type === 'mousedown') { $(document).on('mouseup', onBtnEnd); } } function onBtnEnd(ev) { btn = null; if (click) { clearInterval(timer); click = false; } if (ev.type === 'mouseup') { $(document).off('mouseup', onBtnEnd); } } function onKeyDown(ev) { if (ev.keyCode == 38) { // up step(ev, $(this), minus); } else if (ev.keyCode == 40) { // down step(ev, $(this), plus); } } function onKeyUp() { if (click) { clearInterval(timer); click = false; } } function onScroll(ev) { if (!isReadOnly(this)) { ev.preventDefault(); ev = ev.originalEvent || ev; var delta = ev.wheelDelta ? (ev.wheelDelta / 120) : (ev.detail ? (-ev.detail / 3) : 0), t = $('.dw-ul', this); setGlobals(t); calc(t, Math.round(pos[index] - delta), delta < 0 ? 1 : 2); } } // Private functions function step(ev, w, func) { ev.stopPropagation(); ev.preventDefault(); if (!click && !isReadOnly(w) && !w.hasClass('dwa')) { click = true; // + Button var t = w.find('.dw-ul'); setGlobals(t); clearInterval(timer); timer = setInterval(function () { func(t); }, s.delay); func(t); } } function isReadOnly(wh) { if ($.isArray(s.readonly)) { var i = $('.dwwl', $markup).index(wh); return s.readonly[i]; } return s.readonly; } function generateWheelItems(i) { var html = '
', w = wheels[i], l = 1, labels = w.labels || [], values = w.values, keys = w.keys || values; $.each(values, function (j, v) { if (l % 20 === 0) { html += '
'; } html += '
' + '
1 ? ' style="line-height:' + Math.round(itemHeight / lines) + 'px;font-size:' + Math.round(itemHeight / lines * 0.8) + 'px;"' : '') + '>' + v + '
'; l++; }); html += '
'; return html; } function setGlobals(t) { var multiple = t.closest('.dwwl').hasClass('dwwms'); min = $('.dw-li', t).index($(multiple ? '.dw-li' : '.dw-v', t).eq(0)); max = Math.max(min, $('.dw-li', t).index($(multiple ? '.dw-li' : '.dw-v', t).eq(-1)) - (multiple ? s.rows - 1 : 0)); index = $('.dw-ul', $markup).index(t); } function formatHeader(v) { var t = s.headerText; return t ? (typeof t === 'function' ? t.call(el, v) : t.replace(/\{value\}/i, v)) : ''; } function getCurrentPosition(t) { return Math.round(-util.getPosition(t, true) / itemHeight); } function ready(t, i) { clearTimeout(iv[i]); delete iv[i]; t.closest('.dwwl').removeClass('dwa'); } function scroll(t, index, val, time, active) { var px = -val * itemHeight, style = t[0].style; if (px == pixels[index] && iv[index]) { return; } //if (time && px != pixels[index]) { // Trigger animation start event //trigger('onAnimStart', [$markup, index, time]); //} pixels[index] = px; if (has3d) { style[pr + 'Transition'] = util.prefix + 'transform ' + (time ? time.toFixed(3) : 0) + 's ease-out'; style[pr + 'Transform'] = 'translate3d(0,' + px + 'px,0)'; } else { style.top = px + 'px'; } if (iv[index]) { ready(t, index); } if (time && active) { t.closest('.dwwl').addClass('dwa'); iv[index] = setTimeout(function () { ready(t, index); }, time * 1000); } pos[index] = val; } function getValid(val, t, dir, multiple) { var cell = $('.dw-li[data-val="' + val + '"]', t), cells = $('.dw-li', t), v = cells.index(cell), l = cells.length; if (multiple) { setGlobals(t); } else if (!cell.hasClass('dw-v')) { // Scroll to a valid cell var cell1 = cell, cell2 = cell, dist1 = 0, dist2 = 0; while (v - dist1 >= 0 && !cell1.hasClass('dw-v')) { dist1++; cell1 = cells.eq(v - dist1); } while (v + dist2 < l && !cell2.hasClass('dw-v')) { dist2++; cell2 = cells.eq(v + dist2); } // If we have direction (+/- or mouse wheel), the distance does not count if (((dist2 < dist1 && dist2 && dir !== 2) || !dist1 || (v - dist1 < 0) || dir == 1) && cell2.hasClass('dw-v')) { cell = cell2; v = v + dist2; } else { cell = cell1; v = v - dist1; } } return { cell: cell, v: multiple ? constrain(v, min, max) : v, val: cell.hasClass('dw-v') ? cell.attr('data-val') : null }; } function scrollToPos(time, index, manual, dir, active) { // Call validation event if (trigger('validate', [$markup, index, time, dir]) !== false) { // Set scrollers to position $('.dw-ul', $markup).each(function (i) { var t = $(this), multiple = t.closest('.dwwl').hasClass('dwwms'), sc = i == index || index === undefined, res = getValid(that._tempWheelArray[i], t, dir, multiple), cell = res.cell; if (!(cell.hasClass('dw-sel')) || sc) { // Set valid value that._tempWheelArray[i] = res.val; if (!multiple) { $('.dw-sel', t).removeAttr('aria-selected'); cell.attr('aria-selected', 'true'); } // Add selected class to cell $('.dw-sel', t).removeClass('dw-sel'); cell.addClass('dw-sel'); // Scroll to position scroll(t, i, res.v, sc ? time : 0.1, sc ? active : false); } }); trigger('onValidated', []); // Reformat value if validation changed something that._tempValue = s.formatResult(that._tempWheelArray); if (that.live) { that._hasValue = manual || that._hasValue; setValue(manual, manual, 0, true); } that._header.html(formatHeader(that._tempValue)); if (manual) { trigger('onChange', [that._tempValue]); } } } function calc(t, val, dir, anim, orig) { val = constrain(val, min, max); var cell = $('.dw-li', t).eq(val), o = orig === undefined ? val : orig, active = orig !== undefined, idx = index, dist = Math.abs(val - o), time = anim ? (val == o ? 0.1 : dist * s.timeUnit * Math.max(0.5, (100 - dist) / 100)) : 0; // Set selected scroller value that._tempWheelArray[idx] = cell.attr('data-val'); scroll(t, idx, val, time, active); setTimeout(function () { // Validate scrollToPos(time, idx, true, dir, active); }, 10); } function plus(t) { var val = pos[index] + 1; calc(t, val > max ? min : val, 1, true); } function minus(t) { var val = pos[index] - 1; calc(t, val < min ? max : val, 2, true); } function setValue(fill, change, time, noscroll, temp) { if (that._isVisible && !noscroll) { scrollToPos(time); } that._tempValue = s.formatResult(that._tempWheelArray); if (!temp) { that._wheelArray = that._tempWheelArray.slice(0); that._value = that._hasValue ? that._tempValue : null; } if (fill) { trigger('onValueFill', [that._hasValue ? that._tempValue : '', change]); if (that._isInput) { $elm.val(that._hasValue ? that._tempValue : ''); } if (change) { that._preventChange = true; $elm.change(); } } } // Call the parent constructor classes.Widget.call(this, el, settings, true); // Public functions /** * Gets the selected wheel values, formats it, and set the value of the scroller instance. * If input parameter is true, populates the associated input element. * @param {Array} values Wheel values. * @param {Boolean} [fill=false] Also set the value of the associated input element. * @param {Number} [time=0] Animation time * @param {Boolean} [temp=false] If true, then only set the temporary value.(only scroll there but not set the value) * @param {Boolean} [change=false] Trigger change on the input element */ that.setVal = that._setVal = function (val, fill, change, temp, time) { that._hasValue = val !== null && val !== undefined; that._tempWheelArray = $.isArray(val) ? val.slice(0) : s.parseValue.call(el, val, that) || []; setValue(fill, change === undefined ? fill : change, time, false, temp); }; /** * Returns the selected value */ that.getVal = that._getVal = function (temp) { var val = that._hasValue ? that[temp ? '_tempValue' : '_value'] : null; return util.isNumeric(val) ? +val : val; }; /* * Sets the wheel values (passed as an array) */ that.setArrayVal = that.setVal; /* * Returns the selected wheel values as an array */ that.getArrayVal = function (temp) { return temp ? that._tempWheelArray : that._wheelArray; }; // @deprecated since 2.14.0, backward compatibility code // --- that.setValue = function (val, fill, time, temp, change) { that.setVal(val, fill, change, temp, time); }; /** * Return the selected wheel values. */ that.getValue = that.getArrayVal; // --- /** * Changes the values of a wheel, and scrolls to the correct position * @param {Array} idx Indexes of the wheels to change. * @param {Number} [time=0] Animation time when scrolling to the selected value on the new wheel. * @param {Boolean} [manual=false] Indicates that the change was triggered by the user or from code. */ that.changeWheel = function (idx, time, manual) { if ($markup) { var i = 0, nr = idx.length; $.each(s.wheels, function (j, wg) { $.each(wg, function (k, w) { if ($.inArray(i, idx) > -1) { wheels[i] = w; $('.dw-ul', $markup).eq(i).html(generateWheelItems(i)); nr--; if (!nr) { that.position(); scrollToPos(time, undefined, manual); return false; } } i++; }); if (!nr) { return false; } }); } }; /** * Returns the closest valid cell. */ that.getValidCell = getValid; // Protected overrides that._generateContent = function () { var lbl, html = '', l = 0; $.each(s.wheels, function (i, wg) { // Wheel groups html += '
' + '
' + (hasFlex ? '' : ''); $.each(wg, function (j, w) { // Wheels wheels[l] = w; lbl = w.label !== undefined ? w.label : j; html += '<' + (hasFlex ? 'div' : 'td') + ' class="dwfl"' + ' style="' + (s.fixedWidth ? ('width:' + (s.fixedWidth[l] || s.fixedWidth) + 'px;') : (s.minWidth ? ('min-width:' + (s.minWidth[l] || s.minWidth) + 'px;') : 'min-width:' + s.width + 'px;') + (s.maxWidth ? ('max-width:' + (s.maxWidth[l] || s.maxWidth) + 'px;') : '')) + '">' + '
' + (s.mode != 'scroller' ? '
+
' + // + button '
' : '') + // - button '
' + lbl + '
' + // Wheel label '
' + '
' + '
'; // Create wheel values html += generateWheelItems(l) + '
' + (hasFlex ? '' : ''); l++; }); html += (hasFlex ? '' : '
') + '
'; }); return html; }; that._attachEvents = function ($markup) { $markup .on('DOMMouseScroll mousewheel', '.dwwl', onScroll) .on('keydown', '.dwwl', onKeyDown) .on('keyup', '.dwwl', onKeyUp) .on('touchstart mousedown', '.dwwl', onStart) .on('touchmove', '.dwwl', onMove) .on('touchend', '.dwwl', onEnd) .on('touchstart mousedown', '.dwwb', onBtnStart) .on('touchend', '.dwwb', onBtnEnd); }; that._markupReady = function () { $markup = that._markup; scrollToPos(); }; that._fillValue = function () { that._hasValue = true; setValue(true, true, 0, true); }; that._readValue = function () { var v = $elm.val() || ''; that._hasValue = v !== ''; that._tempWheelArray = that._wheelArray ? that._wheelArray.slice(0) : s.parseValue(v, that) || []; setValue(); }; that._processSettings = function () { s = that.settings; trigger = that.trigger; itemHeight = s.height; lines = s.multiline; that._isLiquid = (s.layout || (/top|bottom/.test(s.display) && s.wheels.length == 1 ? 'liquid' : '')) === 'liquid'; //that._wheelArray = null; //that._tempWheelArray = null; if (lines > 1) { s.cssClass = (s.cssClass || '') + ' dw-ml'; } }; // Properties that._selectedValues = {}; // Constructor if (!inherit) { instances[el.id] = that; that.init(settings); } }; // Extend defaults classes.Scroller.prototype._class = 'scroller'; classes.Scroller.prototype._defaults = $.extend({}, classes.Widget.prototype._defaults, { // Options minWidth: 80, height: 40, rows: 3, multiline: 1, delay: 300, readonly: false, showLabel: true, wheels: [], mode: 'scroller', preset: '', speedUnit: 0.0012, timeUnit: 0.08, formatResult: function (d) { return d.join(' '); }, parseValue: function (value, inst) { var val = [], ret = [], i = 0, keys; if (value !== null && value !== undefined) { val = (value + '').split(' '); } $.each(inst.settings.wheels, function (j, wg) { $.each(wg, function (k, w) { keys = w.keys || w.values; if ($.inArray(val[i], keys) !== -1) { ret.push(val[i]); } else { ret.push(keys[0]); } i++; }); }); return ret; } }); })(jQuery, window, document);