[ExercisePlanner] updated ExercisePlanner sources
[samples/web/ExercisePlanner.git] / js / UI.js
1 /*jslint nomen: true*/
2 /*global $, GraphSchedule, range, history, setTimeout */
3 function UI() {
4         "use strict";
5 }
6
7 (function () {
8         "use strict";
9         UI.prototype = {
10                 sentence : {
11                         'lazy' : {
12                                 text : 'He does not seem to me to be a free man who does not sometimes do nothing.',
13                                 signature : 'Marcus T. Cicero'
14                         },
15                         'run' : {
16                                 text : 'A journey of a thousand miles begins with a  single step.',
17                                 signature : 'Lao-tzu'
18                         }
19                 },
20                 graphSchedule : null,
21                 app : null
22         };
23
24         UI.prototype.fillExercises = function (exercisesData) {
25                 var i, len, self = this;
26
27                 $('#exercises').replaceWith(
28                         $('<ul data-role="listview" id="exercises"></ul>')
29                 );
30                 for (i = 0, len = exercisesData.length; i < len; i += 1) {
31                         $('#exercises').append(
32                                 $(this.getExercisesTemplate(exercisesData[i], i))
33                         );
34                 }
35                 $('#exercises').listview();
36                 $('#exercises :jqmData(role="slider")').slider();
37                 $('#exercises li').on('tap', function () {
38                         var $toggle = $(this).find(':jqmData(role="slider")');
39                         $toggle.val(($toggle.val() === 'off') ? 'on' : 'off');
40                         $toggle.slider('refresh');
41                         self.app.saveExercises(self.getExercisesList());
42                 });
43                 $('#exercises :jqmData(role="slider")').on('change', function (e) {
44                         e.preventDefault();
45                         e.stopPropagation();
46                         self.app.saveExercises(self.getExercisesList());
47                 });
48         };
49
50         UI.prototype.popup = function (text, callback) {
51                 var i, popup = $("#popup"),
52                         buttons = {'Cancel': function () { $("#popup").popup('close') }};
53                 // to hide default button give {'Close': false} in callback
54
55                 for (i in callback) {
56                         if (callback.hasOwnProperty(i)) {
57                                 buttons[i] = callback[i];
58                         }
59                 }
60
61                 $(".ui-popup-button-bg", popup).empty();
62                 for (i in buttons) {
63                         if (buttons.hasOwnProperty(i)) {
64                                 if (buttons[i]) {
65                                         $('<a/>')
66                                                 .text(i)
67                                                 .attr({'data-role': 'button', 'data-inline': 'true'})
68                                                 .bind('tap', buttons[i])
69                                                 .appendTo($(".ui-popup-button-bg", popup));
70                                 }
71                         }
72                 }
73                 $(".text", popup).text(text);
74
75                 popup.trigger("create");
76                 popup.popup('open', {positionTo: 'window'});
77         };
78
79         UI.prototype.clearTabbars = function () {
80                 $('[data-role = "tabbar"] li > a').removeClass('ui-focus, ui-btn-active');
81         };
82
83         UI.prototype.fillTimesRanges = function (timesData) {
84                 var self = this, len, i;
85
86                 $('#availableTime').replaceWith(
87                         $('<ul data-role="listview" id="availableTime"></ul>')
88                 );
89                 for (i = 0, len = timesData.length; i < len; i += 1) {
90                         $('#availableTime')
91                                 .append($(this.getAvailableTimeTemplate(timesData[i])));
92                 }
93                 $('#availableTime').trigger('create');
94                 $('#availableTime').listview().listview('refresh');
95                 $('#availableTime :jqmData(name=edit)').on('tap', function (e) {
96                         if (self.app.config.trainingEnabled) {
97                                 self.popup('You should stop the training first');
98                         } else {
99                                 e.preventDefault();
100                                 e.stopPropagation();
101                                 self.editTimeRange($(this).data('val'));
102                         }
103                 });
104                 $('#availableTime :jqmData(name=disable)').on('tap', function (e) {
105                         if (self.app.config.trainingEnabled) {
106                                 self.popup('You should stop the training first');
107                         } else {
108                                 e.stopPropagation();
109                                 self.app.disableTimeRange($(this).data('val'));
110                         }
111                 });
112                 $('#availableTime :jqmData(name=delete)').on('tap', function (e) {
113                         var value = $(this).data('val');
114                         e.stopPropagation();
115                         if (self.app.config.trainingEnabled) {
116                                 self.popup('You should stop the training first');
117                                 return;
118                         }
119                         self.popup('Are you sure?', {
120                                 'Delete': function () {
121                                         self.app.deleteTimeRange(value);
122                                         $("#popup").popup('close');
123                                 }
124                         });
125                 });
126         };
127
128         UI.prototype.fillTimeRangeForm = function fillTimeRangeForm(timeRange) {
129                 var tmpData = new Date();
130                 // Filling form;
131                 $('#startTime').attr('data-val',
132                                 new Date(tmpData.setHours(timeRange.start)));
133                 $('#duration').attr('data-val', timeRange.duration);
134
135                 if ($('#startTime').data('datetimepicker')) {
136                         $('#startTime').data('datetimepicker').options.date
137                                 .setHours(timeRange.start);
138                         $('#startTime').data('datetimepicker').ui
139                                 .find('.ui-datefield-hour').html(
140                                         (timeRange.start < 10) ? '0' + timeRange.start : timeRange.start
141                                 );
142                 }
143                 if ($('#duration').data('datetimepicker')) {
144                         $('#duration').data('datetimepicker').options.date
145                                 .setHours(timeRange.duration);
146                         $('#duration').data('datetimepicker').ui.find('.ui-datefield-hour')
147                                 .html(
148                                         (timeRange.duration < 10) ? '0'
149                                                 + timeRange.duration : timeRange.duration
150                                 );
151                         $('#duration').data('datetimepicker')._populateDataSelector = function (field, pat) {
152                                 var result = $.tizen.datetimepicker.prototype._populateDataSelector
153                                                 .call(this, field, pat);
154                                 result.values = range(1, 20);
155                                 result.data = range(1, 20);
156                                 result.current -= 1;
157                                 return result;
158                         };
159                 }
160                 $.each($("input[name='periodType']"), function () {
161                         $(this).attr('checked', $(this).val() === timeRange.style)
162                                 .checkboxradio('refresh');
163                 });
164                 $('#formEnablePeriod')[0].value = timeRange.enabled ? 'on' : 'off';
165                 $('#formEnablePeriod').slider('refresh');
166         };
167
168         UI.prototype.editTimeRange = function (nr, event) {
169                 if (event && typeof event.stopPropagation === 'function') {
170                         event.preventDefault();
171                         event.stopPropagation();
172                 }
173
174                 if (this.app.editTimeRange(nr) >= 0) {
175                         $('#updateTime').val('modify');
176                         $('#rangesOfTimes h1').text('Edit Time');
177                 } else {
178                         $('#updateTime').val('add');
179                         $('#rangesOfTimes h1').text('Add Time');
180                 }
181
182                 // change page to form;
183                 $.mobile.changePage("#rangesOfTimes");
184         };
185
186         UI.prototype.getExercisesList = function () {
187                 return $('#exercises :jqmData(role=slider)').map(function (o, v) {
188                         return ({
189                                 index : $(v).attr('data-index'),
190                                 checked : ($(v).val() === 'on') ? true : false
191                         });
192                 });
193         };
194
195         UI.prototype.addExercise = function () {
196                 var trimmedName = $("#newExerciseName").val().trim();
197                 trimmedName = $('<span>').text(trimmedName).html();
198                 if (trimmedName !== '') {
199                         if (this.app.addExercise(trimmedName)) {
200                                 $("#newExerciseName").trigger('blur');
201                                 setTimeout(history.back.bind(history), 50);
202                         }
203                 } else {
204                         this.showErrors([ {
205                                 name : 'Name of exercise is not correct.',
206                                 code : 100
207                         } ]);
208                 }
209         };
210
211         UI.prototype.configToUI = function () {
212         };
213
214         UI.prototype.updateMainUI = function () {
215                 this.setStatusRun(this.app.config.trainingEnabled);
216                 this.graphSchedule.setTimeRanges(this.app.periodsWeekToBoolArray());
217         };
218
219         UI.prototype.getTimeRangeFromForm = function () {
220                 return {
221                         start : $('#startTime').data('datetimepicker').options.date
222                                         .getHours(),
223                         duration : $('#duration').data('datetimepicker').options.date
224                                         .getHours(),
225                         stop : $('#startTime').data('datetimepicker').options.date
226                                         .getHours()
227                                         + $('#duration').data('datetimepicker').options.date
228                                                         .getHours(),
229                         style : $('.selectPeriodType :radio:checked').val(),
230                         enabled : ($('#formEnablePeriod')[0].value === 'on' ? true : false)
231                 };
232         };
233
234         UI.prototype.editTimeRangeAction = function (nr) {
235                 if (this.app.saveTimeRange(nr, this.getTimeRangeFromForm())) {
236                         history.back();
237                 } else {
238                         throw ({
239                                 message : 'Time start and stop is not present.',
240                                 code : 1
241                         });
242                 }
243         };
244
245         UI.prototype.showNoticeInMonitor = function (notice, alarm) {
246                 $('#communicate').html(notice);
247                 $('#communicate').toggleClass('onAlert', alarm);
248         };
249
250         UI.prototype.changeButtonAddTime = function (text) {
251                 $('#addTime').html(text);
252         };
253
254         UI.prototype.showErrors = function (errors) {
255                 var i; // count;
256                 for (i = 0; i < errors.length; i += 1) {
257                         this.popup(errors[i].name);
258                 }
259                 this.unblockButtons();
260         };
261
262         UI.prototype.unblockButtons = function () {
263                 $('#btnNewExercise').data('disabled', false);
264         };
265
266         UI.prototype.showAlarmInMonitor = function (data) {
267                 var notice = '';
268                 function formatNN(val) {
269                         return (val < 10) ? ('0' + val) : val;
270                 }
271
272                 if (data && data.alarm && this.app.config.trainingEnabled) {
273                         this.app.currentAlarm = this.app.findCurrentAlarm();
274                         if (this.app.currentAlarm.length > 0) {
275                                 notice += 'Go... go... go...!<br>' + data.exerciseName + ' x '
276                                         + data.numberOfTimes;
277                         } else {
278                                 notice += 'Next exercises set at: '
279                                         + formatNN(data.alarm.getHours()) + ':'
280                                         + formatNN(data.alarm.getMinutes()) + '<br>'
281                                         + data.exerciseName + ' x ' + data.numberOfTimes;
282                         }
283                 } else {
284                         notice += '<br/>You have no workouts scheduled for now.<br/>';
285                 }
286                 this.showNoticeInMonitor(notice, false);
287         };
288
289         UI.prototype.getSentence = function UI_getSentence(type) {
290                 return (this.sentence[type] || {
291                         text : 'No sentence',
292                         signature : 'anonymous'
293                 });
294         };
295
296         UI.prototype.setSentence = function (type) {
297                 var sentence = this.getSentence(type);
298                 $('#sentence').html('"' + sentence.text + '"');
299                 $('#signature').html('- ' + sentence.signature);
300         };
301
302         UI.prototype.showWaitOk = function () {
303                 $('#mainControl').hide();
304                 $('#one .ui-btn-back').hide();
305
306                 $('#onAlertControl').tabbar();
307                 $('#onAlertControl').show();
308                 $('#onAlertControl').css('width', '');
309         };
310
311         UI.prototype.setStatusRun = function (bool) {
312                 if (bool) {
313                         // icon;
314                         $('#status').removeClass('lazy').addClass('run');
315                         // sentence;
316                         this.setSentence('run');
317                         // button in control bar;
318                         $('#startStop .ui-btn-text').html('Stop Training');
319                 } else {
320                         $('#status').removeClass('run').addClass('lazy');
321                         this.setSentence('lazy');
322                         $('#communicate').html('');
323                         $('#startStop .ui-btn-text').html('Start Training');
324                 }
325         };
326
327         UI.prototype.bindEvents = function bindEvents() {
328                 var self = this;
329
330                 // bind events;
331                 $("#popup").popup();
332
333                 $('#one .ui-btn-back').on('tap', this.app.exit.bind(this.app));
334
335                 $('#ok').on('tap', self.app.ok.bind(self.app));
336                 $('#wait').on('tap', self.app.wait.bind(self.app));
337                 $('#todayOffAll').on('tap', self.app.todayOffAll.bind(self.app));
338
339                 $('[data-role = "tabbar"] li > a').on('click', function () {
340                         self.clearTabbars();
341                 });
342
343                 $('#startStop').on('click', function () {
344                         self.app.appStartStop();
345                 });
346
347                 document.addEventListener('tizenhwkey', function(e) {
348                         if (e.keyName == 'back') {
349                                 if ($.mobile.popup.active) {
350                                         $.mobile.popup.active.close();
351                                 } else if ($.mobile.activePage.attr('id') === 'one') {
352                                         tizen.application.getCurrentApplication().exit();
353                                 } else {
354                                         history.back();
355                                 }
356                         }
357                 });
358
359                 $('#one').on(
360                         'pageshow',
361                         function (page, options) {
362                                 if (self.graphSchedule.ui) {
363                                         $('#one .schedule').append(self.graphSchedule.ui);
364                                         self.app.updateGraph();
365                                         self.graphSchedule.refresh();
366                                         self.graphSchedule.setVisibleWeekend(!self.app
367                                                 .todayIsWorkday());
368                                         self.graphSchedule.setVisibleWorkdays(self.app
369                                                 .todayIsWorkday());
370                                 }
371                                 $('#one .schedule').on('touchstart', function (ev) {
372                                         ev.stopPropagation();
373                                 });
374
375                                 // workaround for scroll lock;
376                                 $.mobile.activePage.css('position', 'fixed');
377
378                                 if ($('a.ui-btn-back').is(':hidden')) {
379                                         $('div#mainControl').removeClass('ui-tabbar-margin-back');
380                                 }
381                         }
382                 );
383
384                 $('#two').on('pageshow', function (page, options) {
385                         self.fixPageHeight('#two');
386
387                         if (self.graphSchedule.ui) {
388                                 $('#two .scheduleOptions').append(self.graphSchedule.ui);
389                                 self.graphSchedule.refresh();
390                                 self.graphSchedule.setVisibleWeekend(true);
391                                 self.graphSchedule.setVisibleWorkdays(true);
392                         }
393
394                         if ($('a.ui-btn-back').is(':hidden')) {
395                                 $('div#selectExercisesBar').removeClass('ui-tabbar-margin-back');
396                         }
397                 });
398
399                 $('#two').on('pageinit', function (page, options) {
400                         $('.ui-radio input', $('#frequency')).change(function (ev) {
401                                 var that = this;
402                                 self.startProgress();
403                                 setTimeout(function (){
404                                         self.app.setFrequency(that.value);
405                                         self.updateMainUI();
406                                         self.endProgress();
407                                 }, 100);
408                         });
409
410                         $('.ui-radio input', $('#strength')).change(function (ev) {
411                                 self.app.setStrength(this.value);
412                                 self.updateMainUI();
413                         });
414
415                         $('#frequency')[0].select(self.app.config.frequency);
416                         $('#strength')[0].select(self.app.config.strength);
417
418                         $('#two .scheduleOptions').append(self.graphSchedule.ui);
419                         $('#two .scheduleOptions').on('touchstart', function (ev) {
420                                 ev.stopPropagation();
421                         });
422
423                         $('#workdaysType').on('tap', function (ev) {
424                                 var that = $(this).children("a");
425                                 setTimeout(function(){
426                                         that.removeClass("ui-btn-active");
427                                 }, 400);
428
429                                 self.app.changeTypeOfPeriods('workday');
430                         });
431
432                         $('#weekendType').on('tap', function (ev) {
433                                 var that = $(this).children("a");
434                                 setTimeout(function(){
435                                         that.removeClass("ui-btn-active");
436                                 }, 400);
437
438                                 self.app.changeTypeOfPeriods('weekend');
439                         });
440
441                         $('#addTimeRange').on('tap', function (e) {
442                                 if (self.app.config.trainingEnabled) {
443                                         self.popup('You should stop the training first');
444                                 } else {
445                                         self.editTimeRange(-1, e);
446                                 }
447                         });
448
449                         self.app.updateTimesRanges();
450                         self.configToUI();
451                 });
452
453                 $('#selectExercises').on('pageinit', function (page, options) {
454                         self.app.updateExercises();
455                         self.configToUI();
456                 });
457
458                 $('#selectExercises').on('pageshow', function (page, options) {
459                         self.fixPageHeight('#selectExercises');
460                 });
461
462                 $('#customExercises').on('pageinit', function (page, options) {
463                         $('#btnNewExercise').on('click', function (e) {
464                                 e.preventDefault();
465                                 e.stopPropagation();
466                                 if ($(this).data('disabled') !== true) {
467                                         $(this).data('disabled', true);
468                                         self.addExercise();
469                                 }
470                         });
471                 });
472
473                 $('#customExercises').on('pageshow', function (page, options) {
474                         self.unblockButtons();
475
476                         $('#newExerciseName').val('');
477                 });
478
479                 $('#rangesOfTimes').on('pageinit', function (page, options) {
480                         $("#updateTime").on("click", function (e) {
481                                 e.preventDefault();
482                                 e.stopPropagation();
483                                 self.startProgress('Saving');
484                                 self.editTimeRangeAction(self.app.currentEditingTimePeriodId);
485                         });
486                 });
487
488                 $('#rangesOfTimes').on('pageshow', function (page, options) {
489                         self.fixPageHeight('#rangesOfTimes');
490
491                         $('#updateTime').data('button').refresh();
492                         self.fillTimeRangeForm(self.app.currentEditingTimePeriod);
493                 });
494
495                 $('#increasingStrength').on('change', function () {
496                         self.app.config.increasingStrength = this.checked;
497                         self.app.saveConfig();
498
499                         self.configToUI();
500                 });
501
502                 $('#add_custom_workout_btn').on('tap', function (e) {
503                         e.preventDefault();
504                         e.stopPropagation();
505                         $.mobile.changePage('#customExercises');
506                 });
507         };
508
509         UI.prototype.onGraphSchedule = function onGraphSchedule(onInitEnd) {
510                 this.updateMainUI();
511
512                 $('#one .schedule').append(this.graphSchedule.ui);
513                 this.app.updateGraph();
514                 this.graphSchedule.refresh();
515                 this.graphSchedule.setVisibleWeekend(!this.app.todayIsWorkday());
516                 this.graphSchedule.setVisibleWorkdays(this.app.todayIsWorkday());
517
518                 if (typeof onInitEnd === 'function') {
519                         onInitEnd();
520                 }
521         };
522
523         UI.prototype.initialize = function (onInitEnd) {
524                 $.mobile.tizen.disableSelection(document);
525
526                 this.bindEvents();
527
528                 $('html, body').css('font-size', '');
529                 $('[data-role=footer]').height('');
530
531                 this.graphSchedule = new GraphSchedule({
532                         onSuccess : this.onGraphSchedule.bind(this, onInitEnd)
533                 });
534
535                 this.fixContentHeight();
536         };
537
538         UI.prototype.fixPageHeight = function (element) {
539                 //FIXME (two scrollbar workaround)
540                 setTimeout(
541                         function () {
542                                 var newHeight = $(element).find('[data-role="content"]').prop('style').height;
543                                 $(element).css({'min-height': newHeight, 'height': newHeight});
544                         },
545                         0
546                 );
547         };
548
549         UI.prototype.fixContentHeight = function () {
550                 var contentHeight = screen.availHeight - $('div[data-role="header"]').outerHeight() - $('div[data-role="footer"]').outerHeight();
551                 $('div[data-role="content"]').css('height', contentHeight);
552         };
553
554         UI.prototype.startProgress = function (title) {
555                 title = title || "Updating schedule";
556                 $("#progress").show();
557                 $("#progresstitle").text(title);
558                 $("#progressbar").progressbar({value: false});
559         };
560
561         UI.prototype.endProgress = function () {
562                 $("#progress").fadeOut();
563         };
564 }());