Slider.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. 'use strict';
  2. /**
  3. * Licensed Materials - Property of IBM
  4. * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2014, 2017
  5. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  6. */
  7. define(['jquery', 'underscore', '../lib/@waca/core-client/js/core-client/ui/core/View', 'text!./templates/Slider.template', '../lib/@waca/core-client/js/core-client/i18n/Formatter', '../nls/StringResources', 'bootstrap-slider'], function ($, _, BaseView, Template, formatter, resources) {
  8. var View = BaseView.extend({
  9. templateString: Template,
  10. leftTooltip: null,
  11. leftTooltipArrow: null,
  12. leftTooltipInput: null,
  13. rightTooltip: null,
  14. rightTooltipArrow: null,
  15. rightTooltipInput: null,
  16. tooltipPadding: 5,
  17. events: {
  18. 'change .tooltipHandle input': 'onInputChange',
  19. 'keyup .tooltipHandle input': 'onKeyUp',
  20. 'keydown .tooltipHandle input': 'onKeyDown',
  21. 'keypress .tooltipHandle input': 'onKeyPress',
  22. 'mousedown .tooltipHandle input': 'onMouseDownTooltip',
  23. 'focus .tooltipHandle input': 'onInputFocus',
  24. 'blur .tooltipHandle input': 'onInputBlur',
  25. 'keydown div.slider-handle.round': 'onHandleKeyDown'
  26. },
  27. init: function init(options) {
  28. View.inherited('init', this, arguments);
  29. // Enabled by default.
  30. _.defaults(options, {
  31. sliderId: 'slider',
  32. min: 0,
  33. max: 10,
  34. precision: 20,
  35. value: 0,
  36. inverted: false,
  37. enabled: true,
  38. minimized: false,
  39. indeterminate: false,
  40. showMinMax: true,
  41. valueFormatter: this.valueFormatter,
  42. prettyValue: this.prettyValue,
  43. tooltipTemplate: '<input tabindex="-1" type="text" aria-label="' + resources.get('sliderInputLabel') + '"></input>',
  44. style: 'simple'
  45. });
  46. // If there is only one option, display the slider as disabled so it is clear to the user
  47. if (options.min === options.max) {
  48. options.enabled = false;
  49. }
  50. if (options.indeterminate) {
  51. // The slide track needs to be fully visible for indeterminate mode.
  52. options.value = options.max;
  53. options.enabled = false;
  54. options.minimized = true;
  55. }
  56. if (options.minimized) {
  57. options.showMinMax = false;
  58. }
  59. this.options = options;
  60. },
  61. valueFormatter: function valueFormatter(value) {
  62. return value;
  63. },
  64. _getKeyCode: function _getKeyCode(e) {
  65. return e.keyCode || e.which;
  66. },
  67. prettyValue: function prettyValue(value) {
  68. return value;
  69. },
  70. setFocus: function setFocus() {
  71. this.$('.slider-handle').first().focus();
  72. },
  73. render: function render() {
  74. var _this = this;
  75. var callResolve = true;
  76. var isRange = this.options.value instanceof Array;
  77. this.$el.empty();
  78. var sHtml = this.dotTemplate({
  79. min: this.options.min,
  80. max: this.options.max,
  81. value: this.options.value,
  82. showMinMax: this.options.showMinMax,
  83. isRange: isRange,
  84. minimized: this.options.minimized
  85. });
  86. this.$el.attr('role', 'application');
  87. this.$el.attr('aria-label', resources.get('sliderRegionLabel'));
  88. this.$el.html(sHtml);
  89. var sliderContainer = this.$el.find('.slider-container');
  90. sliderContainer.addClass(this.options.style);
  91. var sliderElement = sliderContainer.find('.slider-control');
  92. sliderElement.attr('id', this.options.sliderId);
  93. var slider = sliderElement.bootstrapSlider({
  94. tooltip: 'hide',
  95. value: this.options.value,
  96. min: this.options.min,
  97. max: this.options.max,
  98. step: this.options.step,
  99. precision: this.options.precision
  100. });
  101. this.slider = slider;
  102. // Remove the bootstrap-slider's tooltips. We are using our own.
  103. this.$el.find('.tooltip').remove();
  104. var handles;
  105. var result = void 0;
  106. if (!this.options.minimized) {
  107. slider.on('slide', this.onSlide.bind(this)).on('slideStart', this.onSlideStart.bind(this)).on('slideStop', this.onSlideStop.bind(this));
  108. var tooltips = this.$el.find('.tooltipHandle');
  109. var tooltipInner = tooltips.find('.tooltip-inner');
  110. tooltips.css({
  111. 'position': 'absolute'
  112. });
  113. tooltips.hide();
  114. tooltips.find('.tooltipHandle .tooltip-arrow').css({
  115. 'left': '0',
  116. 'right': '0',
  117. 'padding': '0',
  118. 'margin-left': 'auto',
  119. 'margin-right': 'auto',
  120. 'width': '0',
  121. 'height': '0'
  122. });
  123. this.sliderSelection = this.$el.find('.slider-selection');
  124. this.sliderTrack = this.$el.find('.slider-track');
  125. handles = this.$el.find('.slider-handle');
  126. if (isRange && sliderContainer.hasClass('dual')) {
  127. this.leftLinkLineTop = this.$el.find('.lineSegment.top .linkLine.left');
  128. this.rightLinkLineTop = this.$el.find('.lineSegment.top .linkLine.right');
  129. this.leftLinkLineBottom = this.$el.find('.lineSegment.bottom .linkLine.left');
  130. this.rightLinkLineBottom = this.$el.find('.lineSegment.bottom .linkLine.right');
  131. var handleArrow = $('<div class="angle"></div>');
  132. var handleBox = $('<div class="box"></div>');
  133. handleArrow.appendTo(handles);
  134. handleBox.appendTo(handles);
  135. this.rightHandle = handles.eq(1);
  136. this.leftTooltip = tooltips.eq(0);
  137. this.rightTooltip = tooltips.eq(1);
  138. this.leftTooltipInner = tooltipInner.eq(0);
  139. this.rightTooltipInner = tooltipInner.eq(1);
  140. } else {
  141. this.sliderTrack.append('<div class="dummy"></div>');
  142. this.rightHandle = handles;
  143. this.rightTooltip = tooltips;
  144. this.rightTooltipArrow = this.rightTooltip.find('.tooltip-arrow');
  145. this.rightTooltipInner = tooltipInner;
  146. }
  147. this.updateTooltips();
  148. this.updateFilterRangeInfo();
  149. callResolve = false;
  150. result = new Promise(function (resolve, reject) {
  151. try {
  152. setTimeout(function () {
  153. _this.layout();
  154. if (_this.leftTooltip) {
  155. _this.leftTooltip.fadeIn();
  156. }
  157. _this.rightTooltip.fadeIn();
  158. resolve();
  159. }, 100);
  160. } catch (error) {
  161. reject(error);
  162. }
  163. });
  164. } else {
  165. sliderContainer.addClass('minimized');
  166. if (this.options.indeterminate) {
  167. sliderContainer.addClass('indeterminate');
  168. }
  169. result = Promise.resolve();
  170. }
  171. if (this.options.inverted) {
  172. this.invert();
  173. }
  174. this.setEnabled(this.options.enabled);
  175. this.setSliderAriaLabel(handles);
  176. // TODO: Refactor so that we don't instantiate multiple promises unecessarily (see above).
  177. if (callResolve) {
  178. result = Promise.resolve();
  179. }
  180. return result;
  181. },
  182. setSliderAriaLabel: function setSliderAriaLabel($handles) {
  183. if ($handles && $handles.length > 0) {
  184. var percentValue = $handles.get(0).style.left;
  185. if (percentValue) {
  186. $handles.attr('role', 'slider');
  187. $handles.attr('aria-valuenow', resources.get('a11ySliderHandleLabel', {
  188. 'sliderValue': this.options.prettyValue(this.getValue())
  189. }));
  190. }
  191. }
  192. },
  193. getValue: function getValue() {
  194. return this.options.value;
  195. },
  196. getMin: function getMin() {
  197. return this.options.min;
  198. },
  199. getMax: function getMax() {
  200. return this.options.max;
  201. },
  202. isInverted: function isInverted() {
  203. return this.inverted;
  204. },
  205. invert: function invert() {
  206. this.inverted = !this.inverted;
  207. this.$el.find('.slider-container').toggleClass('invert');
  208. if (this.options.invertedTooltipTemplate) {
  209. this.updateTooltips();
  210. this.updateFilterRangeInfo();
  211. this.layout();
  212. }
  213. },
  214. isCleared: function isCleared() {
  215. if (this._applyFilter) {
  216. return false;
  217. }
  218. var value = this.getValue();
  219. if (value instanceof Array) {
  220. if (this.inverted) {
  221. // An inverted range slider is considered to not be cleared.
  222. return false;
  223. }
  224. return value[0] === this.getMin() && value[1] === this.getMax();
  225. } else if (this.inverted) {
  226. return value === this.getMax();
  227. }
  228. return value === this.getMin();
  229. },
  230. clear: function clear() {
  231. if (this.isInverted()) {
  232. this.invert();
  233. }
  234. var min = this.getMin();
  235. var max = this.getMax();
  236. var value;
  237. if (this.getValue() instanceof Array) {
  238. value = [min, max];
  239. } else if (this.inverted) {
  240. value = min;
  241. } else {
  242. value = max;
  243. }
  244. this.setValue(value);
  245. this.updateFilterRangeInfo();
  246. },
  247. remove: function remove() {
  248. if (this.slider) {
  249. this.slider.bootstrapSlider('destroy');
  250. this.slider.remove();
  251. }
  252. this.slider = null;
  253. View.inherited('remove', this, arguments);
  254. },
  255. updateValue: function updateValue() {
  256. if (this.slider) {
  257. // Update the model.
  258. this.options.value = this.slider.bootstrapSlider('getValue');
  259. }
  260. this.setSliderAriaLabel(this.$el.find('.slider-handle'));
  261. },
  262. updateFilterRangeInfo: function updateFilterRangeInfo() {
  263. var titleInfo = this.$el.parents().find('.titleInfo .rangeInfo');
  264. if (this.options.value instanceof Array && (this.options.min !== this.options.value[0] || this.options.max !== this.options.value[1])) {
  265. if (this.leftTooltipInner) {
  266. var left = this.leftTooltipInner.text();
  267. var right = this.rightTooltipInner.text();
  268. var prettyValue = this.options.prettyValue(this.options.value);
  269. if (this.inverted) {
  270. titleInfo.text(left + prettyValue[0] + ' ' + right + prettyValue[1]);
  271. } else {
  272. titleInfo.text(prettyValue[0] + ' - ' + prettyValue[1]);
  273. }
  274. }
  275. } else {
  276. titleInfo.text('');
  277. }
  278. },
  279. /**
  280. * Set the value of this slider.
  281. * Use setUiOnly parameter to set the UI state without notifying
  282. * listeners of value change.
  283. */
  284. setValue: function setValue(value, preventNotify) {
  285. this.options.value = value;
  286. if (this.slider) {
  287. this.slider.bootstrapSlider('setValue', value);
  288. this.layout();
  289. }
  290. this.triggerOnChange();
  291. if (!preventNotify) {
  292. this.triggerSlideStop();
  293. }
  294. },
  295. setStep: function setStep(step) {
  296. this.options.step = step;
  297. if (this.slider) {
  298. this.slider.bootstrapSlider('setAttribute', 'step', step);
  299. }
  300. },
  301. setMin: function setMin(min) {
  302. this.options.min = min;
  303. if (this.slider) {
  304. this.slider.bootstrapSlider('setAttribute', 'min', min);
  305. }
  306. },
  307. setMax: function setMax(max) {
  308. this.options.max = max;
  309. if (this.slider) {
  310. this.slider.bootstrapSlider('setAttribute', 'max', max);
  311. }
  312. },
  313. setEnabled: function setEnabled(enable) {
  314. if (enable) {
  315. this.slider.bootstrapSlider('enable');
  316. this.$el.find('.slider-container').removeClass('disabled');
  317. } else {
  318. this.slider.bootstrapSlider('disable');
  319. this.$el.find('.slider-container').addClass('disabled');
  320. }
  321. },
  322. onKeyDown: function onKeyDown(oEvent) {
  323. if (oEvent.keyCode === 13) {
  324. //Enter
  325. oEvent.preventDefault();
  326. this.onInputChange(oEvent);
  327. }
  328. },
  329. onKeyUp: function onKeyUp() {},
  330. onKeyPress: function onKeyPress() {
  331. this.layoutTooltips();
  332. },
  333. onMouseDownTooltip: function onMouseDownTooltip(oEvent) {
  334. var selector = $(oEvent.target);
  335. if (!selector.is(':focus')) {
  336. oEvent.preventDefault();
  337. oEvent.stopPropagation();
  338. oEvent.target.select();
  339. }
  340. },
  341. onInputFocus: function onInputFocus(ev) {
  342. $(ev.target).parent().addClass('focus');
  343. ev.preventDefault();
  344. ev.stopPropagation();
  345. },
  346. onInputBlur: function onInputBlur(ev) {
  347. $(ev.target).parent().removeClass('focus');
  348. },
  349. calculateTooltipsWidth: function calculateTooltipsWidth() {
  350. if (this.leftTooltipInput) {
  351. this.leftTooltipWidth = this.calculateTooltipWidth(this.leftTooltipInput);
  352. }
  353. this.rightTooltipWidth = this.calculateTooltipWidth(this.rightTooltipInput);
  354. },
  355. calculateTooltipWidth: function calculateTooltipWidth(input) {
  356. var val = input.val();
  357. var width = 20 + (val.length + 1) * 5;
  358. var maxWidth = Math.floor((this.sliderTrack.width() - this.tooltipPadding) / 1.3);
  359. if (width > maxWidth) {
  360. width = maxWidth;
  361. }
  362. return width;
  363. },
  364. updateTooltipsWidth: function updateTooltipsWidth() {
  365. if (this.leftTooltipInput) {
  366. this.updateTooltipWidth(this.leftTooltip, this.leftTooltipWidth);
  367. }
  368. this.updateTooltipWidth(this.rightTooltip, this.rightTooltipWidth);
  369. },
  370. updateTooltipWidth: function updateTooltipWidth(input, width) {
  371. input.attr('aria-label', input.attr('value'));
  372. input.css({
  373. 'width': width + 'px'
  374. });
  375. },
  376. onInputChange: function onInputChange(oEvent) {
  377. var $target = $(oEvent.currentTarget);
  378. var rval = 0;
  379. var lval = 0;
  380. if ($target.data('input') === 'left') {
  381. lval = formatter.parseDecimal($target.val());
  382. rval = this.rightTooltipInput.data('value') ? this.rightTooltipInput.data('value') : this.rightTooltipInput.val();
  383. } else if ($target.data('input') === 'right') {
  384. if (this.leftTooltipInput) {
  385. lval = this.leftTooltipInput.data('value') ? this.leftTooltipInput.data('value') : this.leftTooltipInput.val();
  386. }
  387. rval = formatter.parseDecimal($target.val());
  388. }
  389. var value;
  390. var prettyValue;
  391. if (this.options.value instanceof Array) {
  392. value = this.validate(lval, rval);
  393. value = this.options.valueFormatter(value);
  394. if (lval !== value[0] || rval !== value[1]) {
  395. prettyValue = this.options.prettyValue(value);
  396. this.leftTooltipInput.data('value', value[0]);
  397. this.leftTooltipInput.val(prettyValue[0]);
  398. this.rightTooltipInput.data('value', value[1]);
  399. this.rightTooltipInput.val(prettyValue[1]);
  400. }
  401. } else {
  402. value = this.validateMax(rval);
  403. value = this.options.valueFormatter(value);
  404. if (rval !== value) {
  405. prettyValue = this.options.prettyValue(value);
  406. this.rightTooltipInput.data('value', value);
  407. this.rightTooltipInput.val(prettyValue);
  408. }
  409. }
  410. // When input value is smaller than min or greater than max, need to apply filter after input.
  411. // Set a flag "_applyFilter" to make isClear function to return false so the filter will be applied.
  412. if (value[0] < this.options.value[0]) {
  413. this._applyFilter = true;
  414. this.setMin(value[0]);
  415. }
  416. if (value[1] > this.options.value[1]) {
  417. this._applyFilter = true;
  418. this.setMax(value[1]);
  419. }
  420. this.setValue(value);
  421. this.updateFilterRangeInfo();
  422. },
  423. updateTooltips: function updateTooltips() {
  424. if (this.options.tooltipTemplate instanceof Array) {
  425. var leftTemplate;
  426. var rightTemplate;
  427. if (this.inverted && this.options.invertedTooltipTemplate) {
  428. leftTemplate = this.options.invertedTooltipTemplate[0];
  429. rightTemplate = this.options.invertedTooltipTemplate[1];
  430. } else {
  431. leftTemplate = this.options.tooltipTemplate[0];
  432. rightTemplate = this.options.tooltipTemplate[1];
  433. }
  434. this.leftTooltipInner.html($(leftTemplate));
  435. this.rightTooltipInner.html($(rightTemplate));
  436. } else {
  437. this.rightTooltipInner.html($(this.options.tooltipTemplate));
  438. }
  439. this.updateInputs();
  440. },
  441. updateInputs: function updateInputs() {
  442. this.rightTooltipInput = this.rightTooltip.find('input');
  443. this.rightTooltipInput.data('input', 'right');
  444. if (this.leftTooltip) {
  445. this.leftTooltipInput = this.leftTooltip.find('input');
  446. this.leftTooltipInput.data('input', 'left');
  447. }
  448. },
  449. layoutValues: function layoutValues() {
  450. // Update the model.
  451. this.updateValue();
  452. var value = this.options.valueFormatter(this.getValue());
  453. var prettyValue = this.options.prettyValue(value);
  454. if (this.leftTooltip) {
  455. this.leftTooltipInput.data('value', value[0]);
  456. this.leftTooltipInput.val(prettyValue[0]);
  457. this.rightTooltipInput.data('value', value[1]);
  458. this.rightTooltipInput.val(prettyValue[1]);
  459. } else {
  460. this.rightTooltipInput.data('value', value);
  461. this.rightTooltipInput.val(prettyValue);
  462. }
  463. },
  464. layout: function layout() {
  465. this.layoutValues();
  466. this.layoutTooltips();
  467. },
  468. layoutTooltips: function layoutTooltips() {
  469. this.calculateTooltipsWidth();
  470. this.calculateRightTooltip();
  471. if (this.leftTooltip) {
  472. this.calculateLeftTooltip();
  473. // Only calculate possible collisions if there are two handles.
  474. this.calculateCollisions();
  475. // Adjust
  476. this.paintLines();
  477. this.layoutTooltip(this.leftTooltip, this.leftTooltipCenter, this.leftTooltipMarginLeft);
  478. }
  479. this.layoutTooltip(this.rightTooltip, this.rightTooltipCenter, this.rightTooltipMarginLeft);
  480. if (this.rightTooltipArrow) {
  481. this.layoutTooltipArrow(this.rightTooltipArrow, this.rightTooltipArrowLeft);
  482. }
  483. this.updateTooltipsWidth();
  484. },
  485. layoutTooltip: function layoutTooltip(tooltip, tooltipLeft, tooltipMarginLeft) {
  486. tooltip.css({
  487. 'left': tooltipLeft,
  488. 'margin-left': tooltipMarginLeft
  489. });
  490. },
  491. layoutTooltipArrow: function layoutTooltipArrow(arrow, left) {
  492. arrow.css({
  493. 'left': left
  494. });
  495. },
  496. paintLines: function paintLines() {
  497. this.leftLinkLineTop.css({
  498. 'left': Math.min(this.leftHandleCenter, this.leftTooltipCenter),
  499. 'width': this.leftHandleCenter - this.leftTooltipCenter
  500. });
  501. this.rightLinkLineTop.css({
  502. 'left': this.rightHandleCenter,
  503. 'width': this.rightTooltipCenter - this.rightHandleCenter
  504. });
  505. this.leftLinkLineBottom.css({
  506. 'left': this.leftHandleCenter
  507. });
  508. this.rightLinkLineBottom.css({
  509. 'left': this.rightHandleCenter
  510. });
  511. },
  512. calculateLeftTooltip: function calculateLeftTooltip() {
  513. var tooltipWidth = this.leftTooltipWidth;
  514. var sliderPosition = Math.floor(this.sliderSelection.position().left);
  515. // Cache the handle position.
  516. this.leftHandleCenter = sliderPosition;
  517. var tooltipLeft = sliderPosition;
  518. tooltipLeft = this.checkLeftBoundaryForLeftTooltip(tooltipLeft, tooltipWidth);
  519. tooltipLeft = this.checkRightBoundary(tooltipLeft, tooltipWidth);
  520. var marginLeft = Math.floor(-(tooltipWidth / 2));
  521. this.leftTooltipCenter = tooltipLeft;
  522. this.leftTooltipMarginLeft = marginLeft;
  523. this.leftTooltipWidth = tooltipWidth;
  524. },
  525. calculateRightTooltip: function calculateRightTooltip() {
  526. var tooltipWidth = this.rightTooltipWidth;
  527. var sliderPosition = Math.floor(this.rightHandle.position().left);
  528. // Cache the handle position.
  529. this.rightHandleCenter = sliderPosition;
  530. var tooltipLeft = sliderPosition;
  531. tooltipLeft = this.checkLeftBoundaryForRightTooltip(tooltipLeft, tooltipWidth);
  532. tooltipLeft = this.checkRightBoundary(tooltipLeft, tooltipWidth);
  533. var marginLeft = Math.floor(-tooltipWidth / 2);
  534. this.rightTooltipCenter = tooltipLeft;
  535. this.rightTooltipMarginLeft = marginLeft;
  536. if (this.rightTooltipArrow) {
  537. this.rightTooltipArrowLeft = (sliderPosition - tooltipLeft) * 2;
  538. }
  539. this.rightTooltipWidth = tooltipWidth;
  540. },
  541. calculateCollisions: function calculateCollisions() {
  542. var padding = this.tooltipPadding;
  543. var leftTooltipRight = this.leftTooltipCenter + this.leftTooltipWidth / 2;
  544. var rightTooltipLeft = this.rightTooltipCenter - this.rightTooltipWidth / 2;
  545. var difference = rightTooltipLeft - leftTooltipRight - padding;
  546. if (difference < 0) {
  547. var halfDifference = Math.floor(difference / 2);
  548. this.leftTooltipCenter += halfDifference;
  549. this.rightTooltipCenter -= halfDifference;
  550. if (this.leftTooltipCenter <= this.tooltipMinLeftForLeftTooltip) {
  551. this.leftTooltipCenter = this.tooltipMinLeftForLeftTooltip;
  552. this.rightTooltipCenter = this.leftTooltipCenter + this.leftTooltipWidth / 2 + padding + this.rightTooltipWidth / 2;
  553. } else {
  554. var rightTooltipRight = this.rightTooltipCenter + this.rightTooltipWidth / 2;
  555. var trackRight = this.sliderTrack.position().left + this.sliderTrack.width() + 15;
  556. difference = rightTooltipRight - trackRight;
  557. if (difference > 0) {
  558. this.rightTooltipCenter = trackRight - this.rightTooltipWidth / 2;
  559. this.leftTooltipCenter = this.rightTooltipCenter - this.rightTooltipWidth / 2 - padding - this.leftTooltipWidth / 2;
  560. }
  561. }
  562. this.rightTooltipCenter = Math.floor(this.rightTooltipCenter);
  563. this.leftTooltipCenter = Math.floor(this.leftTooltipCenter);
  564. }
  565. },
  566. checkLeftBoundaryForLeftTooltip: function checkLeftBoundaryForLeftTooltip(position, tooltipWidth) {
  567. var trackLeft = this.sliderTrack.position().left;
  568. var minLeft = trackLeft + tooltipWidth / 2 - 15;
  569. // Cache the min left.
  570. this.tooltipMinLeftForLeftTooltip = minLeft;
  571. if (position < minLeft) {
  572. position = minLeft;
  573. }
  574. return position;
  575. },
  576. checkLeftBoundaryForRightTooltip: function checkLeftBoundaryForRightTooltip(position, tooltipWidth) {
  577. var trackLeft = this.sliderTrack.position().left;
  578. var minLeft = trackLeft + tooltipWidth / 2 - 15;
  579. if (position < minLeft) {
  580. position = minLeft;
  581. }
  582. return position;
  583. },
  584. checkRightBoundary: function checkRightBoundary(position, tooltipWidth) {
  585. var trackRight = this.sliderTrack.position().left + this.sliderTrack.width();
  586. var maxRight = trackRight - tooltipWidth / 2 + 15;
  587. // Cache the max left.
  588. this.tooltipMaxRight = maxRight;
  589. if (position > maxRight) {
  590. position = maxRight;
  591. }
  592. return position;
  593. },
  594. onSlide: function onSlide() {
  595. this.layout();
  596. this.triggerOnChange();
  597. },
  598. onSlideStart: function onSlideStart() {
  599. this.sliding = true;
  600. },
  601. onSlideStop: function onSlideStop() {
  602. this.sliding = false;
  603. // Update the model.
  604. this.updateValue();
  605. this.updateFilterRangeInfo();
  606. this.layout();
  607. this.triggerOnChange();
  608. this.triggerSlideStop();
  609. },
  610. triggerSlideStop: function triggerSlideStop() {
  611. this.trigger('action:slidestop', {});
  612. },
  613. triggerOnChange: function triggerOnChange() {
  614. this.trigger('action:change', {});
  615. },
  616. validate: function validate(lval, rval) {
  617. lval = this.validateMin(lval);
  618. if (rval !== undefined) {
  619. rval = this.validateMax(rval);
  620. // The left value should always be less than the right value.
  621. if (rval < lval) {
  622. var tempVal = rval;
  623. // Swap the values.
  624. rval = lval;
  625. lval = tempVal;
  626. }
  627. return [lval, rval];
  628. }
  629. return lval;
  630. },
  631. validateMin: function validateMin(val) {
  632. if (isNaN(val)) {
  633. val = this.options.min;
  634. }
  635. return this.validateBoundary(val);
  636. },
  637. validateMax: function validateMax(val) {
  638. if (isNaN(val)) {
  639. val = this.options.max;
  640. }
  641. return this.validateBoundary(val);
  642. },
  643. validateBoundary: function validateBoundary(val) {
  644. if (!this.options.noMinMaxRestriction) {
  645. // Check min bounds.
  646. var minVal = this.options.min;
  647. if (val <= minVal) {
  648. return minVal;
  649. }
  650. // Check max bounds.
  651. var maxVal = this.options.max;
  652. if (val >= maxVal) {
  653. return maxVal;
  654. }
  655. } else if (typeof val !== 'number') {
  656. val = Number(val);
  657. }
  658. return val;
  659. }
  660. });
  661. return View;
  662. });
  663. //# sourceMappingURL=Slider.js.map