mobiscroll_date.js 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166
  1. /*jslint eqeq: true, plusplus: true, undef: true, sloppy: true, vars: true, forin: true */
  2. /*!
  3. * jQuery MobiScroll v2.5.1
  4. * http://mobiscroll.com
  5. *
  6. * Copyright 2010-2013, Acid Media
  7. * Licensed under the MIT license.
  8. *
  9. */
  10. (function ($) {
  11. function Scroller(elem, settings) {
  12. var m,
  13. hi,
  14. v,
  15. dw,
  16. ww, // Window width
  17. wh, // Window height
  18. rwh,
  19. mw, // Modal width
  20. mh, // Modal height
  21. anim,
  22. debounce,
  23. that = this,
  24. ms = $.mobiscroll,
  25. e = elem,
  26. elm = $(e),
  27. theme,
  28. lang,
  29. s = extend({}, defaults),
  30. pres = {},
  31. warr = [],
  32. iv = {},
  33. pixels = {},
  34. input = elm.is('input'),
  35. visible = false;
  36. // Private functions
  37. function isReadOnly(wh) {
  38. if ($.isArray(s.readonly)) {
  39. var i = $('.dwwl', dw).index(wh);
  40. return s.readonly[i];
  41. }
  42. return s.readonly;
  43. }
  44. function generateWheelItems(i) {
  45. var html = '<div class="dw-bf">',
  46. l = 1,
  47. j;
  48. for (j in warr[i]) {
  49. if (l % 20 == 0) {
  50. html += '</div><div class="dw-bf">';
  51. }
  52. html += '<div class="dw-li dw-v" data-val="' + j + '" style="height:' + hi + 'px;line-height:' + hi + 'px;"><div class="dw-i">' + warr[i][j] + '</div></div>';
  53. l++;
  54. }
  55. html += '</div>';
  56. return html;
  57. }
  58. function setGlobals(t) {
  59. min = $('.dw-li', t).index($('.dw-v', t).eq(0));
  60. max = $('.dw-li', t).index($('.dw-v', t).eq(-1));
  61. index = $('.dw-ul', dw).index(t);
  62. h = hi;
  63. inst = that;
  64. }
  65. function formatHeader(v) {
  66. var t = s.headerText;
  67. return t ? (typeof t === 'function' ? t.call(e, v) : t.replace(/\{value\}/i, v)) : '';
  68. }
  69. function read() {
  70. that.temp = ((input && that.val !== null && that.val != elm.val()) || that.values === null) ? s.parseValue(elm.val() || '', that) : that.values.slice(0);
  71. that.setValue(true);
  72. }
  73. function scrollToPos(time, index, manual, dir, orig) {
  74. // Call validation event
  75. if (event('validate', [dw, index, time]) !== false) {
  76. // Set scrollers to position
  77. $('.dw-ul', dw).each(function (i) {
  78. var t = $(this),
  79. cell = $('.dw-li[data-val="' + that.temp[i] + '"]', t),
  80. cells = $('.dw-li', t),
  81. v = cells.index(cell),
  82. l = cells.length,
  83. sc = i == index || index === undefined;
  84. // Scroll to a valid cell
  85. if (!cell.hasClass('dw-v')) {
  86. var cell1 = cell,
  87. cell2 = cell,
  88. dist1 = 0,
  89. dist2 = 0;
  90. while (v - dist1 >= 0 && !cell1.hasClass('dw-v')) {
  91. dist1++;
  92. cell1 = cells.eq(v - dist1);
  93. }
  94. while (v + dist2 < l && !cell2.hasClass('dw-v')) {
  95. dist2++;
  96. cell2 = cells.eq(v + dist2);
  97. }
  98. // If we have direction (+/- or mouse wheel), the distance does not count
  99. if (((dist2 < dist1 && dist2 && dir !== 2) || !dist1 || (v - dist1 < 0) || dir == 1) && cell2.hasClass('dw-v')) {
  100. cell = cell2;
  101. v = v + dist2;
  102. } else {
  103. cell = cell1;
  104. v = v - dist1;
  105. }
  106. }
  107. if (!(cell.hasClass('dw-sel')) || sc) {
  108. // Set valid value
  109. that.temp[i] = cell.attr('data-val');
  110. // Add selected class to cell
  111. $('.dw-sel', t).removeClass('dw-sel');
  112. cell.addClass('dw-sel');
  113. // Scroll to position
  114. //that.scroll(t, i, v, time);
  115. that.scroll(t, i, v, sc ? time : 0.1, sc ? orig : undefined);
  116. }
  117. });
  118. // Reformat value if validation changed something
  119. that.change(manual);
  120. }
  121. }
  122. function position(check) {
  123. if (s.display == 'inline' || (ww === $(window).width() && rwh === $(window).height() && check)) {
  124. return;
  125. }
  126. var w,
  127. l,
  128. t,
  129. aw, // anchor width
  130. ah, // anchor height
  131. ap, // anchor position
  132. at, // anchor top
  133. al, // anchor left
  134. arr, // arrow
  135. arrw, // arrow width
  136. arrl, // arrow left
  137. scroll,
  138. totalw = 0,
  139. minw = 0,
  140. st = $(window).scrollTop(),
  141. wr = $('.dwwr', dw),
  142. d = $('.dw', dw),
  143. css = {},
  144. anchor = s.anchor === undefined ? elm : s.anchor;
  145. ww = $(window).width();
  146. rwh = $(window).height();
  147. wh = window.innerHeight; // on iOS we need innerHeight
  148. wh = wh || rwh;
  149. if (/modal|bubble/.test(s.display)) {
  150. $('.dwc', dw).each(function () {
  151. w = $(this).outerWidth(true);
  152. totalw += w;
  153. minw = (w > minw) ? w : minw;
  154. });
  155. w = totalw > ww ? minw : totalw;
  156. wr.width(w);
  157. }
  158. mw = d.outerWidth();
  159. mh = d.outerHeight(true);
  160. if (s.display == 'modal') {
  161. l = (ww - mw) / 2;
  162. t = st + (wh - mh) / 2;
  163. } else if (s.display == 'bubble') {
  164. scroll = true;
  165. arr = $('.dw-arrw-i', dw);
  166. ap = anchor.offset();
  167. at = ap.top;
  168. al = ap.left;
  169. // horizontal positioning
  170. aw = anchor.outerWidth();
  171. ah = anchor.outerHeight();
  172. l = al - (d.outerWidth(true) - aw) / 2;
  173. l = l > (ww - mw) ? (ww - (mw + 20)) : l;
  174. l = l >= 0 ? l : 20;
  175. // vertical positioning
  176. t = at - mh; //(mh + 3); // above the input
  177. if ((t < st) || (at > st + wh)) { // if doesn't fit above or the input is out of the screen
  178. d.removeClass('dw-bubble-top').addClass('dw-bubble-bottom');
  179. t = at + ah;// + 3; // below the input
  180. } else {
  181. d.removeClass('dw-bubble-bottom').addClass('dw-bubble-top');
  182. }
  183. //t = t >= st ? t : st;
  184. // Calculate Arrow position
  185. arrw = arr.outerWidth();
  186. arrl = al + aw / 2 - (l + (mw - arrw) / 2);
  187. // Limit Arrow position to [0, pocw.width] intervall
  188. $('.dw-arr', dw).css({ left: arrl > arrw ? arrw : arrl });
  189. } else {
  190. css.width = '100%';
  191. if (s.display == 'top') {
  192. t = st;
  193. } else if (s.display == 'bottom') {
  194. t = st + wh - mh;
  195. }
  196. }
  197. css.top = t < 0 ? 0 : t;
  198. css.left = l;
  199. d.css(css);
  200. // If top + modal height > doc height, increase doc height
  201. $('.dw-persp', dw).height(0).height(t + mh > $(document).height() ? t + mh : $(document).height());
  202. // Scroll needed
  203. if (scroll && ((t + mh > st + wh) || (at > st + wh))) {
  204. $(window).scrollTop(t + mh - wh);
  205. }
  206. }
  207. function testTouch(e) {
  208. if (e.type === 'touchstart') {
  209. touch = true;
  210. setTimeout(function () {
  211. touch = false; // Reset if mouse event was not fired
  212. }, 500);
  213. } else if (touch) {
  214. touch = false;
  215. return false;
  216. }
  217. return true;
  218. }
  219. function event(name, args) {
  220. var ret;
  221. args.push(that);
  222. $.each([theme.defaults, pres, settings], function (i, v) {
  223. if (v[name]) { // Call preset event
  224. ret = v[name].apply(e, args);
  225. }
  226. });
  227. return ret;
  228. }
  229. function plus(t) {
  230. var p = +t.data('pos'),
  231. val = p + 1;
  232. calc(t, val > max ? min : val, 1, true);
  233. }
  234. function minus(t) {
  235. var p = +t.data('pos'),
  236. val = p - 1;
  237. calc(t, val < min ? max : val, 2, true);
  238. }
  239. // Public functions
  240. /**
  241. * Enables the scroller and the associated input.
  242. */
  243. that.enable = function () {
  244. s.disabled = false;
  245. if (input) {
  246. elm.prop('disabled', false);
  247. }
  248. };
  249. /**
  250. * Disables the scroller and the associated input.
  251. */
  252. that.disable = function () {
  253. s.disabled = true;
  254. if (input) {
  255. elm.prop('disabled', true);
  256. }
  257. };
  258. /**
  259. * Scrolls target to the specified position
  260. * @param {Object} t - Target wheel jQuery object.
  261. * @param {Number} index - Index of the changed wheel.
  262. * @param {Number} val - Value.
  263. * @param {Number} time - Duration of the animation, optional.
  264. * @param {Number} orig - Original value.
  265. */
  266. that.scroll = function (t, index, val, time, orig) {
  267. function getVal(t, b, c, d) {
  268. return c * Math.sin(t / d * (Math.PI / 2)) + b;
  269. }
  270. function ready() {
  271. clearInterval(iv[index]);
  272. delete iv[index];
  273. t.data('pos', val).closest('.dwwl').removeClass('dwa');
  274. }
  275. var px = (m - val) * hi,
  276. i;
  277. if (px == pixels[index] && iv[index]) {
  278. return;
  279. }
  280. if (time && px != pixels[index]) {
  281. // Trigger animation start event
  282. event('onAnimStart', [dw, index, time]);
  283. }
  284. pixels[index] = px;
  285. t.attr('style', (prefix + '-transition:all ' + (time ? time.toFixed(3) : 0) + 's ease-out;') + (has3d ? (prefix + '-transform:translate3d(0,' + px + 'px,0);') : ('top:' + px + 'px;')));
  286. if (iv[index]) {
  287. ready();
  288. }
  289. if (time && orig !== undefined) {
  290. i = 0;
  291. t.closest('.dwwl').addClass('dwa');
  292. iv[index] = setInterval(function () {
  293. i += 0.1;
  294. t.data('pos', Math.round(getVal(i, orig, val - orig, time)));
  295. if (i >= time) {
  296. ready();
  297. }
  298. }, 100);
  299. } else {
  300. t.data('pos', val);
  301. }
  302. };
  303. /**
  304. * Gets the selected wheel values, formats it, and set the value of the scroller instance.
  305. * If input parameter is true, populates the associated input element.
  306. * @param {Boolean} sc - Scroll the wheel in position.
  307. * @param {Boolean} fill - Also set the value of the associated input element. Default is true.
  308. * @param {Number} time - Animation time
  309. * @param {Boolean} temp - If true, then only set the temporary value.(only scroll there but not set the value)
  310. */
  311. that.setValue = function (sc, fill, time, temp) {
  312. if (!$.isArray(that.temp)) {
  313. that.temp = s.parseValue(that.temp + '', that);
  314. }
  315. if (visible && sc) {
  316. scrollToPos(time);
  317. }
  318. v = s.formatResult(that.temp);
  319. if (!temp) {
  320. that.values = that.temp.slice(0);
  321. that.val = v;
  322. }
  323. if (fill) {
  324. if (input) {
  325. elm.val(v).trigger('change');
  326. }
  327. }
  328. };
  329. that.getValues = function () {
  330. var ret = [],
  331. i;
  332. for (i in that._selectedValues) {
  333. ret.push(that._selectedValues[i]);
  334. }
  335. return ret;
  336. };
  337. /**
  338. * Checks if the current selected values are valid together.
  339. * In case of date presets it checks the number of days in a month.
  340. * @param {Number} time - Animation time
  341. * @param {Number} orig - Original value
  342. * @param {Number} i - Currently changed wheel index, -1 if initial validation.
  343. * @param {Number} dir - Scroll direction
  344. */
  345. that.validate = function (i, dir, time, orig) {
  346. scrollToPos(time, i, true, dir, orig);
  347. };
  348. /**
  349. *
  350. */
  351. that.change = function (manual) {
  352. v = s.formatResult(that.temp);
  353. if (s.display == 'inline') {
  354. that.setValue(false, manual);
  355. } else {
  356. $('.dwv', dw).html(formatHeader(v));
  357. }
  358. if (manual) {
  359. event('onChange', [v]);
  360. }
  361. };
  362. /**
  363. * Changes the values of a wheel, and scrolls to the correct position
  364. */
  365. that.changeWheel = function (idx, time) {
  366. if (dw) {
  367. var i = 0,
  368. j,
  369. k,
  370. nr = idx.length;
  371. for (j in s.wheels) {
  372. for (k in s.wheels[j]) {
  373. if ($.inArray(i, idx) > -1) {
  374. warr[i] = s.wheels[j][k];
  375. $('.dw-ul', dw).eq(i).html(generateWheelItems(i));
  376. nr--;
  377. if (!nr) {
  378. position();
  379. scrollToPos(time, undefined, true);
  380. return;
  381. }
  382. }
  383. i++;
  384. }
  385. }
  386. }
  387. };
  388. /**
  389. * Return true if the scroller is currently visible.
  390. */
  391. that.isVisible = function () {
  392. return visible;
  393. };
  394. /**
  395. *
  396. */
  397. that.tap = function (el, handler) {
  398. var startX,
  399. startY;
  400. if (s.tap) {
  401. el.bind('touchstart', function (e) {
  402. e.preventDefault();
  403. startX = getCoord(e, 'X');
  404. startY = getCoord(e, 'Y');
  405. }).bind('touchend', function (e) {
  406. // If movement is less than 20px, fire the click event handler
  407. if (Math.abs(getCoord(e, 'X') - startX) < 20 && Math.abs(getCoord(e, 'Y') - startY) < 20) {
  408. handler.call(this, e);
  409. }
  410. tap = true;
  411. setTimeout(function () {
  412. tap = false;
  413. }, 300);
  414. });
  415. }
  416. el.bind('click', function (e) {
  417. if (!tap) {
  418. // If handler was not called on touchend, call it on click;
  419. handler.call(this, e);
  420. }
  421. });
  422. };
  423. /**
  424. * Shows the scroller instance.
  425. * @param {Boolean} prevAnim - Prevent animation if true
  426. */
  427. that.show = function (prevAnim) {
  428. if (s.disabled || visible) {
  429. return false;
  430. }
  431. if (s.display == 'top') {
  432. anim = 'slidedown';
  433. }
  434. if (s.display == 'bottom') {
  435. anim = 'slideup';
  436. }
  437. // Parse value from input
  438. read();
  439. event('onBeforeShow', [dw]);
  440. // Create wheels
  441. var l = 0,
  442. i,
  443. label,
  444. mAnim = '';
  445. if (anim && !prevAnim) {
  446. mAnim = 'dw-' + anim + ' dw-in';
  447. }
  448. // Create wheels containers
  449. var html = '<div class="dw-trans ' + s.theme + ' dw-' + s.display + '">' + (s.display == 'inline' ? '<div class="dw dwbg dwi"><div class="dwwr">' : '<div class="dw-persp">' + '<div class="dwo"></div><div class="dw dwbg ' + mAnim + '"><div class="dw-arrw"><div class="dw-arrw-i"><div class="dw-arr"></div></div></div><div class="dwwr">' + (s.headerText ? '<div class="dwv"></div>' : ''));
  450. for (i = 0; i < s.wheels.length; i++) {
  451. html += '<div class="dwc' + (s.mode != 'scroller' ? ' dwpm' : ' dwsc') + (s.showLabel ? '' : ' dwhl') + '"><div class="dwwc dwrc"><table cellpadding="0" cellspacing="0"><tr>';
  452. // Create wheels
  453. for (label in s.wheels[i]) {
  454. warr[l] = s.wheels[i][label];
  455. html += '<td><div class="dwwl dwrc dwwl' + l + '">' + (s.mode != 'scroller' ? '<div class="dwwb dwwbp" style="height:' + hi + 'px;line-height:' + hi + 'px;"><span>+</span></div><div class="dwwb dwwbm" style="height:' + hi + 'px;line-height:' + hi + 'px;"><span>&ndash;</span></div>' : '') + '<div class="dwl">' + label + '</div><div class="dww" style="height:' + (s.rows * hi) + 'px;min-width:' + s.width + 'px;"><div class="dw-ul">';
  456. // Create wheel values
  457. html += generateWheelItems(l);
  458. html += '</div><div class="dwwo"></div></div><div class="dwwol"></div></div></td>';
  459. l++;
  460. }
  461. html += '</tr></table></div></div>';
  462. }
  463. html += (s.display != 'inline' ? '<div class="dwbc' + (s.button3 ? ' dwbc-p' : '') + '"><span class="dwbw dwb-s"><span class="dwb">' + s.setText + '</span></span>' + (s.button3 ? '<span class="dwbw dwb-n"><span class="dwb">' + s.button3Text + '</span></span>' : '') + '<span class="dwbw dwb-c"><span class="dwb">' + s.cancelText + '</span></span></div></div>' : '<div class="dwcc"></div>') + '</div></div></div>';
  464. dw = $(html);
  465. scrollToPos();
  466. event('onMarkupReady', [dw]);
  467. // Show
  468. if (s.display != 'inline') {
  469. dw.appendTo('body');
  470. // Remove animation class
  471. setTimeout(function () {
  472. dw.removeClass('dw-trans').find('.dw').removeClass(mAnim);
  473. }, 350);
  474. } else if (elm.is('div')) {
  475. elm.html(dw);
  476. } else {
  477. dw.insertAfter(elm);
  478. }
  479. event('onMarkupInserted', [dw]);
  480. visible = true;
  481. // Theme init
  482. theme.init(dw, that);
  483. if (s.display != 'inline') {
  484. // Init buttons
  485. that.tap($('.dwb-s span', dw), function () {
  486. if (that.hide(false, 'set') !== false) {
  487. that.setValue(false, true);
  488. event('onSelect', [that.val]);
  489. }
  490. });
  491. that.tap($('.dwb-c span', dw), function () {
  492. that.cancel();
  493. });
  494. if (s.button3) {
  495. that.tap($('.dwb-n span', dw), s.button3);
  496. }
  497. // prevent scrolling if not specified otherwise
  498. if (s.scrollLock) {
  499. dw.bind('touchmove', function (e) {
  500. if (mh <= wh && mw <= ww) {
  501. e.preventDefault();
  502. }
  503. });
  504. }
  505. // Disable inputs to prevent bleed through (Android bug)
  506. $('input,select,button').each(function () {
  507. if (!$(this).prop('disabled')) {
  508. $(this).addClass('dwtd').prop('disabled', true);
  509. }
  510. });
  511. // Set position
  512. position();
  513. $(window).bind('resize.dw', function () {
  514. // Sometimes scrollTop is not correctly set, so we wait a little
  515. clearTimeout(debounce);
  516. debounce = setTimeout(function () {
  517. position(true);
  518. }, 100);
  519. });
  520. }
  521. // Events
  522. dw.delegate('.dwwl', 'DOMMouseScroll mousewheel', function (e) {
  523. if (!isReadOnly(this)) {
  524. e.preventDefault();
  525. e = e.originalEvent;
  526. var delta = e.wheelDelta ? (e.wheelDelta / 120) : (e.detail ? (-e.detail / 3) : 0),
  527. t = $('.dw-ul', this),
  528. p = +t.data('pos'),
  529. val = Math.round(p - delta);
  530. setGlobals(t);
  531. calc(t, val, delta < 0 ? 1 : 2);
  532. }
  533. }).delegate('.dwb, .dwwb', START_EVENT, function (e) {
  534. // Active button
  535. $(this).addClass('dwb-a');
  536. }).delegate('.dwwb', START_EVENT, function (e) {
  537. e.stopPropagation();
  538. e.preventDefault();
  539. var w = $(this).closest('.dwwl');
  540. if (testTouch(e) && !isReadOnly(w) && !w.hasClass('dwa')) {
  541. click = true;
  542. // + Button
  543. var t = w.find('.dw-ul'),
  544. func = $(this).hasClass('dwwbp') ? plus : minus;
  545. setGlobals(t);
  546. clearInterval(timer);
  547. timer = setInterval(function () { func(t); }, s.delay);
  548. func(t);
  549. }
  550. }).delegate('.dwwl', START_EVENT, function (e) {
  551. // Prevent scroll
  552. e.preventDefault();
  553. // Scroll start
  554. if (testTouch(e) && !move && !isReadOnly(this) && !click) {
  555. move = true;
  556. $(document).bind(MOVE_EVENT, onMove);
  557. target = $('.dw-ul', this);
  558. scrollable = s.mode != 'clickpick';
  559. pos = +target.data('pos');
  560. setGlobals(target);
  561. moved = iv[index] !== undefined; // Don't allow tap, if still moving
  562. start = getCoord(e, 'Y');
  563. startTime = new Date();
  564. stop = start;
  565. that.scroll(target, index, pos, 0.001);
  566. if (scrollable) {
  567. target.closest('.dwwl').addClass('dwa');
  568. }
  569. }
  570. });
  571. event('onShow', [dw, v]);
  572. };
  573. /**
  574. * Hides the scroller instance.
  575. */
  576. that.hide = function (prevAnim, btn) {
  577. // If onClose handler returns false, prevent hide
  578. if (!visible || event('onClose', [v, btn]) === false) {
  579. return false;
  580. }
  581. // Re-enable temporary disabled fields
  582. $('.dwtd').prop('disabled', false).removeClass('dwtd');
  583. elm.blur();
  584. // Hide wheels and overlay
  585. if (dw) {
  586. if (s.display != 'inline' && anim && !prevAnim) {
  587. dw.addClass('dw-trans').find('.dw').addClass('dw-' + anim + ' dw-out');
  588. setTimeout(function () {
  589. dw.remove();
  590. dw = null;
  591. }, 350);
  592. } else {
  593. dw.remove();
  594. dw = null;
  595. }
  596. visible = false;
  597. pixels = {};
  598. // Stop positioning on window resize
  599. $(window).unbind('.dw');
  600. }
  601. };
  602. /**
  603. * Cancel and hide the scroller instance.
  604. */
  605. that.cancel = function () {
  606. if (that.hide(false, 'cancel') !== false) {
  607. event('onCancel', [that.val]);
  608. }
  609. };
  610. /**
  611. * Scroller initialization.
  612. */
  613. that.init = function (ss) {
  614. // Get theme defaults
  615. theme = extend({ defaults: {}, init: empty }, ms.themes[ss.theme || s.theme]);
  616. // Get language defaults
  617. lang = ms.i18n[ss.lang || s.lang];
  618. extend(settings, ss); // Update original user settings
  619. extend(s, theme.defaults, lang, settings);
  620. that.settings = s;
  621. // Unbind all events (if re-init)
  622. elm.unbind('.dw');
  623. var preset = ms.presets[s.preset];
  624. if (preset) {
  625. pres = preset.call(e, that);
  626. extend(s, pres, settings); // Load preset settings
  627. extend(methods, pres.methods); // Extend core methods
  628. }
  629. // Set private members
  630. m = Math.floor(s.rows / 2);
  631. hi = s.height;
  632. anim = s.animate;
  633. if (elm.data('dwro') !== undefined) {
  634. e.readOnly = bool(elm.data('dwro'));
  635. }
  636. if (visible) {
  637. that.hide();
  638. }
  639. if (s.display == 'inline') {
  640. that.show();
  641. } else {
  642. read();
  643. if (input && s.showOnFocus) {
  644. // Set element readonly, save original state
  645. elm.data('dwro', e.readOnly);
  646. e.readOnly = true;
  647. // Init show datewheel
  648. elm.bind('focus.dw', function () { that.show(); });
  649. }
  650. }
  651. };
  652. that.trigger = function (name, params) {
  653. return event(name, params);
  654. };
  655. that.values = null;
  656. that.val = null;
  657. that.temp = null;
  658. that._selectedValues = {}; // [];
  659. that.init(settings);
  660. }
  661. function testProps(props) {
  662. var i;
  663. for (i in props) {
  664. if (mod[props[i]] !== undefined) {
  665. return true;
  666. }
  667. }
  668. return false;
  669. }
  670. function testPrefix() {
  671. var prefixes = ['Webkit', 'Moz', 'O', 'ms'],
  672. p;
  673. for (p in prefixes) {
  674. if (testProps([prefixes[p] + 'Transform'])) {
  675. return '-' + prefixes[p].toLowerCase();
  676. }
  677. }
  678. return '';
  679. }
  680. function getInst(e) {
  681. return scrollers[e.id];
  682. }
  683. function getCoord(e, c) {
  684. var org = e.originalEvent,
  685. ct = e.changedTouches;
  686. return ct || (org && org.changedTouches) ? (org ? org.changedTouches[0]['page' + c] : ct[0]['page' + c]) : e['page' + c];
  687. }
  688. function bool(v) {
  689. return (v === true || v == 'true');
  690. }
  691. function constrain(val, min, max) {
  692. val = val > max ? max : val;
  693. val = val < min ? min : val;
  694. return val;
  695. }
  696. function calc(t, val, dir, anim, orig) {
  697. val = constrain(val, min, max);
  698. var cell = $('.dw-li', t).eq(val),
  699. o = orig === undefined ? val : orig,
  700. idx = index,
  701. time = anim ? (val == o ? 0.1 : Math.abs((val - o) * 0.1)) : 0;
  702. // Set selected scroller value
  703. inst.temp[idx] = cell.attr('data-val');
  704. inst.scroll(t, idx, val, time, orig);
  705. setTimeout(function () {
  706. // Validate
  707. inst.validate(idx, dir, time, orig);
  708. }, 10);
  709. }
  710. function init(that, method, args) {
  711. if (methods[method]) {
  712. return methods[method].apply(that, Array.prototype.slice.call(args, 1));
  713. }
  714. if (typeof method === 'object') {
  715. return methods.init.call(that, method);
  716. }
  717. return that;
  718. }
  719. var scrollers = {},
  720. timer,
  721. empty = function () { },
  722. h,
  723. min,
  724. max,
  725. inst, // Current instance
  726. date = new Date(),
  727. uuid = date.getTime(),
  728. move,
  729. click,
  730. target,
  731. index,
  732. start,
  733. stop,
  734. startTime,
  735. pos,
  736. moved,
  737. scrollable,
  738. mod = document.createElement('modernizr').style,
  739. has3d = testProps(['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']),
  740. prefix = testPrefix(),
  741. extend = $.extend,
  742. tap,
  743. touch,
  744. START_EVENT = 'touchstart mousedown',
  745. MOVE_EVENT = 'touchmove mousemove',
  746. END_EVENT = 'touchend mouseup',
  747. onMove = function (e) {
  748. if (scrollable) {
  749. e.preventDefault();
  750. stop = getCoord(e, 'Y');
  751. inst.scroll(target, index, constrain(pos + (start - stop) / h, min - 1, max + 1));
  752. }
  753. moved = true;
  754. },
  755. defaults = {
  756. // Options
  757. width: 70,
  758. height: 40,
  759. rows: 3,
  760. delay: 300,
  761. disabled: false,
  762. readonly: false,
  763. showOnFocus: true,
  764. showLabel: true,
  765. wheels: [],
  766. theme: '',
  767. headerText: '{value}',
  768. display: 'modal',
  769. mode: 'scroller',
  770. preset: '',
  771. lang: 'en-US',
  772. setText: 'Set',
  773. cancelText: 'Cancel',
  774. scrollLock: true,
  775. tap: true,
  776. formatResult: function (d) {
  777. return d.join(' ');
  778. },
  779. parseValue: function (value, inst) {
  780. var w = inst.settings.wheels,
  781. val = value.split(' '),
  782. ret = [],
  783. j = 0,
  784. i,
  785. l,
  786. v;
  787. for (i = 0; i < w.length; i++) {
  788. for (l in w[i]) {
  789. if (w[i][l][val[j]] !== undefined) {
  790. ret.push(val[j]);
  791. } else {
  792. for (v in w[i][l]) { // Select first value from wheel
  793. ret.push(v);
  794. break;
  795. }
  796. }
  797. j++;
  798. }
  799. }
  800. return ret;
  801. }
  802. },
  803. methods = {
  804. init: function (options) {
  805. if (options === undefined) {
  806. options = {};
  807. }
  808. return this.each(function () {
  809. if (!this.id) {
  810. uuid += 1;
  811. this.id = 'scoller' + uuid;
  812. }
  813. scrollers[this.id] = new Scroller(this, options);
  814. });
  815. },
  816. enable: function () {
  817. return this.each(function () {
  818. var inst = getInst(this);
  819. if (inst) {
  820. inst.enable();
  821. }
  822. });
  823. },
  824. disable: function () {
  825. return this.each(function () {
  826. var inst = getInst(this);
  827. if (inst) {
  828. inst.disable();
  829. }
  830. });
  831. },
  832. isDisabled: function () {
  833. var inst = getInst(this[0]);
  834. if (inst) {
  835. return inst.settings.disabled;
  836. }
  837. },
  838. isVisible: function () {
  839. var inst = getInst(this[0]);
  840. if (inst) {
  841. return inst.isVisible();
  842. }
  843. },
  844. option: function (option, value) {
  845. return this.each(function () {
  846. var inst = getInst(this);
  847. if (inst) {
  848. var obj = {};
  849. if (typeof option === 'object') {
  850. obj = option;
  851. } else {
  852. obj[option] = value;
  853. }
  854. inst.init(obj);
  855. }
  856. });
  857. },
  858. setValue: function (d, fill, time, temp) {
  859. return this.each(function () {
  860. var inst = getInst(this);
  861. if (inst) {
  862. inst.temp = d;
  863. inst.setValue(true, fill, time, temp);
  864. }
  865. });
  866. },
  867. getInst: function () {
  868. return getInst(this[0]);
  869. },
  870. getValue: function () {
  871. var inst = getInst(this[0]);
  872. if (inst) {
  873. return inst.values;
  874. }
  875. },
  876. getValues: function () {
  877. var inst = getInst(this[0]);
  878. if (inst) {
  879. return inst.getValues();
  880. }
  881. },
  882. show: function () {
  883. var inst = getInst(this[0]);
  884. if (inst) {
  885. return inst.show();
  886. }
  887. },
  888. hide: function () {
  889. return this.each(function () {
  890. var inst = getInst(this);
  891. if (inst) {
  892. inst.hide();
  893. }
  894. });
  895. },
  896. destroy: function () {
  897. return this.each(function () {
  898. var inst = getInst(this);
  899. if (inst) {
  900. inst.hide();
  901. $(this).unbind('.dw');
  902. delete scrollers[this.id];
  903. if ($(this).is('input')) {
  904. this.readOnly = bool($(this).data('dwro'));
  905. }
  906. }
  907. });
  908. }
  909. };
  910. $(document).bind(END_EVENT, function (e) {
  911. if (move) {
  912. var time = new Date() - startTime,
  913. val = constrain(pos + (start - stop) / h, min - 1, max + 1),
  914. speed,
  915. dist,
  916. tindex,
  917. ttop = target.offset().top;
  918. if (time < 300) {
  919. speed = (stop - start) / time;
  920. dist = (speed * speed) / (2 * 0.0006);
  921. if (stop - start < 0) {
  922. dist = -dist;
  923. }
  924. } else {
  925. dist = stop - start;
  926. }
  927. tindex = Math.round(pos - dist / h);
  928. if (!dist && !moved) { // this is a "tap"
  929. var idx = Math.floor((stop - ttop) / h),
  930. li = $('.dw-li', target).eq(idx),
  931. hl = scrollable;
  932. if (inst.trigger('onValueTap', [li]) !== false) {
  933. tindex = idx;
  934. } else {
  935. hl = true;
  936. }
  937. if (hl) {
  938. li.addClass('dw-hl'); // Highlight
  939. setTimeout(function () {
  940. li.removeClass('dw-hl');
  941. }, 200);
  942. }
  943. }
  944. if (scrollable) {
  945. calc(target, tindex, 0, true, Math.round(val));
  946. }
  947. move = false;
  948. target = null;
  949. $(document).unbind(MOVE_EVENT, onMove);
  950. }
  951. if (click) {
  952. clearInterval(timer);
  953. click = false;
  954. }
  955. $('.dwb-a').removeClass('dwb-a');
  956. }).bind('mouseover mouseup mousedown click', function (e) { // Prevent standard behaviour on body click
  957. if (tap) {
  958. e.stopPropagation();
  959. e.preventDefault();
  960. return false;
  961. }
  962. });
  963. $.fn.mobiscroll = function (method) {
  964. extend(this, $.mobiscroll.shorts);
  965. return init(this, method, arguments);
  966. };
  967. $.mobiscroll = $.mobiscroll || {
  968. /**
  969. * Set settings for all instances.
  970. * @param {Object} o - New default settings.
  971. */
  972. setDefaults: function (o) {
  973. extend(defaults, o);
  974. },
  975. presetShort: function (name) {
  976. this.shorts[name] = function (method) {
  977. return init(this, extend(method, { preset: name }), arguments);
  978. };
  979. },
  980. shorts: {},
  981. presets: {},
  982. themes: {},
  983. i18n: {}
  984. };
  985. $.scroller = $.scroller || $.mobiscroll;
  986. $.fn.scroller = $.fn.scroller || $.fn.mobiscroll;
  987. $.mobiscroll.i18n.zh = $.extend($.mobiscroll.i18n.zh, {
  988. dateFormat: 'yyyy-mm-dd',
  989. dateOrder: 'yymmdd',
  990. dayNames: ['周日', '周一;', '周二;', '周三', '周四', '周五', '周六'],
  991. dayNamesShort: ['日', '一', '二', '三', '四', '五', '六'],
  992. dayText: '日',
  993. hourText: '时',
  994. minuteText: '分',
  995. monthNames: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
  996. monthNamesShort: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
  997. monthText: '月',
  998. secText: '秒',
  999. timeFormat: 'HH:ii',
  1000. timeWheels: 'HHii',
  1001. yearText: '年'
  1002. });
  1003. $.mobiscroll.i18n.zh = $.extend($.mobiscroll.i18n.zh, {
  1004. setText: '确定',
  1005. cancelText: '取消'
  1006. });
  1007. var theme = {
  1008. defaults: {
  1009. dateOrder: 'Mddyy',
  1010. mode: 'mixed',
  1011. rows: 5,
  1012. width: 70,
  1013. height: 36,
  1014. showLabel: true,
  1015. useShortLabels: true
  1016. }
  1017. }
  1018. $.mobiscroll.themes['android-ics'] = theme;
  1019. $.mobiscroll.themes['android-ics light'] = theme;
  1020. })(jQuery);