123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724 |
- (function ($, window, document, undefined) {
- var move,
- ms = $.mobiscroll,
- classes = ms.classes,
- util = ms.util,
- pr = util.jsPrefix,
- has3d = util.has3d,
- hasFlex = util.hasFlex,
- getCoord = util.getCoord,
- constrain = util.constrain,
- testTouch = util.testTouch;
- ms.presetShort('scroller', 'Scroller', false);
- classes.Scroller = function (el, settings, inherit) {
- var $markup,
- btn,
- isScrollable,
- itemHeight,
- multiple,
- s,
- scrollDebounce,
- 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,
- curr = constrain(Math.round(p + (start - stop) / itemHeight), min - 1, max + 1),
- val = curr,
- speed,
- dist,
- ttop = target.offset().top;
- // Better performance if there are tap events on document
- ev.stopPropagation();
- move = false;
- if (ev.type === 'mouseup') {
- $(document).off('mousemove', onMove).off('mouseup', onEnd);
- }
- if (has3d && time < 300) {
- speed = (stop - start) / time;
- dist = (speed * speed) / s.speedUnit;
- if (stop - start < 0) {
- dist = -dist;
- }
- } else {
- dist = stop - start;
- }
- 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;
- time = 0.1;
- if (trigger('onValueTap', [li]) !== false && valid) {
- val = idx;
- } else {
- hl = true;
- }
- if (hl && valid) {
- li.addClass('dw-hl'); // Highlight
- setTimeout(function () {
- li.removeClass('dw-hl');
- }, 100);
- }
- if (!multiple && (s.confirmOnTap === true || s.confirmOnTap[index]) && li.hasClass('dw-sel')) {
- that.select();
- return;
- }
- } else {
- val = constrain(Math.round(p - dist / itemHeight), min, max);
- time = speed ? Math.max(0.1, Math.abs((val - curr) / speed) * s.timeUnit) : 0.1;
- }
- if (isScrollable) {
- calc(target, index, val, 0, time, true);
- }
- }
- }
- 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.deltaY || ev.wheelDelta || ev.detail,
- t = $('.dw-ul', this);
- setGlobals(t);
- scroll(t, index, constrain(((delta < 0 ? -20 : 20) - pixels[index]) / itemHeight, min - 1, max + 1));
- clearTimeout(scrollDebounce);
- scrollDebounce = setTimeout(function () {
- calc(t, index, Math.round(pos[index]), delta > 0 ? 1 : 2, 0.1);
- }, 200);
- }
- }
- // 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 = '<div class="dw-bf">',
- 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 += '</div><div class="dw-bf">';
- }
- html += '<div role="option" aria-selected="false" class="dw-li dw-v" data-val="' + keys[j] + '"' + (labels[j] ? ' aria-label="' + labels[j] + '"' : '') + ' style="height:' + itemHeight + 'px;line-height:' + itemHeight + 'px;">' +
- '<div class="dw-i"' + (lines > 1 ? ' style="line-height:' + Math.round(itemHeight / lines) + 'px;font-size:' + Math.round(itemHeight / lines * 0.8) + 'px;"' : '') + '>' + v + '</div></div>';
- l++;
- });
- html += '</div>';
- return html;
- }
- function setGlobals(t) {
- 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 - (s.mode == 'scroller' ? 1 : 3) : 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, select) {
- var selected,
- 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;
- }
- }
- selected = cell.hasClass('dw-sel');
- if (select) {
- 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');
- }
- return {
- selected: selected,
- 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, true),
- selected = res.selected;
- if (!selected || sc) {
- // Set valid value
- that._tempWheelArray[i] = res.val;
- // 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.formatValue(that._tempWheelArray, that);
- 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, idx, val, dir, time, active) {
- val = constrain(val, min, max);
- // Set selected scroller value
- that._tempWheelArray[idx] = $('.dw-li', t).eq(val).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, index, val > max ? min : val, 1, 0.1);
- }
- function minus(t) {
- var val = pos[index] - 1;
- calc(t, index, val < min ? max : val, 2, 0.1);
- }
- function setValue(fill, change, time, noscroll, temp) {
- if (that._isVisible && !noscroll) {
- scrollToPos(time);
- }
- that._tempValue = s.formatValue(that._tempWheelArray, that);
- 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.Frame.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 || temp ? 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;
- that.scroll = scroll;
- // Protected overrides
- that._generateContent = function () {
- var lbl,
- html = '',
- l = 0;
- $.each(s.wheels, function (i, wg) { // Wheel groups
- html += '<div class="mbsc-w-p dwc' + (s.mode != 'scroller' ? ' dwpm' : ' dwsc') + (s.showLabel ? '' : ' dwhl') + '">' +
- '<div class="dwwc"' + (s.maxWidth ? '' : ' style="max-width:600px;"') + '>' +
- (hasFlex ? '' : '<table class="dw-tbl" cellpadding="0" cellspacing="0"><tr>');
- $.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;') : '')) + '">' +
- '<div class="dwwl dwwl' + l + (w.multiple ? ' dwwms' : '') + '">' +
- (s.mode != 'scroller' ?
- '<div class="dwb-e dwwb dwwbp ' + (s.btnPlusClass || '') + '" style="height:' + itemHeight + 'px;line-height:' + itemHeight + 'px;"><span>+</span></div>' + // + button
- '<div class="dwb-e dwwb dwwbm ' + (s.btnMinusClass || '') + '" style="height:' + itemHeight + 'px;line-height:' + itemHeight + 'px;"><span>–</span></div>' : '') + // - button
- '<div class="dwl">' + lbl + '</div>' + // Wheel label
- '<div tabindex="0" aria-live="off" aria-label="' + lbl + '" role="listbox" class="dwww">' +
- '<div class="dww" style="height:' + (s.rows * itemHeight) + 'px;">' +
- '<div class="dw-ul" style="margin-top:' + (w.multiple ? (s.mode == 'scroller' ? 0 : itemHeight) : s.rows / 2 * itemHeight - itemHeight / 2) + 'px;">';
- // Create wheel values
- html += generateWheelItems(l) +
- '</div></div><div class="dwwo"></div></div><div class="dwwol"' +
- (s.selectedLineHeight ? ' style="height:' + itemHeight + 'px;margin-top:-' + (itemHeight / 2 + (s.selectedLineBorder || 0)) + 'px;"' : '') + '></div></div>' +
- (hasFlex ? '</div>' : '</td>');
- l++;
- });
- html += (hasFlex ? '' : '</tr></table>') + '</div></div>';
- });
- return html;
- };
- that._attachEvents = function ($markup) {
- $markup
- .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);
- if (s.mousewheel) {
- $markup.on('wheel mousewheel', '.dwwl', onScroll);
- }
- };
- that._markupReady = function ($m) {
- $markup = $m;
- scrollToPos();
- };
- that._fillValue = function () {
- that._hasValue = true;
- setValue(true, true, 0, true);
- };
- that._readValue = function () {
- var v = $elm.val() || '';
- if (v !== '') {
- that._hasValue = true;
- }
- that._tempWheelArray = that._hasValue && that._wheelArray ? that._wheelArray.slice(0) : s.parseValue.call(el, 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';
- // @deprecated since 2.15.0, backward compatibility code
- // ---
- if (s.formatResult) {
- s.formatValue = s.formatResult;
- }
- // ---
- if (lines > 1) {
- s.cssClass = (s.cssClass || '') + ' dw-ml';
- }
- // Ensure a minimum number of 3 items if clickpick buttons present
- if (s.mode != 'scroller') {
- s.rows = Math.max(3, s.rows);
- }
- };
- // Properties
- that._selectedValues = {};
- // Constructor
- if (!inherit) {
- that.init(settings);
- }
- };
- // Extend defaults
- classes.Scroller.prototype = {
- _hasDef: true,
- _hasTheme: true,
- _hasLang: true,
- _hasPreset: true,
- _class: 'scroller',
- _defaults: $.extend({}, classes.Frame.prototype._defaults, {
- // Options
- minWidth: 80,
- height: 40,
- rows: 3,
- multiline: 1,
- delay: 300,
- readonly: false,
- showLabel: true,
- confirmOnTap: true,
- wheels: [],
- mode: 'scroller',
- preset: '',
- speedUnit: 0.0012,
- timeUnit: 0.08,
- formatValue: function (d) {
- return d.join(' ');
- },
- parseValue: function (value, inst) {
- var val = [],
- ret = [],
- i = 0,
- found,
- 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;
- found = keys[0]; // Default to first wheel value if not found
- $.each(keys, function (l, key) {
- if (val[i] == key) { // Don't do strict comparison
- found = key;
- return false;
- }
- });
- ret.push(found);
- i++;
- });
- });
- return ret;
- }
- })
- };
- ms.themes.scroller = ms.themes.frame;
- })(jQuery, window, document);
|