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('click', '.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();
152 self.lockButtons('#smsActionBtn');
153 self.hideCheckboxes();
154 app.sendSms($('#forCallerList').data('remoteParty'));
157 $('#callActionBtn').on("click", function (event) {
158 self.lockButtons('#callActionBtn');
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.unlockButtons();
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();
214 self.onVisibilityChange();
217 addEventsForCallerListCheckboxes: function Ui_addEventsForCallerListCheckboxes() {
219 $('#forCallerList :checkbox').on('change', function (event) {
220 if ($(this).attr('checked')) {
221 $(this).attr('checked', true);
223 $(this).attr('checked', false);
225 self.setSelectAllDetails();
229 selectAll: function () {
230 if ($('#selectAllDetails').attr('checked')) {
231 this.selectCheckbox($('#selectAllDetails'), true);
233 this.selectCheckbox($('#selectAllDetails'), false);
235 this.selectAllDetailsEach();
238 selectCheckbox: function (obj, state) {
239 var deleteButton = $('#deleteActionBtn'), numChecked;
240 obj.attr('checked', state)
241 .data('checkboxradio')
244 numChecked = $('#forCallerList input:checked').length;
245 if (this.removeMode && numChecked === 0 && !deleteButton.hasClass('ui-disabled')) {
246 deleteButton.addClass('ui-disabled').attr('tabIndex', '-1').blur();
247 } else if (deleteButton.hasClass('ui-disabled')) {
248 deleteButton.removeClass('ui-disabled').attr('tabIndex', '0');
253 * Returns number of selected call logs
254 * @return {number} length
256 getCountSelectedLogEntries: function Ui_getCountSelectedLogEntries() {
257 return $('#forCallerList li .toRemove label.ui-checkbox-on').length;
260 selectAllDetailsEach: function Ui_selectAllDetailsEach() {
262 $('#forCallerList').find('input').each(function () {
263 if ($('#selectAllDetails').attr('checked')) {
264 self.selectCheckbox($(this), true);
266 self.selectCheckbox($(this), false);
274 hideCheckboxes: function Ui_hideCheckboxes() {
276 this.selectCheckbox($('#selectAllDetails'), false);
278 $('#forCallerList').find('input').each(function () {
279 self.selectCheckbox($(this), false);
281 this.changeDetailsToRemoveState('hide');
285 * Returns css classes for specified entry
287 * @param {CallHistoryEntry} entry
290 cssClassesForEntry: function Ui_cssClassesForEntry(entry) {
291 return 'call dir_' + entry.direction.toLowerCase() + ' type_' + entry.type.replace('.', '-').toLowerCase();
294 setSelectAllDetails: function Ui_setSelectAllDetails() {
295 if ($('#forCallerList input[type="checkbox"]').length ===
296 $('#forCallerList input[checked="checked"]').length) {
297 this.selectCheckbox($('#selectAllDetails'), true);
299 this.selectCheckbox($('#selectAllDetails'), false);
304 * Shows popup with specified message
305 * @param {string} message
307 showPopup: function Ui_showPopup(message) {
308 $('#popupMessage').html(message);
309 $('#popup').popup('open', {'positionTo': 'window'});
315 closePopup: function Ui_closePopup() {
316 $('#popup').popup('close');
319 showErrorPopup: function Ui_showErrorPopup(message) {
320 $('#errorPopupMessage').html(message);
321 $('#errorPopup').popup('open', {'positionTo': 'window'});
324 closeErrorPopup: function Ui_closeErrorPopup() {
325 $('#errorPopup').popup('close');
329 * Deletes checked log entries
331 deleteCheckedLogs: function Ui_deleteCheckedLogs(e) {
334 this.selectCheckbox($('#selectAllDetails'), false);
336 $('#forCallerList li.call').each(function () {
337 if ($(this).find('form label').hasClass('ui-checkbox-on')) {
338 app.deleteLog($(this).data('entries')[0]);
343 if ($('#forCallerList li.call').length > 0) {
344 this.updateCallerHeaderNumberOfEntries($('#forCallerList li.call').length);
347 $('.ui-listview-filter .ui-input-text').val('');
348 $('.ui-listview-filter .ui-input-text').trigger('change');
349 $.mobile.changePage('#callView');
352 this.changeDetailsToRemoveState(true);
353 this.scrollToBottom();
356 changeDetailsToRemoveState: function Ui_changeDetailsToRemoveState(set, clear) {
357 var counter = this.getCountSelectedLogEntries(),
358 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?');
395 matrix = $('#historyForCallerView .ui-scrollview-view').css('transform');
396 pos = matrix.substr(7, matrix.length -8).split(',')[5];
397 if (pos !== undefined) {
398 $('#callerListContainer').scrollview('scrollTo', 100, parseInt(pos), 10);
400 this.refreshScrollView();
405 * Renders call history list
407 * @param {CallHistoryEntry[]} callEntries
409 showCallHistory: function Ui_showCallHistory(callEntries) {
411 pdate = null, // previous date
413 elements = [], // list elements
414 len = callEntries.length, // entries length
415 tempLength = 0, // length of temporary table;
418 current, // current entry object
419 today = this.helpers.getShortDate(new Date()), // today short date
425 calllogList = $('#calllogList'),
426 calllogListContent = $('#calllogListContent'),
427 calllogListContentPos;
429 function filterForSameEntry(element) {
430 return self.getNumber(current) === self.getNumber(element)
431 && current.direction === element.direction;
434 $('.selectedCount').hide();
436 for (i = 0; i < len; i = i + 1) {
437 current = callEntries[i];
438 date = this.helpers.toNativeDate(current.startTime);
440 // if date is changed create new deyLog;
441 if (date !== pdate) {
445 dayLog.counters = [];
446 groupsOfDays.push(dayLog);
450 // group entries by remote Party;
451 filterResult = dayLog.entries.filter(filterForSameEntry);
452 if (filterResult.length) {
453 index = dayLog.entries.indexOf(filterResult[0]);
454 dayLog.counters[index] += 1;
456 dayLog.entries.push(current);
457 dayLog.counters[dayLog.entries.length - 1] = 1;
460 // Create UL list with dividers;
461 len = groupsOfDays.length;
462 for (i = 0; i < len; i += 1) {
463 dayLog = groupsOfDays[i];
464 tempLength = dayLog.entries.length;
465 entryShortDate = this.helpers.getShortDate(dayLog.entries[0].startTime);
467 //original code, do not remove until web-ui release; N_SE-48946
468 // elements.push($(this.templateManager.get('dateRow', {
469 // 'date': today === entryShortDate ? 'Today' : dayLog.date
472 for (j = 0; j < tempLength; j = j + 1) {
473 elements.push(this.getCallItemRow(dayLog.entries[j], dayLog.counters[j]));
476 calllogListContentPos = this.helpers.getScrollPosition(calllogListContent);
477 calllogList.empty().append(elements);
479 /* workaround solution for searching phrase remain*/
480 if ($("[data-type='search']").val().length != "") {
481 calllogList.listview('refresh');
482 $("[data-type='search']").trigger("keyup");
483 $(".ui-li-divider").removeClass("ui-li ui-li-divider ui-bar-s").addClass("date");
485 calllogList.listview({
488 autodividersSelector: function ( li ) {
489 return $(li).find('.callDate').text() === app.ui.helpers.toNativeDate(new Date())
490 ? "Today" : $(li).find('.callDate').text();
492 }).listview('refresh');
493 $(".ui-li-divider").removeClass().addClass("date");
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 this.setSelectAllDetails();
640 // close popup if there are no checked checkboxes
641 if (!$("#forCallerList input:checked").length) {
642 if ($.mobile.popup.active) {
643 $.mobile.popup.active.close();
647 this.addEventsForCallerListCheckboxes();
648 // lock buttons if unknown caller
650 this.unlockButtons();
652 this.lockButtons('#callActionBtn, #smsActionBtn');
658 * @param {string} accountId
660 updateCallerHeaderAccountId: function Ui_updateCallerHeaderAccountId(accountId) {
661 $('.infoContainer .accountId').html(accountId);
665 * Update number of entries
666 * @param numberOfEntries
668 updateCallerHeaderNumberOfEntries: function Ui_updateCallerHeaderNumberOfEntries(numberOfEntries) {
669 $('.infoContainer .numberOfEntries').html('' + numberOfEntries + ' ' + (numberOfEntries === 1 ? 'call' : 'calls'));
673 * Updates caller main info
674 * @param {CallHistoryEntry} entry
675 * @param {number} numberOfEntries
677 updateCallerHeader: function Ui_updateCallerHeader(entry, numberOfEntries) {
678 var name = '', party, imgPath, personId;
680 $('#header .photo').css('background-image', this.photoURIdefault);
682 if (entry.remoteParties !== null) {
683 party = entry.remoteParties[0];
684 personId = parseInt(party.personId, 10);
685 name = this.getNameByNumber(party.remoteParty);
686 if (party.displayName) {
687 this.updateCallerHeaderAccountId(party.remoteParty);
689 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
690 if (personId !== 0) {
691 imgPath = app.getPhotoURIForContact(personId);
692 if (imgPath !== false) {
693 $('#header .photo').css('background-image', 'url(' + imgPath + ')');
696 } else if (entry.contactId !== null) {
697 name = entry.accountId;
698 this.updateCallerHeaderAccountId(entry.accountId);
699 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
701 name = entry.accountId;
702 this.updateCallerHeaderAccountId('');
703 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
705 $('.contact > .infoContainer > .name').html(this.templateManager.modifiers.escape(name));
709 loadContacts: function Model_loadContacts(callback) {
710 var contactsFoundCB, errorCB;
712 this.contactsLoaded = null;
714 contactsFoundCB = function (contacts) {
715 this.contactsLoaded = contacts;
716 if (callback instanceof Function) {
721 errorCB = function (error) {
722 console.error('Model_loadContacts, problem with find() method: ' + error.message);
725 this.addressBook.find(contactsFoundCB.bind(this), errorCB);
729 * Remove search filter from content and appends it to header
731 removeSearchBarToHeader: function () {
732 $('#page-header').append($('#callView .ui-listview-filter'));
733 $.mobile.activePage.page('refresh');
734 $('.ui-input-cancel').remove(); // patch for WebUI bug
735 $('#calllogListContent').trigger('resize'); // WebUi scrollview fix
738 scrollToBottom: function () {
739 var scrollView = $(".ui-scrollview-view");
740 scrollView.css("-webkit-transform", "translate3d(0px, -" +
741 scrollView.height() + "px, 0px)");
744 onVisibilityChange: function () {
746 document.addEventListener('webkitvisibilitychange', function () {
747 if (document.webkitVisibilityState === 'hidden') {
748 self.checkedLogs = [];
749 $('#forCallerList li.call').each(function () {
750 if ($(this).find('form label')
751 .hasClass('ui-checkbox-on')) {
752 var checkedEntry = $(this).data('entries')[0];
753 self.checkedLogs.push(checkedEntry.uid);
757 self.loadContacts(app.updateCallLists.bind(app));
758 $('#callActionBtn, #smsActionBtn')
759 .removeClass('ui-disabled');
764 lockButtons: function Ui_lockButtons(buttons) {
765 $(buttons).addClass('ui-disabled').attr('tabIndex', '-1').blur();
768 unlockButtons: function Ui_unlockButtons(){
769 $('#callActionBtn, #smsActionBtn').removeClass('ui-disabled').attr('tabIndex', '0');
774 * Patch for UI, bad refresh scrollView
776 refreshScrollView: function () {
777 var scrollView = $('.ui-scrollview-view'),
785 removedLastLog: function () {
786 this.hideCheckboxes();
787 $(".ui-popup").popup('close');
788 $.mobile.changePage('#callView');