angular-awesome-slider.js 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285
  1. (function (angular) {
  2. 'use strict';
  3. angular.module('angularAwesomeSlider', [])
  4. // DIRECTIVE
  5. .directive('slider', [
  6. '$compile', '$templateCache', '$timeout', '$window', 'slider',
  7. function (compile, templateCache, timeout, win, Slider) {
  8. return {
  9. restrict: 'AE',
  10. require: '?ngModel',
  11. scope: {options: '=', ngDisabled: '='},
  12. priority: 1,
  13. link: function (scope, element, attrs, ngModel) {
  14. if (!ngModel) return;
  15. if (!scope.options)
  16. throw new Error('You must provide a value for "options" attribute.');
  17. var injector = angular.injector();
  18. // options as inline variable
  19. if (angular.isString(scope.options)) {
  20. scope.options = angular.toJson(scope.options);
  21. }
  22. scope.mainSliderClass = 'jslider';
  23. scope.mainSliderClass += scope.options.skin ? ' jslider_' + scope.options.skin : ' ';
  24. scope.mainSliderClass += scope.options.vertical ? ' vertical ' : '';
  25. scope.mainSliderClass += scope.options.css ? ' sliderCSS' : '';
  26. scope.mainSliderClass += scope.options.className ? ' ' + scope.options.className : '';
  27. // handle limit labels visibility
  28. scope.options.limits = angular.isDefined(scope.options.limits) ? scope.options.limits : true;
  29. // compile template
  30. element.after(compile(templateCache.get('ng-slider/slider-bar.tmpl.html'))(scope, function (clonedElement, scope) {
  31. scope.tmplElt = clonedElement;
  32. }));
  33. // init
  34. var initialized = false;
  35. var init = function (value) {
  36. scope.from = '' + scope.options.from;
  37. scope.to = '' + scope.options.to;
  38. if (scope.options.calculate && angular.isFunction(scope.options.calculate)) {
  39. scope.from = scope.options.calculate(scope.from);
  40. scope.to = scope.options.calculate(scope.to);
  41. }
  42. var OPTIONS = {
  43. from: !scope.options.round ? parseInt(scope.options.from, 10) : parseFloat(scope.options.from),
  44. to: !scope.options.round ? parseInt(scope.options.to, 10) : parseFloat(scope.options.to),
  45. step: scope.options.step,
  46. smooth: scope.options.smooth,
  47. limits: scope.options.limits,
  48. round: scope.options.round || false,
  49. value: value || ngModel.$viewValue,
  50. dimension: '',
  51. scale: scope.options.scale,
  52. modelLabels: scope.options.modelLabels,
  53. vertical: scope.options.vertical,
  54. css: scope.options.css,
  55. className: scope.options.className,
  56. realtime: scope.options.realtime,
  57. cb: forceApply,
  58. threshold: scope.options.threshold,
  59. heterogeneity: scope.options.heterogeneity
  60. };
  61. OPTIONS.calculate = scope.options.calculate || undefined;
  62. OPTIONS.onstatechange = scope.options.onstatechange || undefined;
  63. // slider
  64. scope.slider = !scope.slider ? slidering(element, scope.tmplElt, OPTIONS) : scope.slider.init(element, scope.tmplElt, OPTIONS);
  65. if (!initialized) {
  66. initListener();
  67. }
  68. // scale
  69. var scaleDiv = scope.tmplElt.find('div')[7];
  70. angular.element(scaleDiv).html(scope.slider.generateScale());
  71. scope.slider.drawScale(scaleDiv);
  72. if (scope.ngDisabled) {
  73. disabler(scope.ngDisabled);
  74. }
  75. initialized = true;
  76. };
  77. function initListener() {
  78. // window resize listener
  79. angular.element(win).bind('resize', function (event) {
  80. scope.slider.onresize();
  81. });
  82. }
  83. // model -> view
  84. ngModel.$render = function () {
  85. //elm.html(ctrl.$viewValue);
  86. var singleValue = false;
  87. if (!ngModel.$viewValue && ngModel.$viewValue !== 0) {
  88. return;
  89. }
  90. if (typeof (ngModel.$viewValue) === 'number') {
  91. ngModel.$viewValue = '' + ngModel.$viewValue;
  92. }
  93. if (!ngModel.$viewValue.split(';')[1]) {
  94. scope.mainSliderClass += ' jslider-single';
  95. } else {
  96. scope.mainSliderClass = scope.mainSliderClass.replace(' jslider-single', '');
  97. }
  98. if (scope.slider) {
  99. var vals = ngModel.$viewValue.split(";");
  100. scope.slider.getPointers()[0].set(vals[0], true);
  101. if (vals[1]) {
  102. scope.slider.getPointers()[1].set(vals[1], true);
  103. //if moving left to right with two pointers
  104. //we need to "finish" moving the first
  105. if (parseInt(vals[1]) > parseInt(vals[0])) {
  106. scope.slider.getPointers()[0].set(vals[0], true);
  107. }
  108. }
  109. }
  110. };
  111. scope.$on('slider-value-update', function (e, msg) {
  112. init(msg.value);
  113. timeout(function () {
  114. scope.slider.redrawPointers();
  115. });
  116. });
  117. // view -> model
  118. var forceApply = function (value, released) {
  119. if (scope.disabled)
  120. return;
  121. scope.$apply(function () {
  122. ngModel.$setViewValue(value);
  123. });
  124. if (scope.options.callback) {
  125. scope.options.callback(value, released);
  126. }
  127. };
  128. // watch options
  129. scope.$watch('options', function (value) {
  130. timeout(function () {
  131. init();
  132. });
  133. }, scope.watchOptions || true);
  134. // disabling
  135. var disabler = function (value) {
  136. scope.disabled = value;
  137. if (scope.slider) {
  138. scope.tmplElt.toggleClass('disabled');
  139. scope.slider.disable(value);
  140. }
  141. };
  142. scope.$watch('ngDisabled', function (value) {
  143. disabler(value);
  144. });
  145. scope.limitValue = function (value) {
  146. if (scope.options.modelLabels) {
  147. if (angular.isFunction(scope.options.modelLabels)) {
  148. return scope.options.modelLabels(value);
  149. }
  150. return scope.options.modelLabels[value] !== undefined ? scope.options.modelLabels[value] : value;
  151. }
  152. return value;
  153. };
  154. var slidering = function (inputElement, element, settings) {
  155. return new Slider(inputElement, element, settings);
  156. };
  157. }
  158. };
  159. }])
  160. .config(function () {
  161. })
  162. .run(function () {
  163. });
  164. })(angular);
  165. ;(function (angular) {
  166. 'use strict';
  167. angular.module('angularAwesomeSlider').constant('sliderConstants', {
  168. SLIDER: {
  169. settings: {
  170. from: 1,
  171. to: 40,
  172. step: 1,
  173. smooth: true,
  174. limits: false,
  175. round: false,
  176. value: "3",
  177. dimension: "",
  178. vertical: false,
  179. calculate: false,
  180. onstatechange: false,
  181. callback: false,
  182. realtime: false
  183. },
  184. className: "jslider",
  185. selector: ".jslider-",
  186. css: {
  187. visible: {visibility: "visible"},
  188. hidden: {visibility: "hidden"}
  189. }
  190. },
  191. EVENTS: {}
  192. });
  193. }(angular));
  194. ;(function (angular) {
  195. 'use strict';
  196. angular.module('angularAwesomeSlider').factory('sliderUtils', ['$window', function (win) {
  197. return {
  198. offset: function (elm) {
  199. // try {return elm.offset();} catch(e) {}
  200. var rawDom = elm[0];
  201. var _x = 0;
  202. var _y = 0;
  203. var body = document.documentElement || document.body;
  204. var scrollX = window.pageXOffset || body.scrollLeft;
  205. var scrollY = window.pageYOffset || body.scrollTop;
  206. _x = rawDom.getBoundingClientRect().left + scrollX;
  207. _y = rawDom.getBoundingClientRect().top + scrollY;
  208. return {left: _x, top: _y};
  209. },
  210. browser: function () {
  211. // TODO finish browser detection and this case
  212. var userAgent = win.navigator.userAgent;
  213. var browsers = {
  214. mozilla: /mozilla/i,
  215. chrome: /chrome/i,
  216. safari: /safari/i,
  217. firefox: /firefox/i,
  218. ie: /internet explorer/i
  219. };
  220. for (var key in browsers) {
  221. if (browsers[key].test(userAgent)) {
  222. return key;
  223. }
  224. }
  225. return 'unknown';
  226. }
  227. };
  228. }]);
  229. })(angular);
  230. ;(function (angular) {
  231. 'use strict';
  232. angular.module('angularAwesomeSlider').factory('sliderDraggable', ['sliderUtils', function (utils) {
  233. function Draggable() {
  234. this._init.apply(this, arguments);
  235. }
  236. Draggable.prototype.oninit = function () {
  237. };
  238. Draggable.prototype.events = function () {
  239. };
  240. Draggable.prototype.onmousedown = function () {
  241. this.ptr.css({position: 'absolute'});
  242. };
  243. Draggable.prototype.onmousemove = function (evt, x, y) {
  244. this.ptr.css({left: x, top: y});
  245. };
  246. Draggable.prototype.onmouseup = function () {
  247. };
  248. Draggable.prototype.isDefault = {
  249. drag: false,
  250. clicked: false,
  251. toclick: true,
  252. mouseup: false
  253. };
  254. Draggable.prototype._init = function () {
  255. if (arguments.length > 0) {
  256. this.ptr = arguments[0];
  257. this.label = arguments[3];
  258. this.parent = arguments[2];
  259. if (!this.ptr)
  260. return;
  261. //this.outer = $(".draggable-outer");
  262. this.is = {};
  263. angular.extend(this.is, this.isDefault);
  264. var offset = utils.offset(this.ptr);
  265. this.d = {
  266. left: offset.left,
  267. top: offset.top,
  268. width: this.ptr[0].clientWidth,
  269. height: this.ptr[0].clientHeight
  270. };
  271. this.oninit.apply(this, arguments);
  272. this._events();
  273. }
  274. };
  275. Draggable.prototype._getPageCoords = function (event) {
  276. if (event.targetTouches && event.targetTouches[0]) {
  277. return {x: event.targetTouches[0].pageX, y: event.targetTouches[0].pageY};
  278. } else
  279. return {x: event.pageX, y: event.pageY};
  280. };
  281. Draggable.prototype._bindEvent = function (ptr, eventType, handler) {
  282. var self = this;
  283. // PS need to bind to touch and non-touch events for devices which support both
  284. if (this.supportTouches_) {
  285. ptr[0].addEventListener(this.events_[eventType].touch, handler, false);
  286. }
  287. ptr.bind(this.events_[eventType].nonTouch, handler);
  288. };
  289. Draggable.prototype._events = function () {
  290. var self = this;
  291. this.supportTouches_ = 'ontouchend' in document;
  292. this.events_ = {
  293. 'click': {touch: 'touchstart', nonTouch: 'click'},
  294. 'down': {touch: 'touchstart', nonTouch: 'mousedown'},
  295. 'move': {touch: 'touchmove', nonTouch: 'mousemove'},
  296. 'up': {touch: 'touchend', nonTouch: 'mouseup'},
  297. 'mousedown': {touch: 'mousedown', nonTouch: 'mousedown'}
  298. };
  299. var documentElt = angular.element(window.document);
  300. this._bindEvent(documentElt, 'move', function (event) {
  301. if (self.is.drag) {
  302. event.stopPropagation();
  303. event.preventDefault();
  304. if (!self.parent.disabled) {
  305. self._mousemove(event);
  306. }
  307. }
  308. });
  309. this._bindEvent(documentElt, 'down', function (event) {
  310. if (self.is.drag) {
  311. event.stopPropagation();
  312. event.preventDefault();
  313. }
  314. });
  315. this._bindEvent(documentElt, 'up', function (event) {
  316. self._mouseup(event);
  317. });
  318. this._bindEvent(this.label, 'down', function (event) {
  319. self._mousedown(event);
  320. return false;
  321. });
  322. this._bindEvent(this.label, 'up', function (event) {
  323. self._mouseup(event);
  324. });
  325. this._bindEvent(this.ptr, 'down', function (event) {
  326. self._mousedown(event);
  327. return false;
  328. });
  329. this._bindEvent(this.ptr, 'up', function (event) {
  330. self._mouseup(event);
  331. });
  332. // TODO see if needed
  333. this.events();
  334. };
  335. Draggable.prototype._mousedown = function (evt) {
  336. this.is.drag = true;
  337. this.is.clicked = false;
  338. this.is.mouseup = false;
  339. var coords = this._getPageCoords(evt);
  340. this.cx = coords.x - this.ptr[0].offsetLeft;
  341. this.cy = coords.y - this.ptr[0].offsetTop;
  342. angular.extend(this.d, {
  343. left: coords.x,
  344. top: coords.y,
  345. width: this.ptr[0].clientWidth,
  346. height: this.ptr[0].clientHeight
  347. });
  348. if (this.outer && this.outer.get(0)) {
  349. this.outer.css({height: Math.max(this.outer.height(), $(document.body).height()), overflow: 'hidden'});
  350. }
  351. this.onmousedown(evt);
  352. };
  353. Draggable.prototype._mousemove = function (evt) {
  354. this.is.toclick = false;
  355. var coords = this._getPageCoords(evt);
  356. this.onmousemove(evt, coords.x - this.cx, coords.y - this.cy);
  357. };
  358. Draggable.prototype._mouseup = function (evt) {
  359. var oThis = this;
  360. if (this.is.drag) {
  361. this.is.drag = false;
  362. var browser = utils.browser();
  363. if (this.outer && this.outer.get(0)) {
  364. if (browser === 'mozilla') {
  365. this.outer.css({overflow: "hidden"});
  366. } else {
  367. this.outer.css({overflow: "visible"});
  368. }
  369. // TODO finish browser detection and this case, remove following line
  370. this.outer.css({height: "auto"});
  371. // if( browser === 'ie' && $.browser.version == '6.0' ){
  372. // this.outer.css({ height: "100%" });
  373. // } else {
  374. // this.outer.css({ height: "auto" });
  375. // }
  376. }
  377. this.onmouseup(evt);
  378. }
  379. };
  380. return Draggable;
  381. }]);
  382. }(angular));
  383. ;(function (angular) {
  384. 'use strict';
  385. angular.module('angularAwesomeSlider').factory('sliderPointer', ['sliderDraggable', 'sliderUtils', function (Draggable, utils) {
  386. function SliderPointer() {
  387. Draggable.apply(this, arguments);
  388. }
  389. SliderPointer.prototype = new Draggable();
  390. SliderPointer.prototype.oninit = function (ptr, id, vertical, label, _constructor) {
  391. this.uid = id;
  392. this.parent = _constructor;
  393. this.value = {};
  394. this.vertical = vertical;
  395. this.settings = angular.copy(_constructor.settings);
  396. this.threshold = this.settings.threshold;
  397. };
  398. SliderPointer.prototype.onmousedown = function (evt) {
  399. var off = utils.offset(this.parent.domNode);
  400. var offset = {
  401. left: off.left,
  402. top: off.top,
  403. width: this.parent.domNode[0].clientWidth,
  404. height: this.parent.domNode[0].clientHeight
  405. };
  406. this._parent = {
  407. offset: offset,
  408. width: offset.width,
  409. height: offset.height
  410. };
  411. this.ptr.addClass('jslider-pointer-hover');
  412. };
  413. SliderPointer.prototype.onmousemove = function (evt, x, y) {
  414. var coords = this._getPageCoords(evt);
  415. this._set(!this.vertical ? this.calc(coords.x) : this.calc(coords.y));
  416. if (this.settings.realtime && this.settings.cb && angular.isFunction(this.settings.cb))
  417. this.settings.cb.call(this.parent, this.parent.getValue(), !this.is.drag);
  418. };
  419. SliderPointer.prototype.onmouseup = function (evt) {
  420. if (this.settings.cb && angular.isFunction(this.settings.cb))
  421. this.settings.cb.call(this.parent, this.parent.getValue(), !this.is.drag);
  422. if (!this.is.drag)
  423. this.ptr.removeClass('jslider-pointer-hover');
  424. };
  425. SliderPointer.prototype.limits = function (x) {
  426. return this.parent.limits(x, this);
  427. };
  428. SliderPointer.prototype.calc = function (coords) {
  429. return !this.vertical ?
  430. this.limits(((coords - this._parent.offset.left) * 100) / this._parent.width)
  431. :
  432. this.limits(((coords - this._parent.offset.top) * 100) / this._parent.height);
  433. };
  434. SliderPointer.prototype.set = function (value, opt_origin) {
  435. this.value.origin = this.parent.round(value);
  436. this._set(this.parent.valueToPrc(value, this), opt_origin);
  437. };
  438. SliderPointer.prototype._set = function (prc, opt_origin) {
  439. this.allowed = true;
  440. var oldOrigin = this.value.origin;
  441. var oldPerc = this.value.prc;
  442. this.value.origin = this.parent.prcToValue(prc);
  443. this.value.prc = prc;
  444. // check threshold
  445. if (this.threshold && this.parent.o.pointers[1]) {
  446. var v1 = this.value.origin,
  447. v2 = this.parent.o.pointers[this.uid === 0 ? 1 : 0].value.origin;
  448. this.allowed = Math.abs(v2 - v1) >= this.threshold;
  449. if (!this.allowed && oldOrigin !== undefined && oldPerc !== undefined) {
  450. this.value.origin = oldOrigin;
  451. this.value.prc = oldPerc;
  452. }
  453. }
  454. if (!this.vertical)
  455. this.ptr.css({left: this.value.prc + '%'});
  456. else
  457. this.ptr.css({top: this.value.prc + '%', marginTop: -5});
  458. this.parent.redraw(this);
  459. };
  460. return SliderPointer;
  461. }]);
  462. }(angular));
  463. ;(function (angular) {
  464. 'use strict';
  465. angular.module('angularAwesomeSlider').factory('slider', ['sliderPointer', 'sliderConstants', 'sliderUtils', function (SliderPointer, sliderConstants, utils) {
  466. function Slider() {
  467. return this.init.apply(this, arguments);
  468. }
  469. Slider.prototype.init = function (inputNode, templateNode, settings) {
  470. this.settings = settings;
  471. this.inputNode = inputNode;
  472. this.inputNode.addClass('ng-hide');
  473. this.settings.interval = this.settings.to - this.settings.from;
  474. if (this.settings.calculate && angular.isFunction(this.settings.calculate)) {
  475. this.nice = this.settings.calculate;
  476. }
  477. if (this.settings.onstatechange && angular.isFunction(this.settings.onstatechange)) {
  478. this.onstatechange = this.settings.onstatechange;
  479. }
  480. this.css = sliderConstants.SLIDER.css;
  481. this.is = {init: false};
  482. this.o = {};
  483. this.initValue = {};
  484. this.isAsc = settings.from < settings.to;
  485. this.create(templateNode);
  486. return this;
  487. };
  488. Slider.prototype.create = function (templateNode) {
  489. // set skin class
  490. // if( this.settings.skin && this.settings.skin.length > 0 )
  491. // this.setSkin( this.settings.skin );
  492. var self = this;
  493. this.domNode = templateNode;
  494. var divs = this.domNode.find('div'),
  495. is = this.domNode.find('i'),
  496. angElt = angular.element,
  497. angExt = angular.extend,
  498. angForEach = angular.forEach,
  499. pointer1 = angElt(divs[1]),
  500. pointer2 = angElt(divs[2]),
  501. pointerLabel1 = angElt(divs[5]),
  502. pointerLabel2 = angElt(divs[6]),
  503. indicatorLeft = angElt(is[0]),
  504. indicatorRight = angElt(is[1]),
  505. range = angElt(is[2]),
  506. indicator1 = angElt(is[3]),
  507. indicator2 = angElt(is[4]),
  508. indicator3 = angElt(is[5]),
  509. indicator4 = angElt(is[6]),
  510. labels = [pointerLabel1, pointerLabel2],
  511. pointers = [pointer1, pointer2],
  512. off = utils.offset(this.domNode),
  513. offset = {
  514. left: off.left,
  515. top: off.top,
  516. width: this.domNode[0].clientWidth,
  517. height: this.domNode[0].clientHeight
  518. },
  519. values = self.settings.value.split(';');
  520. this.sizes = {
  521. domWidth: this.domNode[0].clientWidth,
  522. domHeight: this.domNode[0].clientHeight,
  523. domOffset: offset
  524. };
  525. // find some objects
  526. angExt(this.o, {
  527. pointers: {},
  528. labels: {0: {o: pointerLabel1}, 1: {o: pointerLabel2}},
  529. limits: {0: angular.element(divs[3]), 1: angular.element(divs[4])},
  530. indicators: {0: indicator1, 1: indicator2, 2: indicator3, 3: indicator4}
  531. });
  532. angExt(this.o.labels[0], {
  533. value: this.o.labels[0].o.find("span")
  534. });
  535. angExt(this.o.labels[1], {
  536. value: this.o.labels[1].o.find("span")
  537. });
  538. // single pointer
  539. this.settings.single = !self.settings.value.split(";")[1];
  540. if (this.settings.single) {
  541. range.addClass('ng-hide');
  542. } else {
  543. range.removeClass('ng-hide');
  544. }
  545. angForEach(pointers, function (pointer, key) {
  546. self.settings = angular.copy(self.settings);
  547. var value = values[key],
  548. prev,
  549. prevValue,
  550. test,
  551. value1,
  552. offset;
  553. if (value) {
  554. self.o.pointers[key] = new SliderPointer(pointer, key, self.settings.vertical, labels[key], self);
  555. prev = values[key - 1];
  556. prevValue = prev ? parseInt(prev, 10) : undefined;
  557. value = self.settings.round ? parseFloat(value) : parseInt(value, 10);
  558. if (prev && self.isAsc ? value < prevValue : value > prevValue) {
  559. value = prev;
  560. }
  561. // limit threshold adjust
  562. /* test = self.isAsc ? value < self.settings.from : value > self.settings.from,
  563. value1 = test ? self.settings.from : value; */
  564. test = self.isAsc ? value > self.settings.to : value < self.settings.to;
  565. value1 = test ? self.settings.to : value;
  566. self.o.pointers[key].set(value1, true);
  567. // reinit position d
  568. offset = utils.offset(self.o.pointers[key].ptr);
  569. self.o.pointers[key].d = {
  570. left: offset.left,
  571. top: offset.top
  572. };
  573. }
  574. });
  575. self.domNode.bind('mousedown', self.clickHandler.apply(self));
  576. this.o.value = angElt(this.domNode.find("i")[2]);
  577. this.is.init = true;
  578. // CSS SKIN
  579. if (this.settings.css) {
  580. indicatorLeft.css(this.settings.css.background ? this.settings.css.background : {});
  581. indicatorRight.css(this.settings.css.background ? this.settings.css.background : {});
  582. if (!this.o.pointers[1]) {
  583. indicator1.css(this.settings.css.before ? this.settings.css.before : {});
  584. indicator4.css(this.settings.css.after ? this.settings.css.after : {});
  585. }
  586. indicator2.css(this.settings.css.default ? this.settings.css.default : {});
  587. indicator3.css(this.settings.css.default ? this.settings.css.default : {});
  588. range.css(this.settings.css.range ? this.settings.css.range : {});
  589. pointer1.css(this.settings.css.pointer ? this.settings.css.pointer : {});
  590. pointer2.css(this.settings.css.pointer ? this.settings.css.pointer : {});
  591. }
  592. this.redrawPointers();
  593. };
  594. Slider.prototype.clickHandler = function () {
  595. var self = this;
  596. // in case of showing/hiding
  597. var resetPtrSize = function (ptr) {
  598. var ptr1 = self.o.pointers[0].ptr,
  599. ptr2 = self.o.pointers[1].ptr,
  600. offset1 = utils.offset(ptr1),
  601. offset2 = utils.offset(ptr2);
  602. self.o.pointers[0].d = {
  603. left: offset1.left,
  604. top: offset1.top,
  605. width: ptr1[0].clientWidth,
  606. height: ptr1[0].clientHeight
  607. };
  608. self.o.pointers[1].d = {
  609. left: offset2.left,
  610. top: offset2.top,
  611. width: ptr2[0].clientWidth,
  612. height: ptr2[0].clientHeight
  613. };
  614. };
  615. return function (evt) {
  616. if (self.disabled)
  617. return;
  618. var vertical = self.settings.vertical,
  619. targetIdx = 0,
  620. _off = utils.offset(self.domNode),
  621. firstPtr = self.o.pointers[0],
  622. secondPtr = self.o.pointers[1] ? self.o.pointers[1] : null,
  623. tmpPtr,
  624. evtPosition = evt.originalEvent ? evt.originalEvent : evt,
  625. mouse = vertical ? evtPosition.pageY : evtPosition.pageX,
  626. css = vertical ? 'top' : 'left',
  627. offset = {
  628. left: _off.left,
  629. top: _off.top,
  630. width: self.domNode[0].clientWidth,
  631. height: self.domNode[0].clientHeight
  632. },
  633. targetPtr = self.o.pointers[targetIdx];
  634. if (secondPtr) {
  635. if (!secondPtr.d.width) {
  636. resetPtrSize();
  637. }
  638. var firstPtrPosition = utils.offset(firstPtr.ptr)[css];
  639. var secondPtrPosition = utils.offset(secondPtr.ptr)[css];
  640. var middleGap = Math.abs((secondPtrPosition - firstPtrPosition) / 2);
  641. var testSecondPtrToMove = mouse >= secondPtrPosition || mouse >= (secondPtrPosition - middleGap);
  642. if (testSecondPtrToMove) {
  643. targetPtr = secondPtr;
  644. }
  645. }
  646. targetPtr._parent = {offset: offset, width: offset.width, height: offset.height};
  647. var coords = firstPtr._getPageCoords(evt);
  648. targetPtr.cx = coords.x - targetPtr.d.left;
  649. targetPtr.cy = coords.y - targetPtr.d.top;
  650. targetPtr.onmousemove(evt, coords.x, coords.y);
  651. targetPtr.onmouseup();
  652. angular.extend(targetPtr.d, {
  653. left: coords.x,
  654. top: coords.y
  655. });
  656. self.redraw(targetPtr);
  657. return false;
  658. };
  659. };
  660. Slider.prototype.disable = function (bool) {
  661. this.disabled = bool;
  662. };
  663. Slider.prototype.nice = function (value) {
  664. return value;
  665. };
  666. Slider.prototype.onstatechange = function () {
  667. };
  668. Slider.prototype.limits = function (x, pointer) {
  669. // smooth
  670. if (!this.settings.smooth) {
  671. var step = this.settings.step * 100 / (this.settings.interval);
  672. x = Math.round(x / step) * step;
  673. }
  674. if (pointer) {
  675. var another = this.o.pointers[1 - pointer.uid];
  676. if (another && pointer.uid && x < another.value.prc) x = another.value.prc;
  677. if (another && !pointer.uid && x > another.value.prc) x = another.value.prc;
  678. }
  679. // base limit
  680. if (x < 0) x = 0;
  681. if (x > 100) x = 100;
  682. return Math.round(x * 10) / 10;
  683. };
  684. Slider.prototype.getPointers = function () {
  685. return this.o.pointers;
  686. };
  687. Slider.prototype.generateScale = function () {
  688. if (this.settings.scale && this.settings.scale.length > 0) {
  689. var str = '',
  690. s = this.settings.scale,
  691. // FIX Big Scale Failure #34
  692. // var prc = Math.round((100/(s.length-1))*10)/10;
  693. prc,
  694. label,
  695. duplicate = {},
  696. position = this.settings.vertical ? 'top' : 'left',
  697. i = 0;
  698. for (; i < s.length; i++) {
  699. if (!angular.isDefined(s[i].val)) {
  700. prc = (100 / (s.length - 1)).toFixed(2);
  701. str += '<span style="' + position + ': ' + i * prc + '%">' + (s[i] != '|' ? '<ins>' + s[i] + '</ins>' : '') + '</span>';
  702. }
  703. if (s[i].val <= this.settings.to && s[i].val >= this.settings.from && !duplicate[s[i].val]) {
  704. duplicate[s[i].val] = true;
  705. prc = this.valueToPrc(s[i].val);
  706. label = s[i].label ? s[i].label : s[i].val;
  707. str += '<span style="' + position + ': ' + prc + '%">' + '<ins>' + label + '</ins>' + '</span>';
  708. }
  709. }
  710. return str;
  711. }
  712. return '';
  713. };
  714. Slider.prototype.onresize = function () {
  715. var self = this;
  716. this.sizes = {
  717. domWidth: this.domNode[0].clientWidth,
  718. domHeight: this.domNode[0].clientHeight,
  719. domOffset: {
  720. left: this.domNode[0].offsetLeft,
  721. top: this.domNode[0].offsetTop,
  722. width: this.domNode[0].clientWidth,
  723. height: this.domNode[0].clientHeight
  724. }
  725. };
  726. this.redrawPointers();
  727. };
  728. Slider.prototype.update = function () {
  729. this.onresize();
  730. this.drawScale();
  731. };
  732. Slider.prototype.drawScale = function (scaleDiv) {
  733. angular.forEach(angular.element(scaleDiv).find('ins'), function (scaleLabel, key) {
  734. scaleLabel.style.marginLeft = -scaleLabel.clientWidth / 2;
  735. });
  736. };
  737. Slider.prototype.redrawPointers = function () {
  738. angular.forEach(this.o.pointers, function (pointer) {
  739. this.redraw(pointer);
  740. }, this);
  741. };
  742. Slider.prototype.redraw = function (pointer) {
  743. if (!this.is.init) {
  744. // this.settings.single
  745. if (this.o.pointers[0] && !this.o.pointers[1]) {
  746. this.originValue = this.o.pointers[0].value.prc;
  747. this.o.indicators[0].css(!this.settings.vertical ? {
  748. left: 0,
  749. width: this.o.pointers[0].value.prc + "%"
  750. } : {top: 0, height: this.o.pointers[0].value.prc + "%"});
  751. this.o.indicators[1].css(!this.settings.vertical ? {left: this.o.pointers[0].value.prc + "%"} : {top: this.o.pointers[0].value.prc + "%"});
  752. this.o.indicators[3].css(!this.settings.vertical ? {left: this.o.pointers[0].value.prc + "%"} : {top: this.o.pointers[0].value.prc + "%"});
  753. } else {
  754. this.o.indicators[2].css(!this.settings.vertical ? {left: this.o.pointers[1].value.prc + "%"} : {top: this.o.pointers[1].value.prc + "%"});
  755. this.o.indicators[0].css(!this.settings.vertical ? {left: 0, width: "0"} : {top: 0, height: "0"});
  756. this.o.indicators[3].css(!this.settings.vertical ? {left: "0", width: "0"} : {
  757. top: "0",
  758. height: "0"
  759. });
  760. }
  761. return false;
  762. }
  763. this.setValue();
  764. var newPos,
  765. newWidth;
  766. // redraw range line
  767. if (this.o.pointers[0] && this.o.pointers[1]) {
  768. newPos = !this.settings.vertical ?
  769. {
  770. left: this.o.pointers[0].value.prc + "%",
  771. width: (this.o.pointers[1].value.prc - this.o.pointers[0].value.prc) + "%"
  772. }
  773. :
  774. {
  775. top: this.o.pointers[0].value.prc + "%",
  776. height: (this.o.pointers[1].value.prc - this.o.pointers[0].value.prc) + "%"
  777. };
  778. this.o.value.css(newPos);
  779. // both pointer overlap on limits
  780. if (this.o.pointers[0].value.prc === this.o.pointers[1].value.prc) {
  781. this.o.pointers[1].ptr.css("z-index", this.o.pointers[0].value.prc === 0 ? '3' : '1');
  782. }
  783. }
  784. if (this.o.pointers[0] && !this.o.pointers[1]) {
  785. newWidth = this.o.pointers[0].value.prc - this.originValue;
  786. if (newWidth >= 0) {
  787. this.o.indicators[3].css(!this.settings.vertical ? {width: newWidth + "%"} : {height: newWidth + "%"});
  788. } else {
  789. this.o.indicators[3].css(!this.settings.vertical ? {width: 0} : {height: 0});
  790. }
  791. if (this.o.pointers[0].value.prc < this.originValue) {
  792. this.o.indicators[0].css(!this.settings.vertical ? {width: this.o.pointers[0].value.prc + "%"} : {height: this.o.pointers[0].value.prc + "%"});
  793. } else {
  794. this.o.indicators[0].css(!this.settings.vertical ? {width: this.originValue + "%"} : {height: this.originValue + "%"});
  795. }
  796. }
  797. var value = this.nice(pointer.value.origin);
  798. if (this.settings.modelLabels) {
  799. if (angular.isFunction(this.settings.modelLabels)) {
  800. value = this.settings.modelLabels(value);
  801. } else {
  802. value = this.settings.modelLabels[value] !== undefined ? this.settings.modelLabels[value] : value;
  803. }
  804. }
  805. this.o.labels[pointer.uid].value.html(value);
  806. // redraw position of labels
  807. this.redrawLabels(pointer);
  808. };
  809. Slider.prototype.redrawLabels = function (pointer) {
  810. function setPosition(label, sizes, prc) {
  811. sizes.margin = -sizes.label / 2;
  812. var domSize = !self.settings.vertical ? self.sizes.domWidth : self.sizes.domHeight;
  813. if (self.sizes.domWidth) {
  814. // left limit
  815. var label_left = sizes.border + sizes.margin;
  816. if (label_left < 0)
  817. sizes.margin -= label_left;
  818. // right limit
  819. if (self.sizes.domWidth > 0 && sizes.border + sizes.label / 2 > domSize) {
  820. sizes.margin = 0;
  821. sizes.right = true;
  822. } else
  823. sizes.right = false;
  824. }
  825. if (!self.settings.vertical)
  826. label.o.css({left: prc + "%", marginLeft: sizes.margin + "px", right: "auto"});
  827. else
  828. label.o.css({top: prc + "%", marginLeft: "20px", marginTop: sizes.margin, bottom: "auto"});
  829. if (sizes.right && self.sizes.domWidth > 0) {
  830. if (!self.settings.vertical)
  831. label.o.css({left: "auto", right: 0});
  832. else
  833. label.o.css({top: "auto", bottom: 0});
  834. }
  835. return sizes;
  836. }
  837. var self = this,
  838. label = this.o.labels[pointer.uid],
  839. prc = pointer.value.prc,
  840. // case hidden
  841. labelWidthSize = label.o[0].offsetWidth === 0 ? (label.o[0].textContent.length) * 7 : label.o[0].offsetWidth;
  842. this.sizes.domWidth = this.domNode[0].clientWidth;
  843. this.sizes.domHeight = this.domNode[0].clientHeight;
  844. var sizes = {
  845. label: !self.settings.vertical ? labelWidthSize : label.o[0].offsetHeight,
  846. right: false,
  847. border: (prc * (!self.settings.vertical ? this.sizes.domWidth : this.sizes.domHeight)) / 100
  848. };
  849. var anotherIdx = pointer.uid === 0 ? 1 : 0,
  850. anotherLabel,
  851. anotherPtr;
  852. if (!this.settings.single && !this.settings.vertical) {
  853. // glue if near;
  854. anotherLabel = this.o.labels[anotherIdx];
  855. anotherPtr = this.o.pointers[anotherIdx];
  856. var label1 = this.o.labels[0],
  857. label2 = this.o.labels[1],
  858. ptr1 = this.o.pointers[0],
  859. ptr2 = this.o.pointers[1],
  860. gapBetweenLabel = ptr2.ptr[0].offsetLeft - ptr1.ptr[0].offsetLeft,
  861. value = this.nice(anotherPtr.value.origin);
  862. label1.o.css(this.css.visible);
  863. label2.o.css(this.css.visible);
  864. value = this.getLabelValue(value);
  865. if (gapBetweenLabel + 10 < label1.o[0].offsetWidth + label2.o[0].offsetWidth) {
  866. anotherLabel.o.css(this.css.hidden);
  867. anotherLabel.value.html(value);
  868. prc = (anotherPtr.value.prc - prc) / 2 + prc;
  869. if (anotherPtr.value.prc != pointer.value.prc) {
  870. value = this.nice(this.o.pointers[0].value.origin);
  871. var value1 = this.nice(this.o.pointers[1].value.origin);
  872. value = this.getLabelValue(value);
  873. value1 = this.getLabelValue(value1);
  874. label.value.html(value + "&nbsp;&ndash;&nbsp;" + value1);
  875. sizes.label = label.o[0].offsetWidth;
  876. sizes.border = (prc * domSize) / 100;
  877. }
  878. } else {
  879. anotherLabel.value.html(value);
  880. anotherLabel.o.css(this.css.visible);
  881. }
  882. }
  883. sizes = setPosition(label, sizes, prc);
  884. var domSize = !self.settings.vertical ? self.sizes.domWidth : self.sizes.domHeight;
  885. /* draw second label */
  886. if (anotherLabel) {
  887. // case hidden
  888. var labelWidthSize2 = label.o[0].offsetWidth === 0 ? (label.o[0].textContent.length / 2) * 7 : label.o[0].offsetWidth,
  889. sizes2 = {
  890. label: !self.settings.vertical ? labelWidthSize2 : anotherLabel.o[0].offsetHeight,
  891. right: false,
  892. border: (anotherPtr.value.prc * this.sizes.domWidth) / 100
  893. };
  894. sizes = setPosition(anotherLabel, sizes2, anotherPtr.value.prc);
  895. }
  896. this.redrawLimits();
  897. };
  898. Slider.prototype.redrawLimits = function () {
  899. if (this.settings.limits) {
  900. var limits = [true, true],
  901. i = 0;
  902. for (var key in this.o.pointers) {
  903. if (!this.settings.single || key === 0) {
  904. var pointer = this.o.pointers[key],
  905. label = this.o.labels[pointer.uid],
  906. label_left = label.o[0].offsetLeft - this.sizes.domOffset.left,
  907. limit = this.o.limits[0];
  908. if (label_left < limit[0].clientWidth) {
  909. limits[0] = false;
  910. }
  911. limit = this.o.limits[1];
  912. if (label_left + label.o[0].clientWidth > this.sizes.domWidth - limit[0].clientWidth) {
  913. limits[1] = false;
  914. }
  915. }
  916. }
  917. for (; i < limits.length; i++) {
  918. if (limits[i]) { // TODO animate
  919. angular.element(this.o.limits[i]).addClass("animate-show");
  920. } else {
  921. angular.element(this.o.limits[i]).addClass("animate-hidde");
  922. }
  923. }
  924. }
  925. };
  926. Slider.prototype.setValue = function () {
  927. var value = this.getValue();
  928. this.inputNode.attr("value", value);
  929. this.onstatechange.call(this, value, this.inputNode);
  930. };
  931. Slider.prototype.getValue = function () {
  932. if (!this.is.init) return false;
  933. var $this = this;
  934. var value = "";
  935. angular.forEach(this.o.pointers, function (pointer, key) {
  936. if (pointer.value.prc !== undefined && !isNaN(pointer.value.prc))
  937. value += (key > 0 ? ";" : "") + $this.prcToValue(pointer.value.prc);
  938. });
  939. return value;
  940. };
  941. Slider.prototype.getLabelValue = function (value) {
  942. if (this.settings.modelLabels) {
  943. if (angular.isFunction(this.settings.modelLabels)) {
  944. return this.settings.modelLabels(value);
  945. } else {
  946. return this.settings.modelLabels[value] !== undefined ? this.settings.modelLabels[value] : value;
  947. }
  948. }
  949. return value;
  950. };
  951. Slider.prototype.getPrcValue = function () {
  952. if (!this.is.init) return false;
  953. var $this = this;
  954. var value = "";
  955. // TODO remove jquery and see if % value is nice feature
  956. /*$.each(this.o.pointers, function(i){
  957. if(this.value.prc !== undefined && !isNaN(this.value.prc)) value += (i > 0 ? ";" : "") + this.value.prc;
  958. });*/
  959. return value;
  960. };
  961. Slider.prototype.prcToValue = function (prc) {
  962. var value;
  963. if (this.settings.heterogeneity && this.settings.heterogeneity.length > 0) {
  964. var h = this.settings.heterogeneity,
  965. _start = 0,
  966. _from = this.settings.round ? parseFloat(this.settings.from) : parseInt(this.settings.from, 10),
  967. _to = this.settings.round ? parseFloat(this.settings.to) : parseInt(this.settings.to, 10),
  968. i = 0;
  969. for (; i <= h.length; i++) {
  970. var v;
  971. if (h[i])
  972. v = h[i].split('/');
  973. else
  974. v = [100, _to];
  975. var v1 = this.settings.round ? parseFloat(v[0]) : parseInt(v[0], 10);
  976. var v2 = this.settings.round ? parseFloat(v[1]) : parseInt(v[1], 10);
  977. if (prc >= _start && prc <= v1) {
  978. value = _from + ((prc - _start) * (v2 - _from)) / (v1 - _start);
  979. }
  980. _start = v1;
  981. _from = v2;
  982. }
  983. } else {
  984. value = this.settings.from + (prc * this.settings.interval) / 100;
  985. }
  986. return this.round(value);
  987. };
  988. Slider.prototype.valueToPrc = function (value, pointer) {
  989. var prc,
  990. _from = this.settings.round ? parseFloat(this.settings.from) : parseInt(this.settings.from, 10);
  991. if (this.settings.heterogeneity && this.settings.heterogeneity.length > 0) {
  992. var h = this.settings.heterogeneity,
  993. _start = 0,
  994. i = 0;
  995. for (; i <= h.length; i++) {
  996. var v;
  997. if (h[i])
  998. v = h[i].split('/');
  999. else
  1000. v = [100, this.settings.to];
  1001. var v1 = this.settings.round ? parseFloat(v[0]) : parseInt(v[0], 10);
  1002. var v2 = this.settings.round ? parseFloat(v[1]) : parseInt(v[1], 10);
  1003. if (value >= _from && value <= v2) {
  1004. if (pointer) {
  1005. prc = pointer.limits(_start + (value - _from) * (v1 - _start) / (v2 - _from));
  1006. } else {
  1007. prc = this.limits(_start + (value - _from) * (v1 - _start) / (v2 - _from));
  1008. }
  1009. }
  1010. _start = v1;
  1011. _from = v2;
  1012. }
  1013. } else {
  1014. if (pointer) {
  1015. prc = pointer.limits((value - _from) * 100 / this.settings.interval);
  1016. } else {
  1017. prc = this.limits((value - _from) * 100 / this.settings.interval);
  1018. }
  1019. }
  1020. return prc;
  1021. };
  1022. Slider.prototype.round = function (value) {
  1023. value = Math.round(value / this.settings.step) * this.settings.step;
  1024. if (this.settings.round)
  1025. value = Math.round(value * Math.pow(10, this.settings.round)) / Math.pow(10, this.settings.round);
  1026. else
  1027. value = Math.round(value);
  1028. return value;
  1029. };
  1030. return Slider;
  1031. }]);
  1032. }(angular));
  1033. ;(function (angular, undefined) {
  1034. 'use strict';
  1035. angular.module('angularAwesomeSlider')
  1036. .run(['$templateCache', function ($templateCache) {
  1037. $templateCache.put('ng-slider/slider-bar.tmpl.html',
  1038. '<span ng-class="mainSliderClass" id="{{sliderTmplId}}">' +
  1039. '<table><tr><td>' +
  1040. '<div class="jslider-bg">' +
  1041. '<i class="left"></i>' +
  1042. '<i class="right"></i>' +
  1043. '<i class="range"></i>' +
  1044. '<i class="before"></i>' +
  1045. '<i class="default"></i>' +
  1046. '<i class="default"></i>' +
  1047. '<i class="after"></i>' +
  1048. '</div>' +
  1049. '<div class="jslider-pointer"></div>' +
  1050. '<div class="jslider-pointer jslider-pointer-to"></div>' +
  1051. '<div class="jslider-label" ng-show="options.limits"><span ng-bind="limitValue(options.from)"></span>{{options.dimension}}</div>' +
  1052. '<div class="jslider-label jslider-label-to" ng-show="options.limits"><span ng-bind="limitValue(options.to)"></span>{{options.dimension}}</div>' +
  1053. '<div class="jslider-value"><span></span>{{options.dimension}}</div>' +
  1054. '<div class="jslider-value jslider-value-to"><span></span>{{options.dimension}}</div>' +
  1055. '<div class="jslider-scale" id="{{sliderScaleDivTmplId}}"></div>' +
  1056. '</td></tr></table>' +
  1057. '</span>');
  1058. }]);
  1059. })(window.angular);