Slider: Popup slider issue has been fixed ( N_SE-36430 )
[platform/framework/web/web-ui-fw.git] / src / js / widgets / jquery.mobile.tizen.slider.js
1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
2 //>>description: Shows slider bar to input number by dragging
3 //>>label: Slider
4 //>>group: Tizen:Widgets
5
6 define( [ '../jquery.mobile.tizen.core' ], function ( ) {
7 //>>excludeEnd("jqmBuildExclude");
8
9 /*
10  * jQuery Mobile Widget @VERSION
11  *
12  * This software is licensed under the MIT licence (as defined by the OSI at
13  * http://www.opensource.org/licenses/mit-license.php)
14  *
15  * ***************************************************************************
16  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
17  * Copyright (c) 2011 by Intel Corporation Ltd.
18  *
19  * Permission is hereby granted, free of charge, to any person obtaining a
20  * copy of this software and associated documentation files (the "Software"),
21  * to deal in the Software without restriction, including without limitation
22  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
23  * and/or sell copies of the Software, and to permit persons to whom the
24  * Software is furnished to do so, subject to the following conditions:
25  *
26  * The above copyright notice and this permission notice shall be included in
27  * all copies or substantial portions of the Software.
28  *
29  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
34  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
35  * DEALINGS IN THE SOFTWARE.
36  * ***************************************************************************
37  *
38  * Authors: Max Waterman <max.waterman@intel.com>
39  * Authors: Minkyu Kang <mk7.kang@samsung.com>
40  */
41
42 /**
43  * tizenslider modifies the JQuery Mobile slider and is created in the same way.
44  *
45  * See the JQuery Mobile slider widget for more information :
46  *     http://jquerymobile.com/demos/1.0a4.1/docs/forms/forms-slider.html
47  *
48  * The JQuery Mobile slider option:
49  *     theme: specify the theme using the 'data-theme' attribute
50  *
51  * Options:
52  *     theme: string; the theme to use if none is specified using the 'data-theme' attribute
53  *            default: 'c'
54  *     popup: boolean; controls whether the popup is displayed or not
55  *                   specify if the popup is enabled using the 'data-popup' attribute
56  *                   set from javascript using .tizenslider('option','popup',newValue)
57  *
58  * Events:
59  *     changed: triggers when the value is changed (rather than when the handle is moved)
60  *
61  * Examples:
62  *
63  *     <a href="#" id="popupEnabler" data-role="button" data-inline="true">Enable popup</a>
64  *     <a href="#" id="popupDisabler" data-role="button" data-inline="true">Disable popup</a>
65  *     <div data-role="fieldcontain">
66  *         <input id="mySlider" data-theme='a' data-popup='false' type="range" name="slider" value="7" min="0" max="9" />
67  *     </div>
68  *     <div data-role="fieldcontain">
69  *         <input id="mySlider2" type="range" name="slider" value="77" min="0" max="777" />
70  *     </div>
71  *
72  *     // disable popup from javascript
73  *     $('#mySlider').tizenslider('option','popup',false);
74  *
75  *     // from buttons
76  *     $('#popupEnabler').bind('vclick', function() {
77  *         $('#mySlider').tizenslider('option','popup',true);
78  *     });
79  *     $('#popupDisabler').bind('vclick', function() {
80  *         $('#mySlider').tizenslider('option','popup',false);
81  *     });
82  */
83
84 /**
85         @class Slider
86         The slider widget shows a control on the screen that you can use to change values by dragging a handle on a horizontal scale. Sliders can be used in Tizen as described in the jQueryMobile documentation for sliders.
87
88         To add a slider widget to the application, use the following code:
89
90                 <input data-popup='false' type="range" name="slider" value="5" min="0" max="10" data-icon="text" data-text-left="Min" data-text-right="Max" />
91
92         The slider can define callbacks for events as described in the jQueryMobile documentation for slider events.
93         You can use methods with the slider as described in the jQueryMobile documentation for slider methods.
94 */
95 /**
96         @property {String} data-icon
97         Defines the icon style for the slider ends. The icon options are bright, volume, and text.
98         The default value is text.
99 */
100 /**
101         @property {Boolean} data-popup
102         Enables or disables a pop-up showing the current value while the handle is dragged.
103         The default value is true.
104 */
105 /**
106         @property {String} data-text-left
107         Defines the text displayed on the left side of the slider.
108         The data-icon option must be set to text.
109 */
110 /**
111         @property {String} data-text-right
112         Defines the text displayed on the right side of the slider.
113         The data-icon option must be set to text.
114 */
115
116 (function ($, window, undefined) {
117         $.widget("tizen.tizenslider", $.mobile.widget, {
118                 options: {
119                         popup: true
120                 },
121
122                 popup: null,
123                 handle: null,
124                 handleText: null,
125
126                 _create: function () {
127                         this.currentValue = null;
128                         this.popupVisible = false;
129
130                         var self = this,
131                                 inputElement = $( this.element ),
132                                 slider,
133                                 handle_press,
134                                 popupEnabledAttr,
135                                 icon,
136                                 text_right,
137                                 text_left,
138                                 text_length,
139                                 elem_left,
140                                 elem_right,
141                                 margin_left,
142                                 margin_right;
143
144                         // apply jqm slider
145                         inputElement.slider();
146
147                         // hide the slider input element proper
148                         inputElement.hide();
149
150                         self.popup = $('<div class="ui-slider-popup"></div>');
151
152                         // set the popup according to the html attribute
153                         popupEnabledAttr = inputElement.jqmData('popup');
154                         if ( popupEnabledAttr !== undefined ) {
155                                 self.options.popup = ( popupEnabledAttr == true );
156                         }
157
158                         // get the actual slider added by jqm
159                         slider = inputElement.next('.ui-slider');
160
161                         icon = inputElement.attr('data-icon');
162
163                         // wrap the background
164                         slider.wrap('<div class="ui-slider-container"></div>');
165
166                         // get the handle
167                         self.handle = slider.find('.ui-slider-handle');
168
169                         // remove the rounded corners from the slider and its children
170                         slider.removeClass('ui-btn-corner-all');
171                         slider.find('*').removeClass('ui-btn-corner-all');
172
173                         // add icon
174                         switch ( icon ) {
175                         case 'bright':
176                         case 'volume':
177                                 elem_left = $('<div class="ui-slider-left-' + icon + '"></div>');
178                                 elem_right = $('<div class="ui-slider-right-' + icon + '"></div>');
179
180                                 slider.before( elem_left );
181                                 slider.after( elem_right );
182
183                                 margin_left = elem_left.width() + 16;
184                                 margin_right = elem_right.width() + 16;
185                                 break;
186
187                         case 'text':
188                                 text_left = ( inputElement.attr('data-text-left') === undefined ) ? '' :
189                                                 inputElement.attr('data-text-left').substring( 0, 3 );
190                                 text_right = ( inputElement.attr('data-text-right') === undefined ) ? '' :
191                                                 inputElement.attr('data-text-right').substring( 0, 3 );
192
193                                 text_length = Math.max( text_left.length, text_right.length ) + 1;
194
195                                 margin_left = text_length + "rem";
196                                 margin_right = text_length + "rem";
197
198                                 elem_left = $('<div class="ui-slider-left-text" style="left:' +
199                                         -( text_length ) + 'rem; width:' + text_length + 'rem;">' +
200                                         '<span style="position:relative;top:0.4em;">' +
201                                         text_left +
202                                         '</span></div>');
203                                 elem_right = $('<div class="ui-slider-right-text" style="right:' +
204                                         -( text_length ) + 'rem; width:' + text_length + 'rem;">' +
205                                         '<span style="position:relative;top:0.4em;">' +
206                                         text_right +
207                                         '</span></div>');
208
209                                 slider.before( elem_left );
210                                 slider.after( elem_right );
211                                 break;
212                         }
213
214                         if ( icon ) {
215                                 slider.parent('.ui-slider-container').css({
216                                         "margin-left": margin_left,
217                                         "margin-right": margin_right
218                                 });
219                         }
220
221                         // handle press
222                         slider.append($('<div class="ui-slider-handle-press"></div>'));
223                         self.handle_press = slider.find('.ui-slider-handle-press');
224                         self.handle_press.css('display', 'none');
225
226                         // add a popup element (hidden initially)
227                         slider.parents(".ui-page").append( self.popup );
228                         self.popup.hide();
229
230                         // get the element where value can be displayed
231                         self.handleText = slider.find('.ui-btn-text');
232
233                         // set initial value
234                         self.updateSlider();
235
236                         // bind to changes in the slider's value to update handle text
237                         this.element.on('change', function () {
238                                 self.updateSlider();
239                                 self.showPopup();
240                         });
241                         this.element.on( 'slidestart', function( event ) {
242                                 self.updateSlider();
243                                 self.showPopup();
244                         });
245
246                         // bind clicks on the handle to show the popup
247                         self.handle.on('vmousedown', function () {
248                                 self.showPopup();
249                         });
250
251                         // watch events on the document to turn off the slider popup
252                         slider.add( document ).on('vmouseup', function () {
253                                 self.hidePopup();
254                         });
255                 },
256
257                 _handle_press_show: function () {
258                         this.handle_press.css('display', '');
259                 },
260
261                 _handle_press_hide: function () {
262                         this.handle_press.css('display', 'none');
263                 },
264
265                 // position the popup
266                 positionPopup: function () {
267                         var dstOffset = this.handle.offset();
268
269                         this.popup.offset({
270                                 left: dstOffset.left + ( this.handle.width() - this.popup.width() ) / 2,
271                                 top: dstOffset.top - this.popup.height()
272                         });
273
274                         this.handle_press.offset({
275                                 left: dstOffset.left,
276                                 top: dstOffset.top
277                         });
278                 },
279
280                 // show value on the handle and in popup
281                 updateSlider: function () {
282                         var font_size,
283                                 font_length,
284                                 font_top,
285                                 padding_size,
286                                 newValue,
287                                 get_value_length = function ( v ) {
288                                         var val = Math.abs( v ),
289                                                 len;
290
291                                         if ( val > 999 ) {
292                                                 len = 4;
293                                         } else if ( val > 99 ) {
294                                                 len = 3;
295                                         } else if ( val > 9 ) {
296                                                 len = 2;
297                                         } else {
298                                                 len = 1;
299                                         }
300
301                                         if ( v < 0 ) {
302                                                 len++;
303                                         }
304
305                                         return len;
306                                 };
307
308                         // remove the title attribute from the handle (which is
309                         // responsible for the annoying tooltip); NB we have
310                         // to do it here as the jqm slider sets it every time
311                         // the slider's value changes :(
312                         this.handle.removeAttr('title');
313
314                         newValue = this.element.val();
315
316                         font_length = get_value_length( newValue );
317
318                         if ( this.popupVisible ) {
319                                 this.positionPopup();
320
321                                 switch ( font_length ) {
322                                 case 1:
323                                 case 2:
324                                         font_size = '1.5rem';
325                                         padding_size = '0.15rem';
326                                         break;
327                                 case 3:
328                                         font_size = '1rem';
329                                         padding_size = '0.5rem';
330                                         break;
331                                 default:
332                                         font_size = '0.8rem';
333                                         padding_size = '0.5rem';
334                                         break;
335                                 }
336
337                                 this.popup.css({
338                                         "font-size": font_size,
339                                         "padding-top": padding_size
340                                 });
341                         }
342
343                         if ( newValue === this.currentValue ) {
344                                 return;
345                         }
346
347                         switch ( font_length ) {
348                         case 1:
349                                 font_size = '0.95rem';
350                                 font_top = '0';
351                                 break;
352                         case 2:
353                                 font_size = '0.85rem';
354                                 font_top = '-0.01rem';
355                                 break;
356                         case 3:
357                                 font_size = '0.65rem';
358                                 font_top = '-0.05rem';
359                                 break;
360                         default:
361                                 font_size = '0.45rem';
362                                 font_top = '-0.15rem';
363                                 break;
364                         }
365
366                         if ( font_size != this.handleText.css('font-size') ) {
367                                 this.handleText.css({
368                                         'font-size': font_size,
369                                         'top': font_top
370                                 });
371                         }
372
373                         this.currentValue = newValue;
374                         this.handleText.text( newValue );
375                         this.popup.html( newValue );
376
377                         this.element.trigger( 'update', newValue );
378                 },
379
380                 // show the popup
381                 showPopup: function () {
382                         if ( !this.options.popup || this.popupVisible ) {
383                                 return;
384                         }
385
386                         this.popup.show();
387                         this.popupVisible = true;
388                         this._handle_press_show();
389                 },
390
391                 // hide the popup
392                 hidePopup: function () {
393                         if ( !this.options.popup || !this.popupVisible ) {
394                                 return;
395                         }
396
397                         this.popup.hide();
398                         this.popupVisible = false;
399                         this._handle_press_hide();
400                 },
401
402                 _setOption: function (key, value) {
403                         var needToChange = ( value !== this.options[key] );
404
405                         if ( !needToChange ) {
406                                 return;
407                         }
408
409                         switch ( key ) {
410                         case 'popup':
411                                 this.options.popup = value;
412
413                                 if ( this.options.popup) {
414                                         this.updateSlider();
415                                 } else {
416                                         this.hidePopup();
417                                 }
418
419                                 break;
420                         }
421                 }
422         });
423
424         // stop jqm from initialising sliders
425         $( document ).on( "pagebeforecreate", function ( e ) {
426                 if ( $.data( window, "jqmSliderInitSelector" ) === undefined ) {
427                         $.data( window, "jqmSliderInitSelector",
428                                 $.mobile.slider.prototype.options.initSelector );
429                         $.mobile.slider.prototype.options.initSelector = null;
430                 }
431         });
432
433         // initialise sliders with our own slider
434         $( document ).on( "pagecreate create", function ( e ) {
435                 var jqmSliderInitSelector = $.data( window, "jqmSliderInitSelector" );
436                 $( e.target ).find(jqmSliderInitSelector).each(function () {
437                         var $this = $( this );
438                         if ( $this.is("select") ) {
439                                 $this.slider();
440                         } else {
441                                 $this.tizenslider();
442                         }
443                 });
444         });
445
446 }( jQuery, this ));
447
448 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
449 } );
450 //>>excludeEnd("jqmBuildExclude");