483675fdbf066f4fe34b8dcc024c8a03293dae47
[apps/web/sample/CallLog.git] / project / js / app.ui.js
1 /*
2 *      Copyright 2013  Samsung Electronics Co., Ltd
3 *
4 *      Licensed under the Flora License, Version 1.1 (the "License");
5 *      you may not use this file except in compliance with the License.
6 *      You may obtain a copy of the License at
7 *
8 *              http://floralicense.org/license/
9 *
10 *      Unless required by applicable law or agreed to in writing, software
11 *      distributed under the License is distributed on an "AS IS" BASIS,
12 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *      See the License for the specific language governing permissions and
14 *      limitations under the License.
15 */
16
17 /*jslint devel: true*/
18 /*global tizen, document, $, jQuery, app, UiPanel, UiContact, TemplateManager, window, Helpers */
19
20 /**
21 * @class Ui
22 */
23 function Ui(contacts) {
24     'use strict';
25     this.init();
26 }
27
28 (function () { // strict mode wrapper
29     'use strict';
30
31     Ui.prototype = {
32
33         /**
34         * UI remove mode
35         * @type {boolean}
36         */
37         removeMode: false,
38
39         /**
40          * Default tizen address book
41          * @type {AddressBook}
42          */
43         addressBook: tizen.contact.getDefaultAddressBook(),
44
45         /**
46          * Default photo uri
47          * @type {String}
48          */
49         photoURIdefault: null,
50
51         /**
52          * Cached contacts from address book
53          * @type {Array}
54          */
55         contactsLoaded: null,
56
57         /**
58          * identifiers of currently checked checkboxes
59          * @type {Array}
60          */
61         checkedLogs: [],
62
63         /**
64         * @type {TemplateManager}
65         */
66         templateManager: null,
67
68         /**
69         * UI Initializer
70         */
71         init: function Ui_init() {
72             this.loadContacts();
73             this.templateManager = new TemplateManager();
74             this.helpers = new Helpers();
75             $(document).ready(this.domInit.bind(this));
76             $.mobile.tizen.disableSelection(document);
77         },
78
79         /**
80         * When DOM is ready, initialise it (bind events)
81         */
82         domInit: function Ui_domInit() {
83             this.templateManager.loadToCache(['callView',
84                 'callerHistory',
85                 'callItemRow',
86                 'callerCallItemRow',
87                 'messageWindow',
88                 'errorWindow',
89                 'dateRow'], this.initPages.bind(this));
90         },
91
92         /**
93         * UI pages initializer
94         */
95         initPages: function Ui_initPages() {
96             var pages = [], body = $('body');
97
98             body
99                 .append(this.templateManager.get('messageWindow'))
100                 .append(this.templateManager.get('errorWindow'))
101                 .trigger('create');
102             $('#callView')
103                 .append(
104                     $(this.templateManager.get('callView')).children()
105                 )
106                 .trigger('pagecreate')
107                 .trigger('pageshow');
108             pages.push(this.templateManager.get('callerHistory'));
109             body.append(pages.join(''));
110             this.removeSearchBarToHeader();
111
112             this.addEvents();
113             app.showCallHistory();
114
115             this.photoURIdefault = $("#header .photo").css('background-image');
116         },
117
118         /**
119         * Add UI events
120         */
121         addEvents: function Ui_addEvents() {
122             var self = this;
123
124             // recalculating page size when window resize
125             // (eg. when soft keybord appear)
126             $(window).on('resize', function () {
127                 $.mobile.activePage.page('refresh');
128             });
129
130             // creating call history view
131             $('#callView').on('pagebeforeshow', function () {
132                 app.showCallHistory();
133             });
134
135             // creating single contact history view
136             $('#historyForCallerView').on('pagebeforeshow', function () {
137                 self.hideCheckboxes();
138                 // move scrollbar to top
139                 $('#historyForCallerView')
140                     .find('.ui-content.ui-scrollview-clip')
141                     .find('.ui-scrollview-view')
142                     .css('-webkit-transform', 'translate3d(0px, 0px, 0px)');
143                 $('#selectAllDetails').on('change', function () {
144                     self.selectAll();
145                 });
146             });
147
148
149             // HACK not dissapearing scrollview indicator
150             $('#historyForCallerView').on('pageshow', function () {
151                 $('#content').css('top', '160px');
152                 $('#header').css('height', '160px');
153                 $('#callerListContainer')
154                     .children(
155                         '.ui-overflow-indicator-top',
156                         '.ui-overflow-indicator-bottom'
157                     ).hide();
158             });
159
160             // HACK not dissapearing scrollview indicator
161             $('#callerListContainer').on('scrollstart', function () {
162                 $(this)
163                     .children(
164                         '.ui-overflow-indicator-top',
165                         '.ui-overflow-indicator-bottom'
166                     ).fadeIn(200);
167             });
168
169             // HACK not dissapearing scrollview indicator
170             $('#callerListContainer').on('scrollstop', function () {
171                 $(this)
172                     .children(
173                         '.ui-overflow-indicator-top',
174                         '.ui-overflow-indicator-bottom'
175                     ).fadeOut(200);
176             });
177
178             // selecting all checkboxes
179             $('.selectAllBox').children().on('click', function () {
180                 $('.selectAllBox input[type=checkbox]').trigger('click');
181                 self.selectAll();
182                 self.selectAllDetailsEach();
183             });
184
185             $('#calllogList').on('click', '.date', function (event) {
186                 event.stopPropagation();
187             });
188
189             // when clicked on a log display all history from that contact
190             $('#calllogList').on(
191                 'click keypress',
192                 '.call',
193                 function onCalllogEntryClick(event) {
194                     if (event.type === 'keypress' && event.keyCode !== 13) {
195                         return;
196                     }
197                     var remoteParty = $(this)
198                         .data('entries')[0]
199                         .remoteParties[0]
200                         .remoteParty;
201                     app.showHistoryForCaller(remoteParty);
202                     $.mobile.changePage('#historyForCallerView');
203                 }
204             );
205
206             // run sms service on click
207             $('#smsActionBtn').on('click', function (event) {
208                 event.stopPropagation();
209                 event.preventDefault();
210                 self.lockButtons('#smsActionBtn, #callActionBtn');
211                 self.hideCheckboxes();
212                 self.lockButtons('#deleteActionBtn');
213                 app.sendSms($('#forCallerList').data('remoteParty'));
214             });
215
216             // run call service on btn click
217             $('#callActionBtn').on("click", function (event) {
218                 self.lockButtons('#callActionBtn, #smsActionBtn');
219                 self.hideCheckboxes();
220                 self.lockButtons('#deleteActionBtn');
221                 app.makeCall($('#forCallerList').data('remoteParty'));
222             });
223
224             $('#deleteActionBtn').on('click', function () {
225                 self.changeDetailsToRemoveState();
226             });
227
228             // selecting all checkboxes
229             $('.selectAllBox').on('click', 'li', function () {
230                 var checkbox = $(this).find(':checkbox');
231                 if (self.removeMode === true) {
232                     if (checkbox.attr('checked')) {
233                         checkbox.attr('checked', false)
234                             .data('checkboxradio')
235                             .refresh();
236                     } else {
237                         checkbox.attr('checked', true)
238                             .data('checkboxradio')
239                             .refresh();
240                     }
241                     self.setSelectAllDetails();
242                 }
243             });
244
245             $('#popup')
246                 .on(
247                     'click',
248                     '#popupCancelActionBtn',
249                     this.closePopup.bind(this)
250                 ).on(
251                     'click',
252                     '#popupSubmitActionBtn',
253                     this.deleteCheckedLogs.bind(this)
254                 );
255
256             $('#errorPopup').on(
257                 'click',
258                 '#errorPopupOkBtn',
259                 this.closeErrorPopup
260             );
261
262             $('#errorPopup').bind(
263                 {
264                     popupafterclose: function () {
265                         self.unlockButtons();
266                     }
267                 }
268             );
269
270             $(window).keyup(function (e) {
271                 if (e.which === 13) {
272                     $('input:focus').blur();
273                 }
274             });
275
276             // bind hardware back button
277             window.addEventListener('tizenhwkey', function (e) {
278                 if (e.keyName === "back") {
279                     // if there is any popup close it
280                     if ($.mobile.popup.active) {
281                         $.mobile.popup.active.close();
282                     // if app is in remove mode close it
283                     } else if (self.removeMode === true) {
284                         app.ui.changeDetailsToRemoveState(undefined, true);
285                     // if app is on calls page close app
286                     } else if ($.mobile.activePage.attr('id') === 'callView') {
287                         tizen.application.getCurrentApplication().exit();
288                     // else back to calls page
289                     } else {
290                         history.back();
291                     }
292                 }
293             });
294             // bind callback to visbility change event
295             self.onVisibilityChange();
296         },
297
298         /**
299          * Bind change event
300          */
301         addEventsForCallerListCheckboxes:
302             function Ui_addEventsForCallerListCheckboxes() {
303             var self = this;
304             $('#forCallerList :checkbox').on('change', function (event) {
305                 if ($(this).attr('checked')) {
306                     $(this).attr('checked', true);
307                 } else {
308                     $(this).attr('checked', false);
309                 }
310                 self.setSelectAllDetails();
311             });
312         },
313
314         /**
315          * Callback function for click on select all element
316          */
317         selectAll: function () {
318             // if select all checkbox is checked
319             if ($('#selectAllDetails').attr('checked')) {
320                 this.selectCheckbox($('#selectAllDetails'), true);
321             } else {
322                 this.selectCheckbox($('#selectAllDetails'), false);
323             }
324             // select each checkbox separatly
325             this.selectAllDetailsEach();
326         },
327
328         /**
329          * Select single checkbox and enable delete button
330          */
331         selectCheckbox: function (obj, state) {
332             var deleteButton = $('#deleteActionBtn'), numChecked;
333             // check checkbox and refresh its view
334             obj.attr('checked', state)
335                 .data('checkboxradio')
336                 .refresh();
337
338             // check if there is any checked checkbox
339             // and toggle delete button availability
340             numChecked = $('#forCallerList input:checked').length;
341             if (this.removeMode && numChecked === 0) {
342                 deleteButton
343                     .addClass('ui-disabled')
344                     .attr('tabIndex', '-1')
345                     .blur();
346             } else if (deleteButton.hasClass('ui-disabled')) {
347                 deleteButton
348                     .removeClass('ui-disabled')
349                     .attr('tabIndex', '0');
350             }
351         },
352
353         /**
354         * Returns number of selected call logs
355         * @return {number} length
356         */
357         getCountSelectedLogEntries: function Ui_getCountSelectedLogEntries() {
358             return $('#forCallerList li .toRemove label.ui-checkbox-on').length;
359         },
360
361         /**
362          * Select each checkbox separatly
363          */
364         selectAllDetailsEach: function Ui_selectAllDetailsEach() {
365             var self = this;
366             $('#forCallerList').find('input').each(function () {
367                 if ($('#selectAllDetails').attr('checked')) {
368                     self.selectCheckbox($(this), true);
369                 } else {
370                     self.selectCheckbox($(this), false);
371                 }
372             });
373         },
374
375         /**
376         * Hides checkboxes
377         */
378         hideCheckboxes: function Ui_hideCheckboxes() {
379             var self = this;
380             this.selectCheckbox($('#selectAllDetails'), false);
381
382             $('#forCallerList').find('input').each(function () {
383                 self.selectCheckbox($(this), false);
384             });
385             this.changeDetailsToRemoveState('hide');
386         },
387
388         /**
389         * Returns css classes for specified entry
390         *
391         * @param {CallHistoryEntry} entry
392         * @returns {string}
393         */
394         cssClassesForEntry: function Ui_cssClassesForEntry(entry) {
395             return 'call dir_' +
396                 entry.direction.toLowerCase() +
397                 ' type_' +
398                 entry.type.replace('.', '-').toLowerCase();
399         },
400
401         /**
402          * Check if all details checkboxes are selected
403          * and if so check selectAll element
404          */
405         setSelectAllDetails: function Ui_setSelectAllDetails() {
406             if (
407                 $('#forCallerList input[type="checkbox"]').length ===
408                     $('#forCallerList input[checked="checked"]').length
409             ) {
410                 this.selectCheckbox($('#selectAllDetails'), true);
411             } else {
412                 this.selectCheckbox($('#selectAllDetails'), false);
413             }
414         },
415
416         /**
417         * Shows popup with specified message
418         * @param {string} message
419         */
420         showPopup: function Ui_showPopup(message) {
421             $('#popupMessage').html(message);
422             $('#popup').popup('open', {'positionTo': 'window'});
423         },
424
425         /**
426         * Hides popup
427         */
428         closePopup: function Ui_closePopup() {
429             $('#popup').popup('close');
430         },
431
432         /**
433          * Display error popup
434          */
435         showErrorPopup: function Ui_showErrorPopup(message) {
436             $('#errorPopupMessage').html(message);
437             $('#errorPopup').popup('open', {'positionTo': 'window'});
438         },
439
440         /**
441          * Hides error popup
442          */
443         closeErrorPopup: function Ui_closeErrorPopup() {
444             $('#errorPopup').popup('close');
445         },
446
447         /**
448         * Deletes checked log entries
449         */
450         deleteCheckedLogs: function Ui_deleteCheckedLogs(e) {
451             // if there is popup open close it
452             this.closePopup();
453
454             // uncheck SelectAll checkbox
455             this.selectCheckbox($('#selectAllDetails'), false);
456
457             // iterate through all entries
458             $('#forCallerList li.call').each(function () {
459                 // if entry contains selected checkbox
460                 if ($(this).find('form label').hasClass('ui-checkbox-on')) {
461                     // remove that entry
462                     app.deleteLog($(this).data('entries')[0]);
463                     // and remove connected html element
464                     $(this).remove();
465                 }
466             });
467
468             // if there are still some entries
469             if ($('#forCallerList li.call').length > 0) {
470                 // update header info
471                 this.updateCallerHeaderNumberOfEntries(
472                     $('#forCallerList li.call').length
473                 );
474             } else {
475                 // if no entries change page
476                 e.preventDefault();
477                 $('.ui-listview-filter .ui-input-text').val('');
478                 $('.ui-listview-filter .ui-input-text').trigger('change');
479                 $.mobile.changePage('#callView');
480             }
481
482             this.changeDetailsToRemoveState(true);
483             this.scrollToBottom();
484         },
485
486         /**
487          * TODO Dont really know what that method exacly doing
488          * and what should do
489          * TODO need refactor
490          */
491         changeDetailsToRemoveState: function Ui_changeDetailsToRemoveState(
492             set,
493             clear
494         ) {
495             var counter = this.getCountSelectedLogEntries(),
496                 numChecked = $('#forCallerList input:checked').length,
497                 matrix,
498                 pos;
499             if (clear === true) {
500                 counter = 0;
501                 // uncheck all checkboxes
502                 $('#forCallerList').find(':checkbox').attr('checked', false)
503                     .data('checkboxradio').refresh();
504                 $('.selectAllBox').find(':checkbox').attr('checked', false)
505                     .data('checkboxradio').refresh();
506             }
507             // TODO it is hard ot understand this
508             if (set !== undefined) {
509                 this.removeMode = false;
510             } else if (counter === 0) {
511                 this.removeMode = !this.removeMode;
512             }
513
514             // if app is in remove mode and there are no selected checkboxes
515             if (this.removeMode && numChecked === 0) {
516                 // disable delete button
517                 $('#deleteActionBtn')
518                     .addClass('ui-disabled')
519                     .attr('tabIndex', '-1')
520                     .blur();
521             // if app is not in removeMode
522             } else if (!this.removeMode) {
523                 // set delete button to enabled
524                 $('#deleteActionBtn')
525                     .removeClass('ui-disabled')
526                     .attr('tabIndex', '0');
527                 this.selectAllDetailsEach();
528             }
529
530             // if there are no selected entries
531             if (counter === 0) {
532                 // again checking removeMode
533                 if (this.removeMode) {
534                     // show buttons from remove mode
535                     $('#historyForCallerView .toRemove').removeClass('hidden');
536                     $('#historyForCallerView .selectAllBox')
537                         .removeClass('hidden');
538                 } else {
539                     $('#historyForCallerView .toRemove').addClass('hidden');
540                     $('#historyForCallerView .selectAllBox').addClass('hidden');
541                 }
542             } else {
543                 // TODO I dont understand
544                 this.showPopup(
545                     counter > 1 ?
546                         'Are you sure you want to delete selected logs?' :
547                         'Are you sure you want to delete selected log?'
548                 );
549             }
550
551             // TODO need refactorin
552             // HACK probably scrollview hack
553             matrix =
554                 $('#historyForCallerView .ui-scrollview-view')
555                 .css('transform');
556             pos = matrix.substr(7, matrix.length - 8).split(',')[5];
557             if (pos !== undefined) {
558                 $('#callerListContainer')
559                     .scrollview('scrollTo', 100, parseInt(pos, 10), 10);
560             } else {
561                 this.refreshScrollView();
562             }
563         },
564
565         /**
566         * Renders call history list
567         *
568         * @param {CallHistoryEntry[]} callEntries
569         */
570         showCallHistory: function Ui_showCallHistory(callEntries) {
571             var self = this,
572                 pdate = null, // previous date
573                 date = '',
574                 elements = [], // list elements
575                 len = callEntries.length, // entries length
576                 tempLength = 0, // length of temporary table;
577                 i, // loop counter
578                 j, // loop counter
579                 current, // current entry object
580                 today = this.helpers.getShortDate(new Date()),
581                 entryShortDate,
582                 filterResult,
583                 groupsOfDays = [],
584                 dayLog,
585                 index = 0,
586                 calllogList = $('#calllogList'),
587                 calllogListContent = $('#calllogListContent'),
588                 calllogListContentPos;
589
590             // return duplicated entries
591             function filterForSameEntry(element) {
592                 return self.getNumber(current) === self.getNumber(element)
593                     && current.direction === element.direction;
594             }
595
596             $('.selectedCount').hide();
597
598             for (i = 0; i < len; i = i + 1) {
599                 current = callEntries[i];
600                 date = this.helpers.toNativeDate(current.startTime);
601
602                 // if date is changed create new deyLog;
603                 if (date !== pdate) {
604                     dayLog = {};
605                     dayLog.date = date;
606                     dayLog.entries = [];
607                     dayLog.counters = [];
608                     groupsOfDays.push(dayLog);
609                     pdate = date;
610                 }
611
612                 // group entries by remote Party;
613                 filterResult = dayLog.entries.filter(filterForSameEntry);
614                 if (filterResult.length) {
615                     index = dayLog.entries.indexOf(filterResult[0]);
616                     dayLog.counters[index] += 1;
617                 } else {
618                     dayLog.entries.push(current);
619                     dayLog.counters[dayLog.entries.length - 1] = 1;
620                 }
621             }
622             // Create UL list with dividers;
623             len = groupsOfDays.length;
624             for (i = 0; i < len; i += 1) {
625                 dayLog = groupsOfDays[i];
626                 tempLength = dayLog.entries.length;
627                 entryShortDate = this.helpers.getShortDate(
628                     dayLog.entries[0].startTime
629                 );
630                 for (j = 0; j < tempLength; j = j + 1) {
631                     elements.push(
632                         this.getCallItemRow(
633                             dayLog.entries[j],
634                             dayLog.counters[j]
635                         )
636                     );
637                 }
638             }
639             calllogListContentPos = this.helpers.getScrollPosition(
640                 calllogListContent
641             );
642             calllogList.empty().append(elements);
643
644             //workaround solution for searching phrase remain
645             // TODO FIXME
646             if ($("[data-type='search']").val().length !== "") {
647                 calllogList.listview('refresh');
648                 $("[data-type='search']").trigger("keyup");
649                 $(".ui-li-divider")
650                     .removeClass("ui-li ui-li-divider ui-bar-s")
651                     .addClass("date");
652             } else {
653                 calllogList.listview({
654                     autodividers: true,
655                     //filter: true,
656                     autodividersSelector: function (li) {
657                         return $(li).find('.callDate').text() ===
658                             app.ui.helpers.toNativeDate(new Date()) ?
659                             "Today" : $(li).find('.callDate').text();
660                     }
661                 }).listview('refresh');
662                 $(".ui-li-divider").removeClass().addClass("date");
663             }
664
665             setTimeout(
666                 this.helpers.scrollTo.bind(
667                     this,
668                     calllogListContent,
669                     calllogListContentPos
670                 ),
671                 10
672             );
673         },
674
675         /**
676         * @param: {CallHistoryEntry} entry
677         */
678         getNumber: function (entry) {
679             return entry.remoteParties[0].remoteParty;
680         },
681
682         /**
683         * Returns HTML for single log entry
684         *
685         * @param {CallHistoryEntry} entry
686         * @param {number} counter
687         * @returns {HTMLPartial}
688         */
689         getCallItemRow: function Ui_getCallItemRow(entry, counter) {
690             var party = entry.remoteParties[0],
691                 name = this.getNameByNumber(party.remoteParty),
692                 tpl;
693
694             if (counter > 1) {
695                 name += ' (' + counter + ')';
696             }
697
698             // prepare html string
699             tpl = this.templateManager.get('callItemRow', {
700                 'name': name,
701                 'callTime': this.helpers.toNativeTime(entry.startTime),
702                 'callDate': this.helpers.toNativeDate(entry.startTime),
703                 'cssClasses': this.cssClassesForEntry(entry),
704                 'uid': entry.uid
705             });
706
707             // return clean DOM element so that array of those could be appended
708             // at once
709             return $(tpl)
710                 .data('remoteParty', entry.remoteParties[0].remoteParty)
711                 .data('entries', [entry])
712                 .get(0); 
713         },
714
715         /**
716          * Return readable number identifier
717          *
718          * @param {string} number
719          * @returns {string}
720          */
721         getNameByNumber: function (number) {
722             var i, j, contact, name;
723             // iterate through loaded contacts
724             for (i in this.contactsLoaded) {
725                 if (this.contactsLoaded.hasOwnProperty(i)) {
726                     contact = this.contactsLoaded[i];
727                     // iterate through numbers of contact
728                     for (j in contact.phoneNumbers) {
729                         if (contact.phoneNumbers.hasOwnProperty(j)) {
730                             // check if first 9 characters match number
731                             if (contact.phoneNumbers[j].number.substr(-9)
732                                     === number.substr(-9)) {
733                                 // get display name
734                                 name = contact.name.displayName;
735                                 break;
736                             }
737                         }
738                     }
739                 }
740             }
741             return name || number || 'Unknown';
742         },
743
744         /**
745         * Returns HTML for single caller log entry
746         *
747         * @param {CallHistoryEntry} entry
748         * @returns {HTMLElement}
749         */
750         getCallerCallLogRow: function Ui_getCallerCallLogRow(entry) {
751             return $(this.templateManager.get('callerCallItemRow', {
752                 'cssClass': this.cssClassesForEntry(entry),
753                 'callTime': this.helpers.toNativeTime(entry.startTime),
754                 'callDuration': this.helpers.secondsToHours(entry.duration),
755                 'uid': entry.uid
756             })).data('entries', [entry]).get(0);
757         },
758
759         /**
760         * Renders call log list for specified caller
761         * TODO that methods is too long!
762         *
763         * @param {string} remoteParty
764         * @param {CallHistoryEntry[]} entries
765         */
766         showHistoryForCaller: function Ui_showHistoryForCaller(
767             remoteParty,
768             entries
769         ) {
770             var pdate = '', // previous data
771                 date = '',
772                 elements = [],
773                 len = entries.length, // number of entries
774                 i,
775                 checkbox;
776
777             if (len) {
778                 this.updateCallerHeader(entries[0], entries.length);
779             } else {
780                 // if last call log has been removed
781                 this.removedLastLog();
782                 this.app.lastViewedCaller = 0;
783             }
784
785             // clean the list
786             $('#forCallerList')
787                 .data('remoteParty', remoteParty)
788                 .data('modified', false)
789                 .empty();
790
791             // group caller log entries by date
792             for (i = 0; i < len; i = i + 1) {
793                 date = this.helpers.toNativeDate(entries[i].startTime);
794
795                 // if date is changed render new header
796                 if (date !== pdate) {
797                     elements.push(
798                         $(this.templateManager.get(
799                             'dateRow',
800                             {'date': date}
801                         )).get(0)
802                     );
803                     pdate = date;
804                 }
805                 elements.push(this.getCallerCallLogRow(entries[i]));
806             }
807
808             $('#forCallerList')
809                 .empty()
810                 .append(elements);
811
812             // set state of delete button
813             if (elements.length > 0) {
814                 $('li#delete > a').addClass('ui-btn-active');
815             } else {
816                 $('li#delete > a').removeClass('ui-btn-active');
817             }
818
819             $('#forCallerList').trigger('create');
820
821             // change to remove mode if it was active before registering call
822             if (this.removeMode) {
823                 this.removeMode = !this.removeMode;
824                 this.changeDetailsToRemoveState();
825                 // check previous checked entries
826                 this.checkedLogs.forEach(function (logUid) {
827                     checkbox =
828                         $('#forCallerList li.call[data-uid="' + logUid + '"]')
829                         .find(':checkbox');
830                     if (checkbox.length > 0) {
831                         checkbox.attr('checked', true)
832                             .data('checkboxradio')
833                             .refresh();
834                         $('#deleteActionBtn')
835                             .removeClass('ui-disabled')
836                             .attr('tabIndex', '0');
837                     }
838                 });
839
840                 this.setSelectAllDetails();
841
842                 // close popup if there are no checked checkboxes
843                 if (!$("#forCallerList input:checked").length) {
844                     if ($.mobile.popup.active) {
845                         $.mobile.popup.active.close();
846                     }
847                 }
848             }
849             this.addEventsForCallerListCheckboxes();
850             // lock buttons if unknown caller
851             if (remoteParty) {
852                 this.unlockButtons();
853             } else {
854                 this.lockButtons(
855                     '#callActionBtn, #smsActionBtn, #deleteActionBtn'
856                 );
857             }
858         },
859
860         /**
861         * Update accoundId
862         * @param {string} accountId
863         */
864         updateCallerHeaderAccountId: function Ui_updateCallerHeaderAccountId(
865             accountId
866         ) {
867             $('.infoContainer .accountId').html(accountId);
868         },
869
870         /**
871         * Update number of entries
872         * @param numberOfEntries
873         */
874         updateCallerHeaderNumberOfEntries:
875             function Ui_updateCallerHeaderNumberOfEntries(numberOfEntries) {
876             $('.infoContainer .numberOfEntries').html(
877                 numberOfEntries +
878                     ' ' +
879                     (numberOfEntries === 1 ? 'call' : 'calls')
880             );
881         },
882
883         /**
884         * Updates caller main info
885         * @param {CallHistoryEntry} entry
886         * @param {number} numberOfEntries
887         */
888         updateCallerHeader: function Ui_updateCallerHeader(
889             entry,
890             numberOfEntries
891         ) {
892             // TODO need to refactor
893             // looks complicated
894             var name = '', party, imgPath, personId;
895
896             $('#header .photo').css('background-image', this.photoURIdefault);
897
898             if (entry.remoteParties !== null) {
899                 party = entry.remoteParties[0];
900                 personId = parseInt(party.personId, 10);
901                 name = this.getNameByNumber(party.remoteParty);
902                 if (party.displayName) {
903                     this.updateCallerHeaderAccountId(party.remoteParty);
904                 }
905                 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
906                 if (personId !== 0) {
907                     imgPath = app.getPhotoURIForContact(personId);
908                     if (imgPath !== false) {
909                         $('#header .photo')
910                             .css('background-image', 'url(' + imgPath + ')');
911                     }
912                 }
913             } else if (entry.contactId !== null) {
914                 name = entry.accountId;
915                 this.updateCallerHeaderAccountId(entry.accountId);
916                 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
917             } else {
918                 name = entry.accountId;
919                 this.updateCallerHeaderAccountId('');
920                 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
921             }
922             $('.contact > .infoContainer > .name').html(
923                 this.templateManager.modifiers.escape(name)
924             );
925         },
926
927         // TODO FIXME why that method is in the UI ?
928         loadContacts: function Model_loadContacts(callback) {
929             var contactsFoundCB, errorCB;
930
931             this.contactsLoaded = null;
932
933             contactsFoundCB = function (contacts) {
934                 this.contactsLoaded = contacts;
935                 if (callback instanceof Function) {
936                     callback();
937                 }
938             };
939
940             errorCB = function (error) {
941                 console.error(
942                     'Model_loadContacts, problem with find() method: ' +
943                         error.message
944                 );
945             };
946
947             this.addressBook.find(contactsFoundCB.bind(this), errorCB);
948         },
949
950         /**
951         * Remove search filter from content and appends it to header
952         */
953         // TODO FIXME HACK it is one big hack for web-ui-fw
954         // title need to be changed
955         removeSearchBarToHeader: function () {
956             $('#page-header').append($('#callView .ui-listview-filter'));
957             $.mobile.activePage.page('refresh');
958             $('.ui-input-cancel').remove(); // patch for WebUI bug
959             $('#calllogListContent').trigger('resize'); // WebUi scrollview fix
960         },
961
962         /**
963          * Scroll to bottom
964          */
965         scrollToBottom: function () {
966             var scrollView = $(".ui-scrollview-view");
967             scrollView.css("-webkit-transform", "translate3d(0px, -" +
968                         scrollView.height() + "px, 0px)");
969         },
970
971         /**
972          * Binding visibility state change event
973          */
974         onVisibilityChange: function () {
975             var self = this;
976             document.addEventListener('webkitvisibilitychange', function () {
977                 if (document.webkitVisibilityState === 'hidden') {
978                     self.updateCheckboxes();
979                 } else {
980                     self.loadContacts(app.updateCallLists.bind(app));
981                     $('#callActionBtn, #smsActionBtn')
982                         .removeClass('ui-disabled');
983                 }
984             });
985         },
986
987         /**
988          * Store uid of checked entries in checkedLogs Array
989          */
990         updateCheckboxes: function Ui_updateCheckboxes() {
991             // empty checkedLogs logs array
992             var checkedLogs = this.checkedLogs = [];
993             // iterate through the entries
994             $('#forCallerList li.call').each(function () {
995                 // if entry cotains checked checkbox
996                 if ($(this).find('form label').hasClass('ui-checkbox-on')) {
997                     var checkedEntry = $(this).data('entries')[0];
998                     // push the entry uid to checkedLogs array
999                     checkedLogs.push(checkedEntry.uid);
1000                 }
1001             });
1002         },
1003
1004         /**
1005          * Disabling element
1006          * @param {jQuery} element
1007          */
1008         lockButtons: function Ui_lockButtons(buttons) {
1009             $(buttons).addClass('ui-disabled').attr('tabIndex', '-1').blur();
1010         },
1011
1012         /**
1013          * Enabling element
1014          * @param {jQuery} element
1015          */
1016         unlockButtons: function Ui_unlockButtons() {
1017             $('#callActionBtn, #smsActionBtn, #deleteActionBtn')
1018                 .removeClass('ui-disabled')
1019                 .attr('tabIndex', '0');
1020         },
1021
1022         /**
1023         * HACK TODO FIXME;
1024         * Patch for UI, bad refresh scrollView
1025         */
1026         refreshScrollView: function () {
1027             var scrollView = $('.ui-scrollview-view'),
1028                 show = function () {
1029                     scrollView.show();
1030                 };
1031             scrollView.hide();
1032             setTimeout(show, 0);
1033         },
1034
1035         /**
1036          * Handle event when last log is removed
1037          */
1038         removedLastLog: function () {
1039             this.hideCheckboxes();
1040             $(".ui-popup").popup('close');
1041             $.mobile.changePage('#callView');
1042         }
1043     };
1044
1045 }());