Tizen 2.0 Release
[samples/web/CallLog.git] / js / app.ui.js
1 /*jslint devel: true*/
2 /*global tizen, document, $, app, UiPanel, UiContact, TemplateManager, window, Helpers */
3
4 /**
5  * @class Ui
6  */
7
8 function Ui(contacts) {
9         'use strict';
10         this.init();
11 }
12
13 (function () { // strict mode wrapper
14         'use strict';
15         Ui.prototype = {
16                 /**
17                  * UI remove mode
18                  * @type {boolean}
19                  */
20                 removeMode: false,
21
22                 /**
23                  * @type {TemplateManager}
24                  */
25                 templateManager: null,
26
27                 /**
28                  * UI Initializer
29                  */
30                 init: function Ui_init() {
31                         this.templateManager = new TemplateManager();
32                         this.helpers = new Helpers();
33                         $(document).ready(this.domInit.bind(this));
34                 },
35
36                 /**
37                  * When DOM is ready, initialise it (bind events)
38                  */
39                 domInit: function Ui_domInit() {
40                         this.templateManager.loadToCache(['callView', 'callerHistory', 'callItemRow', 'callerCallItemRow', 'messageWindow', 'dateRow'], this.initPages.bind(this));
41                 },
42
43                 /**
44                  * UI pages initializer
45                  */
46                 initPages: function Ui_initPages() {
47                         var pages = [];
48
49                         $('#callView').append($(this.templateManager.get('callView')).children()).trigger('pagecreate');
50
51                         pages.push(this.templateManager.get('callerHistory'));
52                         $('body').append(pages.join(''));
53                         this.removeSearchBarToHeader();
54
55                         this.addEvents();
56                         app.showCallHistory();
57                 },
58
59                 /**
60                  * Add UI events
61                  */
62                 addEvents: function Ui_addEvents() {
63                         var self = this;
64
65                         $('#callView .ui-btn-back').on('tap', app.exit.bind(app));
66
67                         $('#callView').on('pagebeforeshow', function () {
68                                 app.showCallHistory();
69                         });
70
71                         $('#historyForCallerView').on('pagebeforeshow', function () {
72                                 self.hideCheckboxes();
73                                 $('#historyForCallerView .ui-content')
74                                         .scrollview('scrollTo', 0, 0);
75                                 $('#historyForCallerView .ui-content .ui-scrollview-view')
76                                         .css('-webkit-transform', 'translate3d(0px, 0px, 0px)');
77                                 $('#selectAllDetails').on('change', function () {
78                                         self.selectAllDetails();
79                                 });
80                         });
81
82                         $('#historyForCallerView').on('pageshow', function () {
83                                 $('#content').css('top', '160px');
84                                 $('#header').css('height', '160px');
85                                 $('#delete-toolbar').css('width', '70px');
86                         });
87
88                         $(window).on('resize', function () {
89                                 $('#delete-toolbar').css('width', '70px');
90                         });
91
92                         $('.selectAllBox').on('tap', function () {
93                                 self.selectAll();
94                                 self.selectAllDetailsEach();
95                         });
96
97                         $('#calllogList').on('tap', '.date', function (event) {
98                                 event.stopPropagation();
99                         });
100
101                         $('#calllogList').on('click', '.call', function onCalllogEntryClick(event) {
102                                 if ($(this).data('entries')[0].remoteParties[0].remoteParty !== "") {
103                                         app.showHistoryForCaller($(this).data('entries')[0].remoteParties[0].remoteParty);
104                                         $.mobile.changePage('#historyForCallerView');
105                                 }
106                         });
107
108                         $('#smsActionBtn').on('tap', function () {
109                                 self.hideCheckboxes();
110                                 app.sendSms($('#forCallerList').data('remoteParty'));
111                         });
112
113                         $('#callActionBtn').on('tap', function () {
114                                 self.hideCheckboxes();
115                                 app.makeCall($('#forCallerList').data('remoteParty'));
116                         });
117
118                         $('#deleteActionBtn').on('tap', function () {
119                                 self.changeDetailsToRemoveState();
120                         });
121
122                         $('#forCallerList').on('tap', 'li', function () {
123                                 var checkbox = $(this).find(':checkbox');
124                                 if (self.removeMode === true) {
125                                         if (checkbox.attr('checked')) {
126                                                 checkbox.attr('checked', false)
127                                                         .data('checkboxradio')
128                                                         .refresh();
129                                         } else {
130                                                 checkbox.attr('checked', true)
131                                                         .data('checkboxradio')
132                                                         .refresh();
133                                         }
134                                         self.setSelectAllDetails();
135                                 }
136                         });
137                 },
138
139                 addEventsForCallerListCheckboxes: function Ui_addEventsForCallerListCheckboxes() {
140                         var self = this;
141                         $('#forCallerList :checkbox').on('change', function (event) {
142                                 if ($(this).attr('checked')) {
143                                         $(this).attr('checked', true);
144                                 } else {
145                                         $(this).attr('checked', false);
146                                 }
147                                 self.setSelectAllDetails();
148                         });
149                 },
150
151                 selectAll: function Ui_selectAll() {
152                         var selectAll = $('#selectAllDetails');
153                         if (selectAll.attr('checked')) {
154                                 selectAll
155                                         .attr('checked', false)
156                                         .data('checkboxradio')
157                                         .refresh();
158                         } else {
159                                 selectAll
160                                         .attr('checked', true)
161                                         .data('checkboxradio')
162                                         .refresh();
163                         }
164                 },
165
166                 selectAllDetails: function Ui_selectAllDetails() {
167                         if ($('#selectAllDetails').attr('checked')) {
168                                 $('#selectAllDetails').attr('checked', true);
169                         } else {
170                                 $('#selectAllDetails').attr('checked', false);
171                         }
172                         this.selectAllDetailsEach();
173                 },
174
175                 /**
176                  * Returns number of selected call logs
177                  * @return {number} length
178                  */
179                 getCountSelectedLogEntries: function Ui_getCountSelectedLogEntries() {
180                         return $('#forCallerList li .toRemove label.ui-checkbox-on').length;
181                 },
182
183                 selectAllDetailsEach: function Ui_selectAllDetailsEach() {
184                         $('#forCallerList').find('input').each(function () {
185                                 if ($('#selectAllDetails').attr('checked')) {
186                                         $(this).attr('checked', true)
187                                                 .data('checkboxradio')
188                                                 .refresh();
189                                 } else {
190                                         $(this).attr('checked', false)
191                                                 .data('checkboxradio')
192                                                 .refresh();
193                                 }
194                         });
195                 },
196
197                 /**
198                  * Hides checkboxes
199                  */
200                 hideCheckboxes: function Ui_hideCheckboxes() {
201                         $('#selectAllDetails')
202                                 .attr('checked', false)
203                                 .data('checkboxradio')
204                                 .refresh();
205
206                         $('#forCallerList').find('input').each(function () {
207                                 $(this).attr('checked', false)
208                                         .data('checkboxradio')
209                                         .refresh();
210                         });
211                         this.changeDetailsToRemoveState('hide');
212                 },
213
214                 /**
215                  * Returns css classes for specified entry
216                  *
217                  * @param {CallHistoryEntry} entry
218                  * @returns {string}
219                  */
220                 cssClassesForEntry: function Ui_cssClassesForEntry(entry) {
221                         return 'call dir_' + entry.direction.toLowerCase() + ' type_' + entry.type.replace('.', '-').toLowerCase();
222                 },
223
224                 setSelectAllDetails: function Ui_setSelectAllDetails() {
225                         if ($('#forCallerList input[type="checkbox"]').length === $('#forCallerList input[checked="checked"]').length) {
226                                 $('#selectAllDetails')
227                                         .attr('checked', true)
228                                         .data('checkboxradio')
229                                         .refresh();
230                         } else {
231                                 $('#selectAllDetails')
232                                         .attr('checked', false)
233                                         .data('checkboxradio')
234                                         .refresh();
235                         }
236                 },
237
238                 /**
239                  * Shows popup with specified message
240                  * @param {string} message
241                  */
242                 showPopup: function Ui_showPopup(message) {
243                         // before create new popup close close & remove old popup if exists
244                         this.closePopup();
245                         $('body')
246                                 .append(this.templateManager.get('messageWindow'))
247                                 .trigger('create');
248                         $('#popupMessage').html(message);
249
250                         $('#popup')
251                                 .on('tap', '#popupCancelActionBtn', this.closePopup.bind(this))
252                                 .on('tap', '#popupSubmitActionBtn', this.deleteCheckedLogs.bind(this));
253
254                         $('#popup').popup('open', {'positionTo': 'window'});
255                 },
256
257                 /**
258                  * Hides popup
259                  */
260                 closePopup: function Ui_closePopup() {
261                         $('#popup')
262                                 .popup('close')
263                                 .remove();
264                 },
265
266                 /**
267                  * Deletes checked log entries
268                  */
269                 deleteCheckedLogs: function Ui_deleteCheckedLogs(e) {
270
271                         this.closePopup();
272
273                         $('#selectAllDetails')
274                                 .attr('checked', false)
275                                 .data('checkboxradio')
276                                 .refresh();
277
278                         $('#forCallerList li.call').each(function () {
279                                 if ($(this).find('form label').hasClass('ui-checkbox-on')) {
280                                         app.deleteLog($(this).data('entries')[0]);
281                                         $(this).remove();
282                                 }
283                         });
284
285                         if ($('#forCallerList li.call').length > 0) {
286                                 this.updateCallerHeaderNumberOfEntries($('#forCallerList li.call').length);
287                         } else {
288                                 e.preventDefault();
289                                 $('.ui-listview-filter .ui-input-text').val('');
290                                 $('.ui-listview-filter .ui-input-text').trigger('change');
291                                 $.mobile.changePage('#callView');
292                         }
293                 },
294
295                 changeDetailsToRemoveState: function Ui_changeDetailsToRemoveState(set) {
296                         var counter = this.getCountSelectedLogEntries();
297
298                         if (set !== undefined) {
299                                 this.removeMode = false;
300                         } else if (counter === 0) {
301                                 this.removeMode = !this.removeMode;
302                         }
303
304                         if (counter === 0) {
305                                 if (this.removeMode) {
306                                         $('#historyForCallerView .toRemove').removeClass('hidden');
307                                         $('#historyForCallerView .selectAllBox').removeClass('hidden');
308                                 } else {
309                                         $('#historyForCallerView .toRemove').addClass('hidden');
310                                         $('#historyForCallerView .selectAllBox').addClass('hidden');
311                                 }
312                         } else if (counter > 1) {
313                                 this.showPopup('Are you sure you want to delete selected logs?');
314                         } else {
315                                 this.showPopup('Are you sure you want to delete selected log?');
316                         }
317                         this.refreshScrollView();
318                 },
319
320                 /**
321                  * Renders call history list
322                  *
323                  * @param {CallHistoryEntry[]} callEntries
324                  */
325                 showCallHistory: function Ui_showCallHistory(callEntries) {
326                         var pdate = null, // previous date
327                                 date = '',
328                                 elements = [], // list elements
329                                 len = callEntries.length, // entries length
330                                 tempLength = 0, // length of temporary table;
331                                 i, // loop counter
332                                 j, // loop counter
333                                 current, // current entry object
334                                 today = this.helpers.getShortDate(new Date()), // today short date
335                                 entryShortDate,
336                                 filterResult,
337                                 groupsOfDays = [],
338                                 dayLog,
339                                 index = 0;
340
341                         function filterForSameEntry(element) {
342                                 return current.remoteParties[0].remoteParty === element.remoteParties[0].remoteParty;
343                         }
344
345                         $('.selectedCount').hide();
346
347                         for (i = 0; i < len; i = i + 1) {
348                                 current = callEntries[i];
349                                 date = current.startTime.toLocaleDateString();
350
351                                 // if date is changed create new deyLog;
352                                 if (date !== pdate) {
353                                         dayLog = {};
354                                         dayLog.date = date;
355                                         dayLog.entries = [];
356                                         dayLog.counters = [];
357                                         groupsOfDays.push(dayLog);
358                                         pdate = date;
359                                 }
360
361                                 // group entries by remote Party;
362                                 filterResult = dayLog.entries.filter(filterForSameEntry);
363                                 if (filterResult.length) {
364                                         index = dayLog.entries.indexOf(filterResult[0]);
365                                         dayLog.counters[index] += 1;
366                                 } else {
367                                         dayLog.entries.push(current);
368                                         dayLog.counters[dayLog.entries.length - 1] = 1;
369                                 }
370                         }
371
372                         // Create UL list with dividers;
373                         len = groupsOfDays.length;
374                         for (i = 0; i < len; i += 1) {
375                                 dayLog = groupsOfDays[i];
376                                 tempLength = dayLog.entries.length;
377                                 entryShortDate = this.helpers.getShortDate(dayLog.entries[0].startTime);
378
379                                 // add date header;
380                                 elements.push($(this.templateManager.get('dateRow', {
381                                         'date': today === entryShortDate ? 'Today' : dayLog.date
382                                 })).get(0));
383
384                                 for (j = 0; j < tempLength; j = j + 1) {
385                                         elements.push(this.getCallItemRow(dayLog.entries[j], dayLog.counters[j]));
386                                 }
387                         }
388
389                         $('#calllogList')
390                                 .empty()
391                                 .append(elements);
392
393                         /* workaround for UIFW & webkit scroll*/
394                         $.mobile.activePage.css('min-height', 0);
395                 },
396
397                 /**
398                  * Returns HTML for single log entry
399                  *
400                  * @param {CallHistoryEntry} entry
401                  * @param {number} counter
402                  * @returns {HTMLPartial}
403                  */
404                 getCallItemRow: function Ui_getCallItemRow(entry, counter) {
405                         var party = entry.remoteParties[0],
406                                 name = party.displayName || party.remoteParty,
407                                 tpl;
408
409                         if (party.displayName === "") {
410                                 name = "No Name";
411                         } else if (party.remoteParty === "") {
412                                 name = "No Number";
413                         }
414
415                         if (counter > 1) {
416                                 name += ' (' + counter + ')';
417                         }
418
419                         tpl = this.templateManager.get('callItemRow', {
420                                 'name': name,
421                                 'callTime': entry.startTime.toLocaleTimeString(),
422                                 'cssClasses': this.cssClassesForEntry(entry)
423                         });
424
425                         return $(tpl)
426                                 .data('remoteParty', entry.remoteParties[0].remoteParty)
427                                 .data('entries', [entry])
428                                 .get(0); // return clean DOM element so array of those could be appended at once*/
429                 },
430
431                 /**
432                  * Returns HTML for single caller log entry
433                  *
434                  * @param {CallHistoryEntry} entry
435                  * @returns {HTMLElement}
436                  */
437                 getCallerCallLogRow: function Ui_getCallerCallLogRow(entry) {
438
439                         return $(this.templateManager.get('callerCallItemRow', {
440                                 'cssClass': this.cssClassesForEntry(entry),
441                                 'callTime': entry.startTime.toLocaleTimeString(),
442                                 'callDuration': this.helpers.secondsToHours(entry.duration)
443                         })).data('entries', [entry]).get(0);
444                 },
445
446                 /**
447                  * Renders call log list for specified caller
448                  *
449                  * @param {string} remoteParty
450                  * @param {CallHistoryEntry[]} entries
451                  */
452                 showHistoryForCaller: function Ui_showHistoryForCaller(remoteParty, entries) {
453                         var pdate = '',
454                                 date = '',
455                                 elements = [],
456                                 len = entries.length,
457                                 i;
458
459                         if (len) {
460                                 this.updateCallerHeader(entries[0], entries.length);
461                         }
462
463                         $('#forCallerList')
464                                 .data('remoteParty', remoteParty)
465                                 .data('modified', false)
466                                 .empty();
467
468                         // group caller log entries by date
469                         for (i = 0; i < len; i = i + 1) {
470                                 date = entries[i].startTime.toLocaleDateString();
471
472                                 // if date is changed render new header
473                                 if (date !== pdate) {
474                                         elements.push($(this.templateManager.get('dateRow', {'date': date})).get(0));
475                                         pdate = date;
476                                 }
477                                 elements.push(this.getCallerCallLogRow(entries[i]));
478                         }
479
480                         $('#forCallerList')
481                                 .empty()
482                                 .append(elements);
483
484                         if (elements.length > 0) {
485                                 $('li#delete > a').addClass('ui-btn-active');
486                         } else {
487                                 $('li#delete > a').removeClass('ui-btn-active');
488                         }
489
490                         $('#forCallerList').trigger('create');
491
492                         this.addEventsForCallerListCheckboxes();
493                 },
494
495                 /**
496                  * Update accoundId
497                  * @param {string} accountId
498                  */
499                 updateCallerHeaderAccountId: function Ui_updateCallerHeaderAccountId(accountId) {
500                         $('.infoContainer .accountId').html(accountId);
501                 },
502
503                 /**
504                  * Update number of entries
505                  * @param numberOfEntries
506                  */
507                 updateCallerHeaderNumberOfEntries: function Ui_updateCallerHeaderNumberOfEntries(numberOfEntries) {
508                         $('.infoContainer .numberOfEntries').html(numberOfEntries);
509                 },
510
511                 /**
512                  * Updates caller main info
513                  * @param {CallHistoryEntry} entry
514                  * @param {number} numberOfEntries
515                  */
516                 updateCallerHeader: function Ui_updateCallerHeader(entry, numberOfEntries) {
517                         var name = '',
518                                 photoURIdefault = '../images/no_photo.png',
519                                 party,
520                                 imgPath;
521
522                         $('.infoContainer .photo').css('background-image', photoURIdefault);
523
524                         if (entry.remoteParties !== null) {
525                                 party = entry.remoteParties[0];
526                                 name = party.displayName || party.remoteParty;
527                                 if (party.displayName) {
528                                         this.updateCallerHeaderAccountId(party.remoteParty);
529                                 }
530                                 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
531
532                                 if (party.contactRef) {
533                                         imgPath = app.getPhotoURIForContact(party.contactRef.addressBookId, party.contactRef.contactId);
534                                         if (imgPath !== false) {
535                                                 $('.contact > .infoContainer > .photo').css('background-image', imgPath);
536                                         }
537                                 }
538                         } else if (entry.contactId !== null) {
539                                 name = entry.accountId;
540                                 this.updateCallerHeaderAccountId(entry.accountId);
541                                 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
542                         } else {
543                                 name = entry.accountId;
544                                 this.updateCallerHeaderAccountId('');
545                                 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
546                         }
547                         $('.contact > .infoContainer > .name').html(name);
548
549                 },
550
551                 /**
552                  * Remove search filter from content and appends it to header
553                  */
554                 removeSearchBarToHeader: function () {
555                         $('#page-content').css('top', '102px');
556                         $('#page-header')
557                                 .css('height', '102px')
558                                 .append($('#callView .ui-listview-filter'));
559                         $.mobile.activePage.page('refresh');
560                         $('.ui-input-cancel').remove(); // patch for WebUI bug;
561                 },
562
563                 /**
564                  * WORKAROUND;
565                  * Patch for UI, bad refresh scrollView
566                  */
567                 refreshScrollView: function () {
568                         var scrollView = $('.ui-scrollview-view'),
569                                 show = function () {
570                                         scrollView.show();
571                                 };
572                         scrollView.hide();
573                         setTimeout(show, 0);
574                 }
575         };
576
577 }());