summaryrefslogtreecommitdiffstats
path: root/js/foundation/foundation.slider.js
blob: 01c7e5b9c2ad0813fcbb88d0f44b664386296f4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
;
(function ($, window, document, undefined) {
    'use strict';

    Foundation.libs.slider = {
        name: 'slider',

        version: '5.5.0',

        settings: {
            start: 0,
            end: 100,
            step: 1,
            precision: null,
            initial: null,
            display_selector: '',
            vertical: false,
            trigger_input_change: false,
            on_change: function () {
            }
        },

        cache: {},

        init: function (scope, method, options) {
            Foundation.inherit(this, 'throttle');
            this.bindings(method, options);
            this.reflow();
        },

        events: function () {
            var self = this;

            $(this.scope)
                .off('.slider')
                .on('mousedown.fndtn.slider touchstart.fndtn.slider pointerdown.fndtn.slider',
                '[' + self.attr_name() + ']:not(.disabled, [disabled]) .range-slider-handle', function (e) {
                    if (!self.cache.active) {
                        e.preventDefault();
                        self.set_active_slider($(e.target));
                    }
                })
                .on('mousemove.fndtn.slider touchmove.fndtn.slider pointermove.fndtn.slider', function (e) {
                    if (!!self.cache.active) {
                        e.preventDefault();
                        if ($.data(self.cache.active[0], 'settings').vertical) {
                            var scroll_offset = 0;
                            if (!e.pageY) {
                                scroll_offset = window.scrollY;
                            }
                            self.calculate_position(self.cache.active, self.get_cursor_position(e, 'y') + scroll_offset);
                        } else {
                            self.calculate_position(self.cache.active, self.get_cursor_position(e, 'x'));
                        }
                    }
                })
                .on('mouseup.fndtn.slider touchend.fndtn.slider pointerup.fndtn.slider', function (e) {
                    self.remove_active_slider();
                })
                .on('change.fndtn.slider', function (e) {
                    self.settings.on_change();
                });

            self.S(window)
                .on('resize.fndtn.slider', self.throttle(function (e) {
                    self.reflow();
                }, 300));
        },

        get_cursor_position: function (e, xy) {
            var pageXY = 'page' + xy.toUpperCase(),
                clientXY = 'client' + xy.toUpperCase(),
                position;

            if (typeof e[pageXY] !== 'undefined') {
                position = e[pageXY];
            }
            else if (typeof e.originalEvent[clientXY] !== 'undefined') {
                position = e.originalEvent[clientXY];
            }
            else if (e.originalEvent.touches && e.originalEvent.touches[0] && typeof e.originalEvent.touches[0][clientXY] !== 'undefined') {
                position = e.originalEvent.touches[0][clientXY];
            }
            else if (e.currentPoint && typeof e.currentPoint[xy] !== 'undefined') {
                position = e.currentPoint[xy];
            }
            return position;
        },

        set_active_slider: function ($handle) {
            this.cache.active = $handle;
        },

        remove_active_slider: function () {
            this.cache.active = null;
        },

        calculate_position: function ($handle, cursor_x) {
            var self = this,
                settings = $.data($handle[0], 'settings'),
                handle_l = $.data($handle[0], 'handle_l'),
                handle_o = $.data($handle[0], 'handle_o'),
                bar_l = $.data($handle[0], 'bar_l'),
                bar_o = $.data($handle[0], 'bar_o');

            requestAnimationFrame(function () {
                var pct;

                if (Foundation.rtl && !settings.vertical) {
                    pct = self.limit_to(((bar_o + bar_l - cursor_x) / bar_l), 0, 1);
                } else {
                    pct = self.limit_to(((cursor_x - bar_o) / bar_l), 0, 1);
                }

                pct = settings.vertical ? 1 - pct : pct;

                var norm = self.normalized_value(pct, settings.start, settings.end, settings.step, settings.precision);

                self.set_ui($handle, norm);
            });
        },

        set_ui: function ($handle, value) {
            var settings = $.data($handle[0], 'settings'),
                handle_l = $.data($handle[0], 'handle_l'),
                bar_l = $.data($handle[0], 'bar_l'),
                norm_pct = this.normalized_percentage(value, settings.start, settings.end),
                handle_offset = norm_pct * (bar_l - handle_l) - 1,
                progress_bar_length = norm_pct * 100,
                $handle_parent = $handle.parent(),
                $hidden_inputs = $handle.parent().children('input[type=hidden]');

            if (Foundation.rtl && !settings.vertical) {
                handle_offset = -handle_offset;
            }

            handle_offset = settings.vertical ? -handle_offset + bar_l - handle_l + 1 : handle_offset;
            this.set_translate($handle, handle_offset, settings.vertical);

            if (settings.vertical) {
                $handle.siblings('.range-slider-active-segment').css('height', progress_bar_length + '%');
            } else {
                $handle.siblings('.range-slider-active-segment').css('width', progress_bar_length + '%');
            }

            $handle_parent.attr(this.attr_name(), value).trigger('change').trigger('change.fndtn.slider');

            $hidden_inputs.val(value);
            if (settings.trigger_input_change) {
                $hidden_inputs.trigger('change');
            }

            if (!$handle[0].hasAttribute('aria-valuemin')) {
                $handle.attr({
                    'aria-valuemin': settings.start,
                    'aria-valuemax': settings.end
                });
            }
            $handle.attr('aria-valuenow', value);

            if (settings.display_selector != '') {
                $(settings.display_selector).each(function () {
                    if (this.hasOwnProperty('value')) {
                        $(this).val(value);
                    } else {
                        $(this).text(value);
                    }
                });
            }

        },

        normalized_percentage: function (val, start, end) {
            return Math.min(1, (val - start) / (end - start));
        },

        normalized_value: function (val, start, end, step, precision) {
            var range = end - start,
                point = val * range,
                mod = (point - (point % step)) / step,
                rem = point % step,
                round = ( rem >= step * 0.5 ? step : 0);
            return ((mod * step + round) + start).toFixed(precision);
        },

        set_translate: function (ele, offset, vertical) {
            if (vertical) {
                $(ele)
                    .css('-webkit-transform', 'translateY(' + offset + 'px)')
                    .css('-moz-transform', 'translateY(' + offset + 'px)')
                    .css('-ms-transform', 'translateY(' + offset + 'px)')
                    .css('-o-transform', 'translateY(' + offset + 'px)')
                    .css('transform', 'translateY(' + offset + 'px)');
            } else {
                $(ele)
                    .css('-webkit-transform', 'translateX(' + offset + 'px)')
                    .css('-moz-transform', 'translateX(' + offset + 'px)')
                    .css('-ms-transform', 'translateX(' + offset + 'px)')
                    .css('-o-transform', 'translateX(' + offset + 'px)')
                    .css('transform', 'translateX(' + offset + 'px)');
            }
        },

        limit_to: function (val, min, max) {
            return Math.min(Math.max(val, min), max);
        },


        initialize_settings: function (handle) {
            var settings = $.extend({}, this.settings, this.data_options($(handle).parent())),
                decimal_places_match_result;

            if (settings.precision === null) {
                decimal_places_match_result = ('' + settings.step).match(/\.([\d]*)/);
                settings.precision = decimal_places_match_result && decimal_places_match_result[1] ? decimal_places_match_result[1].length : 0;
            }

            if (settings.vertical) {
                $.data(handle, 'bar_o', $(handle).parent().offset().top);
                $.data(handle, 'bar_l', $(handle).parent().outerHeight());
                $.data(handle, 'handle_o', $(handle).offset().top);
                $.data(handle, 'handle_l', $(handle).outerHeight());
            } else {
                $.data(handle, 'bar_o', $(handle).parent().offset().left);
                $.data(handle, 'bar_l', $(handle).parent().outerWidth());
                $.data(handle, 'handle_o', $(handle).offset().left);
                $.data(handle, 'handle_l', $(handle).outerWidth());
            }

            $.data(handle, 'bar', $(handle).parent());
            $.data(handle, 'settings', settings);
        },

        set_initial_position: function ($ele) {
            var settings = $.data($ele.children('.range-slider-handle')[0], 'settings'),
                initial = ((typeof settings.initial == 'number' && !isNaN(settings.initial)) ? settings.initial : Math.floor((settings.end - settings.start) * 0.5 / settings.step) * settings.step + settings.start),
                $handle = $ele.children('.range-slider-handle');
            this.set_ui($handle, initial);
        },

        set_value: function (value) {
            var self = this;
            $('[' + self.attr_name() + ']', this.scope).each(function () {
                $(this).attr(self.attr_name(), value);
            });
            if (!!$(this.scope).attr(self.attr_name())) {
                $(this.scope).attr(self.attr_name(), value);
            }
            self.reflow();
        },

        reflow: function () {
            var self = this;
            self.S('[' + this.attr_name() + ']').each(function () {
                var handle = $(this).children('.range-slider-handle')[0],
                    val = $(this).attr(self.attr_name());
                self.initialize_settings(handle);

                if (val) {
                    self.set_ui($(handle), parseFloat(val));
                } else {
                    self.set_initial_position($(this));
                }
            });
        }
    };

}(jQuery, window, window.document));