mobiscroll.frame.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. (function ($, window, document, undefined) {
  2. var $activeElm,
  3. preventShow,
  4. ms = $.mobiscroll,
  5. instances = ms.instances,
  6. util = ms.util,
  7. pr = util.jsPrefix,
  8. has3d = util.has3d,
  9. getCoord = util.getCoord,
  10. constrain = util.constrain,
  11. isString = util.isString,
  12. isOldAndroid = /android [1-3]/i.test(navigator.userAgent),
  13. isIOS8 = /(iphone|ipod|ipad).* os 8_/i.test(navigator.userAgent),
  14. animEnd = 'webkitAnimationEnd animationend',
  15. empty = function () { },
  16. prevdef = function (ev) { ev.preventDefault(); };
  17. ms.classes.Frame = function (el, settings, inherit) {
  18. var $ariaDiv,
  19. $ctx,
  20. $header,
  21. $markup,
  22. $overlay,
  23. $persp,
  24. $popup,
  25. $wnd,
  26. $wrapper,
  27. buttons,
  28. btn,
  29. doAnim,
  30. event,
  31. hasButtons,
  32. isModal,
  33. modalWidth,
  34. modalHeight,
  35. posEvents,
  36. preventPos,
  37. s,
  38. scrollLock,
  39. setReadOnly,
  40. wndWidth,
  41. wndHeight,
  42. that = this,
  43. $elm = $(el),
  44. elmList = [],
  45. posDebounce = {};
  46. function onBtnStart(ev) {
  47. // Can't call preventDefault here, it kills page scroll
  48. if (btn) {
  49. btn.removeClass('dwb-a');
  50. }
  51. btn = $(this);
  52. // Active button
  53. if (!btn.hasClass('dwb-d') && !btn.hasClass('dwb-nhl')) {
  54. btn.addClass('dwb-a');
  55. }
  56. if (ev.type === 'mousedown') {
  57. $(document).on('mouseup', onBtnEnd);
  58. }
  59. }
  60. function onBtnEnd(ev) {
  61. if (btn) {
  62. btn.removeClass('dwb-a');
  63. btn = null;
  64. }
  65. if (ev.type === 'mouseup') {
  66. $(document).off('mouseup', onBtnEnd);
  67. }
  68. }
  69. function onWndKeyDown(ev) {
  70. if (ev.keyCode == 13) {
  71. that.select();
  72. } else if (ev.keyCode == 27) {
  73. that.cancel();
  74. }
  75. }
  76. function onShow(prevFocus) {
  77. if (!prevFocus) {
  78. $popup.focus();
  79. }
  80. that.ariaMessage(s.ariaMessage);
  81. }
  82. function onHide(prevAnim) {
  83. var activeEl,
  84. value,
  85. type,
  86. focus = s.focusOnClose;
  87. $markup.remove();
  88. if ($activeElm && !prevAnim) {
  89. setTimeout(function () {
  90. if (focus === undefined || focus === true) {
  91. preventShow = true;
  92. activeEl = $activeElm[0];
  93. type = activeEl.type;
  94. value = activeEl.value;
  95. try {
  96. activeEl.type = 'button';
  97. } catch (ex) { }
  98. $activeElm.focus();
  99. activeEl.type = type;
  100. activeEl.value = value;
  101. } else if (focus) {
  102. // If a mobiscroll field is focused, allow show
  103. if (instances[$(focus).attr('id')]) {
  104. ms.tapped = false;
  105. }
  106. $(focus).focus();
  107. }
  108. }, 200);
  109. }
  110. that._isVisible = false;
  111. event('onHide', []);
  112. }
  113. function onPosition(ev) {
  114. clearTimeout(posDebounce[ev.type]);
  115. posDebounce[ev.type] = setTimeout(function () {
  116. var isScroll = ev.type == 'scroll';
  117. if (isScroll && !scrollLock) {
  118. return;
  119. }
  120. that.position(!isScroll);
  121. }, 200);
  122. }
  123. function onFocus(ev) {
  124. if (!$popup[0].contains(ev.target)) {
  125. $popup.focus();
  126. }
  127. }
  128. function show(beforeShow, $elm) {
  129. if (!ms.tapped) {
  130. if (beforeShow) {
  131. beforeShow();
  132. }
  133. // Hide virtual keyboard
  134. if ($(document.activeElement).is('input,textarea')) {
  135. $(document.activeElement).blur();
  136. }
  137. $activeElm = $elm;
  138. that.show();
  139. }
  140. setTimeout(function () {
  141. preventShow = false;
  142. }, 300); // With jQuery < 1.9 focus is fired twice in IE
  143. }
  144. // Call the parent constructor
  145. ms.classes.Base.call(this, el, settings, true);
  146. /**
  147. * Positions the scroller on the screen.
  148. */
  149. that.position = function (check) {
  150. var w,
  151. l,
  152. t,
  153. anchor,
  154. aw, // anchor width
  155. ah, // anchor height
  156. ap, // anchor position
  157. at, // anchor top
  158. al, // anchor left
  159. arr, // arrow
  160. arrw, // arrow width
  161. arrl, // arrow left
  162. dh,
  163. scroll,
  164. sl, // scroll left
  165. st, // scroll top
  166. totalw = 0,
  167. minw = 0,
  168. css = {},
  169. nw = Math.min($wnd[0].innerWidth || $wnd.innerWidth(), $persp.width()), //$persp.width(), // To get the width without scrollbar
  170. nh = $wnd[0].innerHeight || $wnd.innerHeight();
  171. if ((wndWidth === nw && wndHeight === nh && check) || preventPos) {
  172. return;
  173. }
  174. if (that._isFullScreen || /top|bottom/.test(s.display)) {
  175. // Set width, if document is larger than viewport, needs to be set before onPosition (for calendar)
  176. $popup.width(nw);
  177. }
  178. if (event('onPosition', [$markup, nw, nh]) === false || !isModal) {
  179. return;
  180. }
  181. sl = $wnd.scrollLeft();
  182. st = $wnd.scrollTop();
  183. anchor = s.anchor === undefined ? $elm : $(s.anchor);
  184. // Set / unset liquid layout based on screen width, but only if not set explicitly by the user
  185. if (that._isLiquid && s.layout !== 'liquid') {
  186. if (nw < 400) {
  187. $markup.addClass('dw-liq');
  188. } else {
  189. $markup.removeClass('dw-liq');
  190. }
  191. }
  192. if (!that._isFullScreen && /modal|bubble/.test(s.display)) {
  193. $wrapper.width('');
  194. $('.mbsc-w-p', $markup).each(function () {
  195. w = $(this).outerWidth(true);
  196. totalw += w;
  197. minw = (w > minw) ? w : minw;
  198. });
  199. w = totalw > nw ? minw : totalw;
  200. $wrapper.width(w).css('white-space', totalw > nw ? '' : 'nowrap');
  201. }
  202. modalWidth = that._isFullScreen ? nw : $popup.outerWidth();
  203. modalHeight = that._isFullScreen ? nh : $popup.outerHeight(true);
  204. scrollLock = modalHeight <= nh && modalWidth <= nw;
  205. that.scrollLock = scrollLock;
  206. if (s.display == 'modal') {
  207. l = Math.max(0, sl + (nw - modalWidth) / 2);
  208. t = st + (nh - modalHeight) / 2;
  209. } else if (s.display == 'bubble') {
  210. scroll = true;
  211. arr = $('.dw-arrw-i', $markup);
  212. ap = anchor.offset();
  213. at = Math.abs($ctx.offset().top - ap.top);
  214. al = Math.abs($ctx.offset().left - ap.left);
  215. // horizontal positioning
  216. aw = anchor.outerWidth();
  217. ah = anchor.outerHeight();
  218. l = constrain(al - ($popup.outerWidth(true) - aw) / 2, sl + 3, sl + nw - modalWidth - 3);
  219. // vertical positioning
  220. t = at - modalHeight; // above the input
  221. if ((t < st) || (at > st + nh)) { // if doesn't fit above or the input is out of the screen
  222. $popup.removeClass('dw-bubble-top').addClass('dw-bubble-bottom');
  223. t = at + ah; // below the input
  224. } else {
  225. $popup.removeClass('dw-bubble-bottom').addClass('dw-bubble-top');
  226. }
  227. // Calculate Arrow position
  228. arrw = arr.outerWidth();
  229. arrl = constrain(al + aw / 2 - (l + (modalWidth - arrw) / 2), 0, arrw);
  230. // Limit Arrow position
  231. $('.dw-arr', $markup).css({ left: arrl });
  232. } else {
  233. l = sl;
  234. if (s.display == 'top') {
  235. t = st;
  236. } else if (s.display == 'bottom') {
  237. t = st + nh - modalHeight;
  238. }
  239. }
  240. t = t < 0 ? 0 : t;
  241. css.top = t;
  242. css.left = l;
  243. $popup.css(css);
  244. // If top + modal height > doc height, increase doc height
  245. $persp.height(0);
  246. dh = Math.max(t + modalHeight, s.context == 'body' ? $(document).height() : $ctx[0].scrollHeight);
  247. $persp.css({ height: dh });
  248. // Scroll needed
  249. if (scroll && ((t + modalHeight > st + nh) || (at > st + nh))) {
  250. preventPos = true;
  251. setTimeout(function () { preventPos = false; }, 300);
  252. $wnd.scrollTop(Math.min(t + modalHeight - nh, dh - nh));
  253. }
  254. wndWidth = nw;
  255. wndHeight = nh;
  256. };
  257. /**
  258. * Show mobiscroll on focus and click event of the parameter.
  259. * @param {jQuery} $elm - Events will be attached to this element.
  260. * @param {Function} [beforeShow=undefined] - Optional function to execute before showing mobiscroll.
  261. */
  262. that.attachShow = function ($elm, beforeShow) {
  263. elmList.push({ readOnly: $elm.prop('readonly'), el: $elm });
  264. if (s.display !== 'inline') {
  265. if (setReadOnly && $elm.is('input')) {
  266. $elm.prop('readonly', true).on('mousedown.dw', function (ev) {
  267. // Prevent input to get focus on tap (virtual keyboard pops up on some devices)
  268. ev.preventDefault();
  269. });
  270. }
  271. if (s.showOnFocus) {
  272. $elm.on('focus.dw', function () {
  273. if (!preventShow) {
  274. show(beforeShow, $elm);
  275. }
  276. });
  277. }
  278. if (s.showOnTap) {
  279. $elm.on('keydown.dw', function (ev) {
  280. if (ev.keyCode == 32 || ev.keyCode == 13) { // Space or Enter
  281. ev.preventDefault();
  282. ev.stopPropagation();
  283. show(beforeShow, $elm);
  284. }
  285. });
  286. that.tap($elm, function () {
  287. show(beforeShow, $elm);
  288. });
  289. }
  290. }
  291. };
  292. /**
  293. * Set button handler.
  294. */
  295. that.select = function () {
  296. if (!isModal || that.hide(false, 'set') !== false) {
  297. that._fillValue();
  298. event('onSelect', [that._value]);
  299. }
  300. };
  301. /**
  302. * Cancel and hide the scroller instance.
  303. */
  304. that.cancel = function () {
  305. if (!isModal || that.hide(false, 'cancel') !== false) {
  306. event('onCancel', [that._value]);
  307. }
  308. };
  309. /**
  310. * Clear button handler.
  311. */
  312. that.clear = function () {
  313. event('onClear', [$markup]);
  314. if (isModal && !that.live) {
  315. that.hide(false, 'clear');
  316. }
  317. that.setVal(null, true);
  318. };
  319. /**
  320. * Enables the scroller and the associated input.
  321. */
  322. that.enable = function () {
  323. s.disabled = false;
  324. if (that._isInput) {
  325. $elm.prop('disabled', false);
  326. }
  327. };
  328. /**
  329. * Disables the scroller and the associated input.
  330. */
  331. that.disable = function () {
  332. s.disabled = true;
  333. if (that._isInput) {
  334. $elm.prop('disabled', true);
  335. }
  336. };
  337. /**
  338. * Shows the scroller instance.
  339. * @param {Boolean} prevAnim - Prevent animation if true
  340. * @param {Boolean} prevFocus - Prevent focusing if true
  341. */
  342. that.show = function (prevAnim, prevFocus) {
  343. // Create wheels
  344. var html;
  345. if (s.disabled || that._isVisible) {
  346. return;
  347. }
  348. if (doAnim !== false) {
  349. if (s.display == 'top') {
  350. doAnim = 'slidedown';
  351. }
  352. if (s.display == 'bottom') {
  353. doAnim = 'slideup';
  354. }
  355. }
  356. // Parse value from input
  357. that._readValue();
  358. event('onBeforeShow', []);
  359. // Create wheels containers
  360. html = '<div lang="' + s.lang + '" class="mbsc-' + s.theme + (s.baseTheme ? ' mbsc-' + s.baseTheme : '') + ' dw-' + s.display + ' ' +
  361. (s.cssClass || '') +
  362. (that._isLiquid ? ' dw-liq' : '') +
  363. (isOldAndroid ? ' mbsc-old' : '') +
  364. (hasButtons ? '' : ' dw-nobtn') + '">' +
  365. '<div class="dw-persp">' +
  366. (isModal ? '<div class="dwo"></div>' : '') + // Overlay
  367. '<div' + (isModal ? ' role="dialog" tabindex="-1"' : '') + ' class="dw' + (s.rtl ? ' dw-rtl' : ' dw-ltr') + '">' + // Popup
  368. (s.display === 'bubble' ? '<div class="dw-arrw"><div class="dw-arrw-i"><div class="dw-arr"></div></div></div>' : '') + // Bubble arrow
  369. '<div class="dwwr">' + // Popup content
  370. '<div aria-live="assertive" class="dw-aria dw-hidden"></div>' +
  371. (s.headerText ? '<div class="dwv">' + (isString(s.headerText) ? s.headerText : '') + '</div>' : '') + // Header
  372. '<div class="dwcc">'; // Wheel group container
  373. html += that._generateContent();
  374. html += '</div>';
  375. if (hasButtons) {
  376. html += '<div class="dwbc">';
  377. $.each(buttons, function (i, b) {
  378. b = isString(b) ? that.buttons[b] : b;
  379. if (b.handler === 'set') {
  380. b.parentClass = 'dwb-s';
  381. }
  382. if (b.handler === 'cancel') {
  383. b.parentClass = 'dwb-c';
  384. }
  385. b.handler = isString(b.handler) ? that.handlers[b.handler] : b.handler;
  386. html += '<div' + (s.btnWidth ? ' style="width:' + (100 / buttons.length) + '%"' : '') + ' class="dwbw ' + (b.parentClass || '') + '"><div tabindex="0" role="button" class="dwb' + i + ' dwb-e ' + (b.cssClass === undefined ? s.btnClass : b.cssClass) + (b.icon ? ' mbsc-ic mbsc-ic-' + b.icon : '') + '">' + (b.text || '') + '</div></div>';
  387. });
  388. html += '</div>';
  389. }
  390. html += '</div></div></div></div>';
  391. $markup = $(html);
  392. $persp = $('.dw-persp', $markup);
  393. $overlay = $('.dwo', $markup);
  394. $wrapper = $('.dwwr', $markup);
  395. $header = $('.dwv', $markup);
  396. $popup = $('.dw', $markup);
  397. $ariaDiv = $('.dw-aria', $markup);
  398. that._markup = $markup;
  399. that._header = $header;
  400. that._isVisible = true;
  401. posEvents = 'orientationchange resize';
  402. that._markupReady($markup);
  403. event('onMarkupReady', [$markup]);
  404. // Show
  405. if (isModal) {
  406. // Enter / ESC
  407. $(window).on('keydown', onWndKeyDown);
  408. // Prevent scroll if not specified otherwise
  409. if (s.scrollLock) {
  410. $markup.on('touchmove mousewheel wheel', function (ev) {
  411. if (scrollLock) {
  412. ev.preventDefault();
  413. }
  414. });
  415. }
  416. // Disable inputs to prevent bleed through (Android bug)
  417. if (pr !== 'Moz') {
  418. $('input,select,button', $ctx).each(function () {
  419. if (!this.disabled) {
  420. $(this).addClass('dwtd').prop('disabled', true);
  421. }
  422. });
  423. }
  424. posEvents += ' scroll';
  425. ms.activeInstance = that;
  426. $markup.appendTo($ctx);
  427. if (has3d && doAnim && !prevAnim) {
  428. $markup.addClass('dw-in dw-trans').on(animEnd, function () {
  429. $markup.off(animEnd).removeClass('dw-in dw-trans').find('.dw').removeClass('dw-' + doAnim);
  430. onShow(prevFocus);
  431. }).find('.dw').addClass('dw-' + doAnim);
  432. }
  433. } else if ($elm.is('div') && !that._hasContent) {
  434. $elm.html($markup);
  435. } else {
  436. $markup.insertAfter($elm);
  437. }
  438. event('onMarkupInserted', [$markup]);
  439. // Set position
  440. that.position();
  441. $wnd
  442. .on(posEvents, onPosition)
  443. .on('focusin', onFocus);
  444. // Events
  445. $markup
  446. .on('selectstart mousedown', prevdef) // Prevents blue highlight on Android and text selection in IE
  447. .on('click', '.dwb-e', prevdef)
  448. .on('keydown', '.dwb-e', function (ev) {
  449. if (ev.keyCode == 32) { // Space
  450. ev.preventDefault();
  451. ev.stopPropagation();
  452. $(this).click();
  453. }
  454. })
  455. .on('keydown', function (ev) { // Trap focus inside modal
  456. if (ev.keyCode == 32) { // Space
  457. ev.preventDefault();
  458. } else if (ev.keyCode == 9) { // Tab
  459. var $focusable = $markup.find('[tabindex="0"]').filter(function () {
  460. return this.offsetWidth > 0 || this.offsetHeight > 0;
  461. }),
  462. index = $focusable.index($(':focus', $markup)),
  463. i = $focusable.length - 1,
  464. target = 0;
  465. if (ev.shiftKey) {
  466. i = 0;
  467. target = -1;
  468. }
  469. if (index === i) {
  470. $focusable.eq(target).focus();
  471. ev.preventDefault();
  472. }
  473. }
  474. });
  475. $('input', $markup).on('selectstart mousedown', function (ev) {
  476. ev.stopPropagation();
  477. });
  478. setTimeout(function () {
  479. // Init buttons
  480. $.each(buttons, function (i, b) {
  481. that.tap($('.dwb' + i, $markup), function (ev) {
  482. b = isString(b) ? that.buttons[b] : b;
  483. b.handler.call(this, ev, that);
  484. }, true);
  485. });
  486. if (s.closeOnOverlay) {
  487. that.tap($overlay, function () {
  488. that.cancel();
  489. });
  490. }
  491. if (isModal && !doAnim) {
  492. onShow(prevFocus);
  493. }
  494. $markup
  495. .on('touchstart mousedown', '.dwb-e', onBtnStart)
  496. .on('touchend', '.dwb-e', onBtnEnd);
  497. that._attachEvents($markup);
  498. }, 300);
  499. event('onShow', [$markup, that._tempValue]);
  500. };
  501. /**
  502. * Hides the scroller instance.
  503. */
  504. that.hide = function (prevAnim, btn, force) {
  505. // If onClose handler returns false, prevent hide
  506. if (!that._isVisible || (!force && !that._isValid && btn == 'set') || (!force && event('onClose', [that._tempValue, btn]) === false)) {
  507. return false;
  508. }
  509. // Hide wheels and overlay
  510. if ($markup) {
  511. // Re-enable temporary disabled fields
  512. if (pr !== 'Moz') {
  513. $('.dwtd', $ctx).each(function () {
  514. $(this).prop('disabled', false).removeClass('dwtd');
  515. });
  516. }
  517. if (has3d && isModal && doAnim && !prevAnim && !$markup.hasClass('dw-trans')) { // If dw-trans class was not removed, means that there was no animation
  518. $markup.addClass('dw-out dw-trans').find('.dw').addClass('dw-' + doAnim).on(animEnd, function () {
  519. onHide(prevAnim);
  520. });
  521. } else {
  522. onHide(prevAnim);
  523. }
  524. // Stop positioning on window resize
  525. $wnd
  526. .off(posEvents, onPosition)
  527. .off('focusin', onFocus);
  528. }
  529. if (isModal) {
  530. $(window).off('keydown', onWndKeyDown);
  531. delete ms.activeInstance;
  532. }
  533. };
  534. that.ariaMessage = function (txt) {
  535. $ariaDiv.html('');
  536. setTimeout(function () {
  537. $ariaDiv.html(txt);
  538. }, 100);
  539. };
  540. /**
  541. * Return true if the scroller is currently visible.
  542. */
  543. that.isVisible = function () {
  544. return that._isVisible;
  545. };
  546. // Protected functions to override
  547. that.setVal = empty;
  548. that._generateContent = empty;
  549. that._attachEvents = empty;
  550. that._readValue = empty;
  551. that._fillValue = empty;
  552. that._markupReady = empty;
  553. that._processSettings = empty;
  554. that._presetLoad = function (s) {
  555. // Add default buttons
  556. s.buttons = s.buttons || (s.display !== 'inline' ? ['set', 'cancel'] : []);
  557. // Hide header text in inline mode by default
  558. s.headerText = s.headerText === undefined ? (s.display !== 'inline' ? '{value}' : false) : s.headerText;
  559. };
  560. // Generic frame functions
  561. /**
  562. * Attach tap event to the given element.
  563. */
  564. that.tap = function (el, handler, prevent) {
  565. var startX,
  566. startY,
  567. moved;
  568. if (s.tap) {
  569. el.on('touchstart.dw', function (ev) {
  570. // Can't always call preventDefault here, it kills page scroll
  571. if (prevent) {
  572. ev.preventDefault();
  573. }
  574. startX = getCoord(ev, 'X');
  575. startY = getCoord(ev, 'Y');
  576. moved = false;
  577. }).on('touchmove.dw', function (ev) {
  578. // If movement is more than 20px, don't fire the click event handler
  579. if (Math.abs(getCoord(ev, 'X') - startX) > 20 || Math.abs(getCoord(ev, 'Y') - startY) > 20) {
  580. moved = true;
  581. }
  582. }).on('touchend.dw', function (ev) {
  583. var that = this;
  584. if (!moved) {
  585. // preventDefault and setTimeout are needed by iOS
  586. ev.preventDefault();
  587. //setTimeout(function () {
  588. handler.call(that, ev);
  589. //}, isOldAndroid ? 400 : 10);
  590. }
  591. // Prevent click events to happen
  592. ms.tapped = true;
  593. setTimeout(function () {
  594. ms.tapped = false;
  595. }, 500);
  596. });
  597. }
  598. el.on('click.dw', function (ev) {
  599. if (!ms.tapped) {
  600. // If handler was not called on touchend, call it on click;
  601. handler.call(this, ev);
  602. }
  603. ev.preventDefault();
  604. });
  605. };
  606. /**
  607. * Destroys the mobiscroll instance.
  608. */
  609. that.destroy = function () {
  610. // Force hide without animation
  611. that.hide(true, false, true);
  612. // Remove all events from elements
  613. $.each(elmList, function (i, v) {
  614. v.el.off('.dw').prop('readonly', v.readOnly);
  615. });
  616. that._destroy();
  617. };
  618. /**
  619. * Scroller initialization.
  620. */
  621. that.init = function (ss) {
  622. that._init(ss);
  623. that._isLiquid = (s.layout || (/top|bottom/.test(s.display) ? 'liquid' : '')) === 'liquid';
  624. that._processSettings();
  625. // Unbind all events (if re-init)
  626. $elm.off('.dw');
  627. doAnim = isOldAndroid ? false : s.animate;
  628. buttons = s.buttons || [];
  629. isModal = s.display !== 'inline';
  630. setReadOnly = s.showOnFocus || s.showOnTap;
  631. $wnd = $(s.context == 'body' ? window : s.context);
  632. $ctx = $(s.context);
  633. that.context = $wnd;
  634. that.live = true;
  635. // If no set button is found, live mode is activated
  636. $.each(buttons, function (i, b) {
  637. if (b == 'ok' || b == 'set' || b.handler == 'set') {
  638. that.live = false;
  639. return false;
  640. }
  641. });
  642. that.buttons.set = { text: s.setText, handler: 'set' };
  643. that.buttons.cancel = { text: (that.live) ? s.closeText : s.cancelText, handler: 'cancel' };
  644. that.buttons.clear = { text: s.clearText, handler: 'clear' };
  645. that._isInput = $elm.is('input');
  646. hasButtons = buttons.length > 0;
  647. if (that._isVisible) {
  648. that.hide(true, false, true);
  649. }
  650. event('onInit', []);
  651. if (isModal) {
  652. that._readValue();
  653. if (!that._hasContent) {
  654. that.attachShow($elm);
  655. }
  656. } else {
  657. that.show();
  658. }
  659. $elm.on('change.dw', function () {
  660. if (!that._preventChange) {
  661. that.setVal($elm.val(), true, false);
  662. }
  663. that._preventChange = false;
  664. });
  665. };
  666. that.buttons = {};
  667. that.handlers = {
  668. set: that.select,
  669. cancel: that.cancel,
  670. clear: that.clear
  671. };
  672. that._value = null;
  673. that._isValid = true;
  674. that._isVisible = false;
  675. // Constructor
  676. s = that.settings;
  677. event = that.trigger;
  678. if (!inherit) {
  679. that.init(settings);
  680. }
  681. };
  682. ms.classes.Frame.prototype._defaults = {
  683. // Localization
  684. lang: 'en',
  685. setText: 'Set',
  686. selectedText: 'Selected',
  687. closeText: 'Close',
  688. cancelText: 'Cancel',
  689. clearText: 'Clear',
  690. // Options
  691. disabled: false,
  692. closeOnOverlay: true,
  693. showOnFocus: false,
  694. showOnTap: true,
  695. display: 'modal',
  696. scrollLock: true,
  697. tap: true,
  698. btnClass: 'dwb',
  699. btnWidth: true,
  700. focusOnClose: !isIOS8 // Temporary for iOS8
  701. };
  702. ms.themes.frame.mobiscroll = {
  703. rows: 5,
  704. showLabel: false,
  705. headerText: false,
  706. btnWidth: false,
  707. selectedLineHeight: true,
  708. selectedLineBorder: 1,
  709. dateOrder: 'MMddyy',
  710. weekDays: 'min',
  711. checkIcon: 'ion-ios7-checkmark-empty',
  712. btnPlusClass: 'mbsc-ic mbsc-ic-arrow-down5',
  713. btnMinusClass: 'mbsc-ic mbsc-ic-arrow-up5',
  714. btnCalPrevClass: 'mbsc-ic mbsc-ic-arrow-left5',
  715. btnCalNextClass: 'mbsc-ic mbsc-ic-arrow-right5'
  716. };
  717. // Prevent re-show on window focus
  718. $(window).on('focus', function () {
  719. if ($activeElm) {
  720. preventShow = true;
  721. }
  722. });
  723. // Prevent standard behaviour on body click
  724. $(document).on('mouseover mouseup mousedown click', function (ev) {
  725. if (ms.tapped) {
  726. ev.stopPropagation();
  727. ev.preventDefault();
  728. return false;
  729. }
  730. });
  731. })(jQuery, window, document);