UnitTC: Additional unit testcases have been added
[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.bind('change', function () {
238                                 self.updateSlider();
239                         });
240
241                         // bind clicks on the handle to show the popup
242                         self.handle.bind('vmousedown', function () {
243                                 self.showPopup();
244                         });
245
246                         // watch events on the document to turn off the slider popup
247                         slider.add( document ).bind('vmouseup', function () {
248                                 self.hidePopup();
249                         });
250                 },
251
252                 _handle_press_show: function () {
253                         this.handle_press.css('display', '');
254                 },
255
256                 _handle_press_hide: function () {
257                         this.handle_press.css('display', 'none');
258                 },
259
260                 // position the popup
261                 positionPopup: function () {
262                         var dstOffset = this.handle.offset();
263
264                         this.popup.offset({
265                                 left: dstOffset.left + ( this.handle.width() - this.popup.width() ) / 2,
266                                 top: dstOffset.top - this.popup.height()
267                         });
268
269                         this.handle_press.offset({
270                                 left: dstOffset.left,
271                                 top: dstOffset.top
272                         });
273                 },
274
275                 // show value on the handle and in popup
276                 updateSlider: function () {
277                         var font_size,
278                                 font_length,
279                                 font_top,
280                                 padding_size,
281                                 newValue,
282                                 get_value_length = function ( v ) {
283                                         var val = Math.abs( v ),
284                                                 len;
285
286                                         if ( val > 999 ) {
287                                                 len = 4;
288                                         } else if ( val > 99 ) {
289                                                 len = 3;
290                                         } else if ( val > 9 ) {
291                                                 len = 2;
292                                         } else {
293                                                 len = 1;
294                                         }
295
296                                         if ( v < 0 ) {
297                                                 len++;
298                                         }
299
300                                         return len;
301                                 };
302
303                         // remove the title attribute from the handle (which is
304                         // responsible for the annoying tooltip); NB we have
305                         // to do it here as the jqm slider sets it every time
306                         // the slider's value changes :(
307                         this.handle.removeAttr('title');
308
309                         newValue = this.element.val();
310
311                         font_length = get_value_length( newValue );
312
313                         if ( this.popupVisible ) {
314                                 this.positionPopup();
315
316                                 switch ( font_length ) {
317                                 case 1:
318                                 case 2:
319                                         font_size = '1.5rem';
320                                         padding_size = '0.15rem';
321                                         break;
322                                 case 3:
323                                         font_size = '1rem';
324                                         padding_size = '0.5rem';
325                                         break;
326                                 default:
327                                         font_size = '0.8rem';
328                                         padding_size = '0.5rem';
329                                         break;
330                                 }
331
332                                 this.popup.css({
333                                         "font-size": font_size,
334                                         "padding-top": padding_size
335                                 });
336                         }
337
338                         if ( newValue === this.currentValue ) {
339                                 return;
340                         }
341
342                         switch ( font_length ) {
343                         case 1:
344                                 font_size = '0.95rem';
345                                 font_top = '0';
346                                 break;
347                         case 2:
348                                 font_size = '0.85rem';
349                                 font_top = '-0.01rem';
350                                 break;
351                         case 3:
352                                 font_size = '0.65rem';
353                                 font_top = '-0.05rem';
354                                 break;
355                         default:
356                                 font_size = '0.45rem';
357                                 font_top = '-0.15rem';
358                                 break;
359                         }
360
361                         if ( font_size != this.handleText.css('font-size') ) {
362                                 this.handleText.css({
363                                         'font-size': font_size,
364                                         'top': font_top
365                                 });
366                         }
367
368                         this.currentValue = newValue;
369                         this.handleText.text( newValue );
370                         this.popup.html( newValue );
371
372                         this.element.trigger( 'update', newValue );
373                 },
374
375                 // show the popup
376                 showPopup: function () {
377                         if ( !this.options.popup || this.popupVisible ) {
378                                 return;
379                         }
380
381                         this.popup.show();
382                         this.popupVisible = true;
383                         this._handle_press_show();
384                 },
385
386                 // hide the popup
387                 hidePopup: function () {
388                         if ( !this.options.popup || !this.popupVisible ) {
389                                 return;
390                         }
391
392                         this.popup.hide();
393                         this.popupVisible = false;
394                         this._handle_press_hide();
395                 },
396
397                 _setOption: function (key, value) {
398                         var needToChange = ( value !== this.options[key] );
399
400                         if ( !needToChange ) {
401                                 return;
402                         }
403
404                         switch ( key ) {
405                         case 'popup':
406                                 this.options.popup = value;
407
408                                 if ( this.options.popup) {
409                                         this.updateSlider();
410                                 } else {
411                                         this.hidePopup();
412                                 }
413
414                                 break;
415                         }
416                 }
417         });
418
419         // stop jqm from initialising sliders
420         $( document ).bind( "pagebeforecreate", function ( e ) {
421                 if ( $.data( window, "jqmSliderInitSelector" ) === undefined ) {
422                         $.data( window, "jqmSliderInitSelector",
423                                 $.mobile.slider.prototype.options.initSelector );
424                         $.mobile.slider.prototype.options.initSelector = null;
425                 }
426         });
427
428         // initialise sliders with our own slider
429         $( document ).bind( "pagecreate create", function ( e ) {
430                 var jqmSliderInitSelector = $.data( window, "jqmSliderInitSelector" );
431                 $( e.target ).find(jqmSliderInitSelector).not('select').tizenslider();
432                 $( e.target ).find(jqmSliderInitSelector).filter('select').slider();
433         });
434
435 }( jQuery, this ));
436
437 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
438 } );
439 //>>excludeEnd("jqmBuildExclude");