2 /*global tizen, document, $, jQuery, app, UiPanel, UiContact, TemplateManager, window, Helpers */
8 function Ui(contacts) {
13 (function () { // strict mode wrapper
22 addressBook: tizen.contact.getDefaultAddressBook(),
24 photoURIdefault: null,
31 * @type {TemplateManager}
33 templateManager: null,
38 init: function Ui_init() {
40 this.templateManager = new TemplateManager();
41 this.helpers = new Helpers();
42 $(document).ready(this.domInit.bind(this));
43 $.mobile.tizen.disableSelection(document);
47 * When DOM is ready, initialise it (bind events)
49 domInit: function Ui_domInit() {
50 this.templateManager.loadToCache(['callView',
56 'dateRow'], this.initPages.bind(this));
60 * UI pages initializer
62 initPages: function Ui_initPages() {
63 var pages = [], body = $('body');
66 .append(this.templateManager.get('messageWindow'))
67 .append(this.templateManager.get('errorWindow'))
70 .append($(this.templateManager.get('callView'))
72 .trigger('pagecreate')
74 pages.push(this.templateManager.get('callerHistory'));
75 body.append(pages.join(''));
76 this.removeSearchBarToHeader();
79 app.showCallHistory();
81 this.photoURIdefault = $("#header .photo").css('background-image');
87 addEvents: function Ui_addEvents() {
90 $(window).on('resize', function () {
91 $.mobile.activePage.page('refresh');
94 $('#callView').on('pagebeforeshow', function () {
95 app.showCallHistory();
98 //original code, do not remove until web-ui release; N_SE-48946
99 //$(".ui-scrollview-view").listview();
101 $('#historyForCallerView').on('pagebeforeshow', function () {
102 self.hideCheckboxes();
103 $('#historyForCallerView .ui-content.ui-scrollview-clip .ui-scrollview-view')
104 .css('-webkit-transform', 'translate3d(0px, 0px, 0px)');
105 $('#selectAllDetails').on('change', function () {
110 $('#historyForCallerView').on('pageshow', function () {
111 $('#content').css('top', '160px');
112 $('#header').css('height', '160px');
113 $('#callerListContainer')
114 .children('.ui-overflow-indicator-top', '.ui-overflow-indicator-bottom')
118 $('#callerListContainer').on('scrollstart', function () {
120 .children('.ui-overflow-indicator-top', '.ui-overflow-indicator-bottom')
124 $('#callerListContainer').on('scrollstop', function () {
126 .children('.ui-overflow-indicator-top', '.ui-overflow-indicator-bottom')
130 $('.selectAllBox').children().on('click', function () {
131 $('.selectAllBox input[type=checkbox]').trigger('click');
133 self.selectAllDetailsEach();
136 $('#calllogList').on('tap', '.date', function (event) {
137 event.stopPropagation();
140 $('#calllogList').on('click', '.call', function onCalllogEntryClick(event) {
141 var remoteParty = $(this)
145 app.showHistoryForCaller(remoteParty);
146 $.mobile.changePage('#historyForCallerView');
149 $('#smsActionBtn').on('click', function (event) {
150 event.stopPropagation();
151 event.preventDefault();
153 self.hideCheckboxes();
154 app.sendSms($('#forCallerList').data('remoteParty'));
157 $('#callActionBtn').on("click", function (event) {
159 self.hideCheckboxes();
160 app.makeCall($('#forCallerList').data('remoteParty'));
163 $('#deleteActionBtn').on('click', function () {
164 self.changeDetailsToRemoveState();
167 $('.selectAllBox').on('click', 'li', function () {
168 var checkbox = $(this).find(':checkbox');
169 if (self.removeMode === true) {
170 if (checkbox.attr('checked')) {
171 checkbox.attr('checked', false)
172 .data('checkboxradio')
175 checkbox.attr('checked', true)
176 .data('checkboxradio')
179 self.setSelectAllDetails();
184 .on('click', '#popupCancelActionBtn', this.closePopup.bind(this))
185 .on('click', '#popupSubmitActionBtn', this.deleteCheckedLogs.bind(this));
187 $('#errorPopup').on('click', '#errorPopupOkBtn', this.closeErrorPopup);
189 $( "#errorPopup" ).bind({
190 popupafterclose: function(){
191 self.unlockOptionButtons();
195 $(window).keyup(function(e){
196 if (e.which === 13) {
197 $('input:focus').blur();
201 window.addEventListener('tizenhwkey', function(e) {
202 if (e.keyName == "back") {
203 if ($.mobile.popup.active) {
204 $.mobile.popup.active.close();
205 } else if (self.removeMode === true) {
206 app.ui.changeDetailsToRemoveState(undefined, true);
207 } else if ($.mobile.activePage.attr('id') === 'callView') {
208 tizen.application.getCurrentApplication().exit();
215 self.onVisibilityChange();
218 addEventsForCallerListCheckboxes: function Ui_addEventsForCallerListCheckboxes() {
220 $('#forCallerList :checkbox').on('change', function (event) {
221 if ($(this).attr('checked')) {
222 $(this).attr('checked', true);
224 $(this).attr('checked', false);
226 self.setSelectAllDetails();
230 selectAll: function () {
231 if ($('#selectAllDetails').attr('checked')) {
232 this.selectCheckbox($('#selectAllDetails'), true);
234 this.selectCheckbox($('#selectAllDetails'), false);
236 this.selectAllDetailsEach();
239 selectCheckbox: function (obj, state) {
240 var deleteButton = $('#deleteActionBtn'), numChecked;
241 obj.attr('checked', state)
242 .data('checkboxradio')
245 numChecked = $('#forCallerList input:checked').length;
246 if (this.removeMode && numChecked === 0 && !deleteButton.hasClass('ui-disabled')) {
247 deleteButton.addClass('ui-disabled').attr('tabIndex', '-1').blur();
248 } else if (deleteButton.hasClass('ui-disabled')) {
249 deleteButton.removeClass('ui-disabled').attr('tabIndex', '0');
254 * Returns number of selected call logs
255 * @return {number} length
257 getCountSelectedLogEntries: function Ui_getCountSelectedLogEntries() {
258 return $('#forCallerList li .toRemove label.ui-checkbox-on').length;
261 selectAllDetailsEach: function Ui_selectAllDetailsEach() {
263 $('#forCallerList').find('input').each(function () {
264 if ($('#selectAllDetails').attr('checked')) {
265 self.selectCheckbox($(this), true);
267 self.selectCheckbox($(this), false);
275 hideCheckboxes: function Ui_hideCheckboxes() {
277 this.selectCheckbox($('#selectAllDetails'), false);
279 $('#forCallerList').find('input').each(function () {
280 self.selectCheckbox($(this), false);
282 this.changeDetailsToRemoveState('hide');
286 * Returns css classes for specified entry
288 * @param {CallHistoryEntry} entry
291 cssClassesForEntry: function Ui_cssClassesForEntry(entry) {
292 return 'call dir_' + entry.direction.toLowerCase() + ' type_' + entry.type.replace('.', '-').toLowerCase();
295 setSelectAllDetails: function Ui_setSelectAllDetails() {
296 if ($('#forCallerList input[type="checkbox"]').length ===
297 $('#forCallerList input[checked="checked"]').length) {
298 this.selectCheckbox($('#selectAllDetails'), true);
300 this.selectCheckbox($('#selectAllDetails'), false);
305 * Shows popup with specified message
306 * @param {string} message
308 showPopup: function Ui_showPopup(message) {
309 $('#popupMessage').html(message);
310 $('#popup').popup('open', {'positionTo': 'window'});
316 closePopup: function Ui_closePopup() {
317 $('#popup').popup('close');
320 showErrorPopup: function Ui_showErrorPopup(message) {
321 $('#errorPopupMessage').html(message);
322 $('#errorPopup').popup('open', {'positionTo': 'window'});
325 closeErrorPopup: function Ui_closeErrorPopup() {
326 $('#errorPopup').popup('close');
330 * Deletes checked log entries
332 deleteCheckedLogs: function Ui_deleteCheckedLogs(e) {
335 this.selectCheckbox($('#selectAllDetails'), false);
337 $('#forCallerList li.call').each(function () {
338 if ($(this).find('form label').hasClass('ui-checkbox-on')) {
339 app.deleteLog($(this).data('entries')[0]);
344 if ($('#forCallerList li.call').length > 0) {
345 this.updateCallerHeaderNumberOfEntries($('#forCallerList li.call').length);
348 $('.ui-listview-filter .ui-input-text').val('');
349 $('.ui-listview-filter .ui-input-text').trigger('change');
350 $.mobile.changePage('#callView');
353 this.changeDetailsToRemoveState(true);
354 this.scrollToBottom();
357 changeDetailsToRemoveState: function Ui_changeDetailsToRemoveState(set, clear) {
358 var counter = this.getCountSelectedLogEntries(),
359 numChecked = $('#forCallerList input:checked').length;
360 if (clear === true) {
362 $('#forCallerList').find(':checkbox').attr('checked', false)
363 .data('checkboxradio').refresh();
364 $('.selectAllBox').find(':checkbox').attr('checked', false)
365 .data('checkboxradio').refresh();
367 if (set !== undefined) {
368 this.removeMode = false;
369 } else if (counter === 0) {
370 this.removeMode = !this.removeMode;
373 if (this.removeMode && numChecked === 0) {
374 $('#deleteActionBtn').addClass('ui-disabled').attr('tabIndex', '-1').blur();
375 } else if (!this.removeMode) {
376 $('#deleteActionBtn').removeClass('ui-disabled').attr('tabIndex', '0');
377 this.selectAllDetailsEach();
381 if (this.removeMode) {
382 $('#historyForCallerView .toRemove').removeClass('hidden');
383 $('#historyForCallerView .selectAllBox')
384 .removeClass('hidden');
386 $('#historyForCallerView .toRemove').addClass('hidden');
387 $('#historyForCallerView .selectAllBox').addClass('hidden');
389 } else if (counter > 1) {
390 this.showPopup('Are you sure you want to delete selected logs?');
392 this.showPopup('Are you sure you want to delete selected log?');
394 this.refreshScrollView();
398 * Renders call history list
400 * @param {CallHistoryEntry[]} callEntries
402 showCallHistory: function Ui_showCallHistory(callEntries) {
404 pdate = null, // previous date
406 elements = [], // list elements
407 len = callEntries.length, // entries length
408 tempLength = 0, // length of temporary table;
411 current, // current entry object
412 today = this.helpers.getShortDate(new Date()), // today short date
418 calllogList = $('#calllogList'),
419 calllogListContent = $('#calllogListContent'),
420 calllogListContentPos;
422 function filterForSameEntry(element) {
423 return self.getNumber(current) === self.getNumber(element)
424 && current.direction === element.direction;
427 $('.selectedCount').hide();
429 for (i = 0; i < len; i = i + 1) {
430 current = callEntries[i];
431 date = this.helpers.toNativeDate(current.startTime);
433 // if date is changed create new deyLog;
434 if (date !== pdate) {
438 dayLog.counters = [];
439 groupsOfDays.push(dayLog);
443 // group entries by remote Party;
444 filterResult = dayLog.entries.filter(filterForSameEntry);
445 if (filterResult.length) {
446 index = dayLog.entries.indexOf(filterResult[0]);
447 dayLog.counters[index] += 1;
449 dayLog.entries.push(current);
450 dayLog.counters[dayLog.entries.length - 1] = 1;
453 // Create UL list with dividers;
454 len = groupsOfDays.length;
455 for (i = 0; i < len; i += 1) {
456 dayLog = groupsOfDays[i];
457 tempLength = dayLog.entries.length;
458 entryShortDate = this.helpers.getShortDate(dayLog.entries[0].startTime);
460 //original code, do not remove until web-ui release; N_SE-48946
461 // elements.push($(this.templateManager.get('dateRow', {
462 // 'date': today === entryShortDate ? 'Today' : dayLog.date
465 for (j = 0; j < tempLength; j = j + 1) {
466 elements.push(this.getCallItemRow(dayLog.entries[j], dayLog.counters[j]));
469 calllogListContentPos = this.helpers.getScrollPosition(calllogListContent);
470 calllogList.empty().append(elements);
472 /* workaround solution for not auto refreshing list view*/
473 setTimeout(function () {
474 // original code, do not remove until web-ui release; N_SE-48946
475 calllogList.listview({
478 autodividersSelector: function ( li ) {
479 return $(li).find('.callDate').text() === app.ui.helpers.toNativeDate(new Date())
480 ? "Today" : $(li).find('.callDate').text();
482 }).listview('refresh');
483 $(".ui-li-divider").removeClass().addClass("date");
486 /* workaround for registering call during working app in removeMode */
487 if (this.removeMode) {
488 if ($('#selectAllDetails').attr('checked')){
491 $('.toRemove, .selectAllBox', $('#historyForCallerView'))
492 .removeClass('hidden');
493 $('#forCallerList .toRemove').show()
496 setTimeout(this.helpers.scrollTo.bind(this, calllogListContent, calllogListContentPos), 10);
500 * @param: {CallHistoryEntry} entry
502 getNumber: function (entry) {
503 return entry.remoteParties[0].remoteParty;
507 * Returns HTML for single log entry
509 * @param {CallHistoryEntry} entry
510 * @param {number} counter
511 * @returns {HTMLPartial}
513 getCallItemRow: function Ui_getCallItemRow(entry, counter) {
514 var party = entry.remoteParties[0],
515 name = this.getNameByNumber(party.remoteParty),
519 name += ' (' + counter + ')';
522 tpl = this.templateManager.get('callItemRow', {
524 'callTime': this.helpers.toNativeTime(entry.startTime),
525 'callDate': this.helpers.toNativeDate(entry.startTime),
526 'cssClasses': this.cssClassesForEntry(entry),
531 .data('remoteParty', entry.remoteParties[0].remoteParty)
532 .data('entries', [entry])
533 .get(0); // return clean DOM element so array of those could be appended at once*/
536 getNameByNumber: function (number) {
537 var i, j, contact, name;
538 for (i in this.contactsLoaded) {
539 if (this.contactsLoaded.hasOwnProperty(i)) {
540 contact = this.contactsLoaded[i];
541 for (j in contact.phoneNumbers) {
542 if (contact.phoneNumbers.hasOwnProperty(j)) {
543 if (contact.phoneNumbers[j].number.substr(-9)
544 === number.substr(-9)) {
545 name = contact.name.displayName;
552 return name || number || 'Unknown';
556 * Returns HTML for single caller log entry
558 * @param {CallHistoryEntry} entry
559 * @returns {HTMLElement}
561 getCallerCallLogRow: function Ui_getCallerCallLogRow(entry) {
562 return $(this.templateManager.get('callerCallItemRow', {
563 'cssClass': this.cssClassesForEntry(entry),
564 'callTime': this.helpers.toNativeTime(entry.startTime),
565 'callDuration': this.helpers.secondsToHours(entry.duration),
567 })).data('entries', [entry]).get(0);
571 * Renders call log list for specified caller
573 * @param {string} remoteParty
574 * @param {CallHistoryEntry[]} entries
576 showHistoryForCaller: function Ui_showHistoryForCaller(remoteParty, entries) {
580 len = entries.length,
585 this.updateCallerHeader(entries[0], entries.length);
587 // if last call log has been removed
588 this.removedLastLog();
589 this.app.lastViewedCaller = 0;
593 .data('remoteParty', remoteParty)
594 .data('modified', false)
597 // group caller log entries by date
598 for (i = 0; i < len; i = i + 1) {
599 date = this.helpers.toNativeDate(entries[i].startTime);
601 // if date is changed render new header
602 if (date !== pdate) {
603 elements.push($(this.templateManager.get('dateRow', {'date': date})).get(0));
606 elements.push(this.getCallerCallLogRow(entries[i]));
613 if (elements.length > 0) {
614 $('li#delete > a').addClass('ui-btn-active');
616 $('li#delete > a').removeClass('ui-btn-active');
619 $('#forCallerList').trigger('create');
621 // change to remove mode if it was active before registering call
622 if (this.removeMode) {
623 this.removeMode = !this.removeMode;
624 this.changeDetailsToRemoveState();
625 // check previous checked entries
626 this.checkedLogs.forEach(function(logUid){
627 checkbox = $('#forCallerList li.call[data-uid="' + logUid + '"]')
630 if (checkbox.length > 0) {
631 checkbox.attr('checked', true)
632 .data('checkboxradio')
634 $('#deleteActionBtn').removeClass('ui-disabled').attr('tabIndex', '0');
638 // close popup if there are no checked checkboxes
639 if (!$("#forCallerList input:checked").length) {
640 if ($.mobile.popup.active) {
641 $.mobile.popup.active.close();
645 this.addEventsForCallerListCheckboxes();
646 // lock buttons if unknown caller
648 this.unlockOptionButtons();
656 * @param {string} accountId
658 updateCallerHeaderAccountId: function Ui_updateCallerHeaderAccountId(accountId) {
659 $('.infoContainer .accountId').html(accountId);
663 * Update number of entries
664 * @param numberOfEntries
666 updateCallerHeaderNumberOfEntries: function Ui_updateCallerHeaderNumberOfEntries(numberOfEntries) {
667 $('.infoContainer .numberOfEntries').html(numberOfEntries);
671 * Updates caller main info
672 * @param {CallHistoryEntry} entry
673 * @param {number} numberOfEntries
675 updateCallerHeader: function Ui_updateCallerHeader(entry, numberOfEntries) {
676 var name = '', party, imgPath, personId;
678 $('#header .photo').css('background-image', this.photoURIdefault);
680 if (entry.remoteParties !== null) {
681 party = entry.remoteParties[0];
682 personId = parseInt(party.personId, 10);
683 name = this.getNameByNumber(party.remoteParty);
684 if (party.displayName) {
685 this.updateCallerHeaderAccountId(party.remoteParty);
687 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
688 if (personId !== 0) {
689 imgPath = app.getPhotoURIForContact(personId);
690 if (imgPath !== false) {
691 $('#header .photo').css('background-image', 'url(' + imgPath + ')');
694 } else if (entry.contactId !== null) {
695 name = entry.accountId;
696 this.updateCallerHeaderAccountId(entry.accountId);
697 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
699 name = entry.accountId;
700 this.updateCallerHeaderAccountId('');
701 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
703 $('.contact > .infoContainer > .name').html(this.templateManager.modifiers.escape(name));
707 loadContacts: function Model_loadContacts(callback) {
708 var contactsFoundCB, errorCB;
710 this.contactsLoaded = null;
712 contactsFoundCB = function (contacts) {
713 this.contactsLoaded = contacts;
714 if (callback instanceof Function) {
719 errorCB = function (error) {
720 console.error('Model_loadContacts, problem with find() method: ' + error.message);
723 this.addressBook.find(contactsFoundCB.bind(this), errorCB);
727 * Remove search filter from content and appends it to header
729 removeSearchBarToHeader: function () {
730 $('#page-header').append($('#callView .ui-listview-filter'));
731 $.mobile.activePage.page('refresh');
732 $('.ui-input-cancel').remove(); // patch for WebUI bug;
735 scrollToBottom: function () {
736 var scrollView = $(".ui-scrollview-view");
737 scrollView.css("-webkit-transform", "translate3d(0px, -" +
738 scrollView.height() + "px, 0px)");
741 onVisibilityChange: function () {
743 document.addEventListener('webkitvisibilitychange', function () {
744 if (document.webkitVisibilityState === 'hidden') {
745 self.checkedLogs = [];
746 $('#forCallerList li.call').each(function () {
747 if ($(this).find('form label')
748 .hasClass('ui-checkbox-on')) {
749 var checkedEntry = $(this).data('entries')[0];
750 self.checkedLogs.push(checkedEntry.uid);
754 self.loadContacts(app.updateCallLists.bind(app));
755 $('#callActionBtn, #smsActionBtn')
756 .removeClass('ui-disabled').attr('tabIndex', '0');
761 lockButtons: function () {
762 $('#callActionBtn, #smsActionBtn').addClass('ui-disabled').attr('tabIndex', '-1').blur();
765 unlockOptionButtons : function Ui_unlockOptionButtons(){
766 $('#callActionBtn, #smsActionBtn').removeClass('ui-disabled').attr('tabIndex', '0');
771 * Patch for UI, bad refresh scrollView
773 refreshScrollView: function () {
774 var scrollView = $('.ui-scrollview-view'),
782 removedLastLog: function () {
783 this.hideCheckboxes();
784 $(".ui-popup").popup('close');
785 $.mobile.changePage('#callView');