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');
65 body.append(this.templateManager.get('messageWindow')).append(this.templateManager.get('errorWindow')).trigger('create');
66 $('#callView').append($(this.templateManager.get('callView')).children()).trigger('pagecreate');
67 pages.push(this.templateManager.get('callerHistory'));
68 body.append(pages.join(''));
69 this.removeSearchBarToHeader();
72 app.showCallHistory();
74 this.photoURIdefault = $("#header .photo").css('background-image');
80 addEvents: function Ui_addEvents() {
83 $(window).on('resize', function () {
84 $.mobile.activePage.page('refresh');
87 $('#callView').on('tap', '.ui-btn-back', app.exit.bind(app));
89 $('#callView').on('pagebeforeshow', function () {
90 app.showCallHistory();
93 $(".ui-scrollview-view").listview();
95 $('#historyForCallerView').on('tap', '.ui-btn-back', function (event) {
96 event.preventDefault();
97 event.stopPropagation();
98 $.mobile.changePage('#callView');
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('tap', function () {
132 self.selectAllDetailsEach();
135 $('#calllogList').on('tap', '.date', function (event) {
136 event.stopPropagation();
139 $('#calllogList').on('click', '.call', function onCalllogEntryClick(event) {
140 if ($(this).data('entries')[0].remoteParties[0].remoteParty !== "") {
141 app.showHistoryForCaller($(this).data('entries')[0].remoteParties[0].remoteParty);
142 $.mobile.changePage('#historyForCallerView');
146 $('#smsActionBtn').on('tap', function (event) {
148 self.hideCheckboxes();
149 app.sendSms($('#forCallerList').data('remoteParty'));
152 $('#callActionBtn').on("tap", function (event) {
154 self.hideCheckboxes();
155 app.makeCall($('#forCallerList').data('remoteParty'));
158 $('#deleteActionBtn').on('click', function () {
159 self.changeDetailsToRemoveState();
162 $('.selectAllBox').on('tap', 'li', function () {
163 var checkbox = $(this).find(':checkbox');
164 if (self.removeMode === true) {
165 if (checkbox.attr('checked')) {
166 checkbox.attr('checked', false)
167 .data('checkboxradio')
170 checkbox.attr('checked', true)
171 .data('checkboxradio')
174 self.setSelectAllDetails();
179 .on('click', '#popupCancelActionBtn', this.closePopup.bind(this))
180 .on('click', '#popupSubmitActionBtn', this.deleteCheckedLogs.bind(this));
182 $('#errorPopup').on('tap', '#errorPopupOkBtn', this.closeErrorPopup);
184 $(window).keyup(function(e){
185 if (e.which === 13) {
186 $('input:focus').blur();
190 document.addEventListener('tizenhwkey', function(e) {
191 if (e.keyName == "back") {
192 if (self.removeMode === true) {
193 app.ui.changeDetailsToRemoveState(undefined, true);
194 } else if ($.mobile.activePage.attr('id') === 'callView') {
195 tizen.application.getCurrentApplication().exit();
202 self.onVisibilityChange();
205 addEventsForCallerListCheckboxes: function Ui_addEventsForCallerListCheckboxes() {
207 $('#forCallerList :checkbox').on('change', function (event) {
208 if ($(this).attr('checked')) {
209 $(this).attr('checked', true);
211 $(this).attr('checked', false);
213 self.setSelectAllDetails();
217 selectAll: function () {
218 if ($('#selectAllDetails').attr('checked')) {
219 this.selectCheckbox($('#selectAllDetails'), true);
221 this.selectCheckbox($('#selectAllDetails'), false);
223 this.selectAllDetailsEach();
226 selectCheckbox: function (obj, state) {
227 obj.attr('checked', state)
228 .data('checkboxradio')
233 * Returns number of selected call logs
234 * @return {number} length
236 getCountSelectedLogEntries: function Ui_getCountSelectedLogEntries() {
237 return $('#forCallerList li .toRemove label.ui-checkbox-on').length;
240 selectAllDetailsEach: function Ui_selectAllDetailsEach() {
242 $('#forCallerList').find('input').each(function () {
243 if ($('#selectAllDetails').attr('checked')) {
244 self.selectCheckbox($(this), true);
246 self.selectCheckbox($(this), false);
254 hideCheckboxes: function Ui_hideCheckboxes() {
256 this.selectCheckbox($('#selectAllDetails'), false);
258 $('#forCallerList').find('input').each(function () {
259 self.selectCheckbox($(this), false);
261 this.changeDetailsToRemoveState('hide');
265 * Returns css classes for specified entry
267 * @param {CallHistoryEntry} entry
270 cssClassesForEntry: function Ui_cssClassesForEntry(entry) {
271 return 'call dir_' + entry.direction.toLowerCase() + ' type_' + entry.type.replace('.', '-').toLowerCase();
274 setSelectAllDetails: function Ui_setSelectAllDetails() {
275 if ($('#forCallerList input[type="checkbox"]').length ===
276 $('#forCallerList input[checked="checked"]').length) {
277 this.selectCheckbox($('#selectAllDetails'), true);
279 this.selectCheckbox($('#selectAllDetails'), false);
284 * Shows popup with specified message
285 * @param {string} message
287 showPopup: function Ui_showPopup(message) {
288 $('#popupMessage').html(message);
289 $('#popup').popup('open', {'positionTo': 'window'});
295 closePopup: function Ui_closePopup() {
296 $('#popup').popup('close');
299 showErrorPopup: function Ui_showErrorPopup(message) {
300 $('#errorPopupMessage').html(message);
301 $('#errorPopup').popup('open', {'positionTo': 'window'});
304 closeErrorPopup: function Ui_closeErrorPopup() {
305 $('#errorPopup').popup('close');
309 * Deletes checked log entries
311 deleteCheckedLogs: function Ui_deleteCheckedLogs(e) {
314 this.selectCheckbox($('#selectAllDetails'), false);
316 $('#forCallerList li.call').each(function () {
317 if ($(this).find('form label').hasClass('ui-checkbox-on')) {
318 app.deleteLog($(this).data('entries')[0]);
323 if ($('#forCallerList li.call').length > 0) {
324 this.updateCallerHeaderNumberOfEntries($('#forCallerList li.call').length);
327 $('.ui-listview-filter .ui-input-text').val('');
328 $('.ui-listview-filter .ui-input-text').trigger('change');
329 $.mobile.changePage('#callView');
332 this.changeDetailsToRemoveState(true);
333 this.scrollToBottom();
336 changeDetailsToRemoveState: function Ui_changeDetailsToRemoveState(set, clear) {
337 var counter = this.getCountSelectedLogEntries();
338 if (clear === true) {
340 $('#forCallerList').find(':checkbox').attr('checked', false)
341 .data('checkboxradio').refresh();
342 $('.selectAllBox').find(':checkbox').attr('checked', false)
343 .data('checkboxradio').refresh();
345 if (set !== undefined) {
346 this.removeMode = false;
347 } else if (counter === 0) {
348 this.removeMode = !this.removeMode;
352 if (this.removeMode) {
353 $('#historyForCallerView .toRemove').removeClass('hidden');
354 $('#historyForCallerView .selectAllBox')
355 .removeClass('hidden');
357 $('#historyForCallerView .toRemove').addClass('hidden');
358 $('#historyForCallerView .selectAllBox').addClass('hidden');
360 } else if (counter > 1) {
361 this.showPopup('Are you sure you want to delete selected logs?');
363 this.showPopup('Are you sure you want to delete selected log?');
365 this.refreshScrollView();
369 * Renders call history list
371 * @param {CallHistoryEntry[]} callEntries
373 showCallHistory: function Ui_showCallHistory(callEntries) {
375 pdate = null, // previous date
377 elements = [], // list elements
378 len = callEntries.length, // entries length
379 tempLength = 0, // length of temporary table;
382 current, // current entry object
383 today = this.helpers.getShortDate(new Date()), // today short date
390 function filterForSameEntry(element) {
391 return self.getNumber(current) === self.getNumber(element)
392 && current.direction === element.direction;
395 $('.selectedCount').hide();
397 for (i = 0; i < len; i = i + 1) {
398 current = callEntries[i];
399 date = current.startTime.toLocaleDateString();
401 // if date is changed create new deyLog;
402 if (date !== pdate) {
406 dayLog.counters = [];
407 groupsOfDays.push(dayLog);
411 // group entries by remote Party;
412 filterResult = dayLog.entries.filter(filterForSameEntry);
413 if (filterResult.length) {
414 index = dayLog.entries.indexOf(filterResult[0]);
415 dayLog.counters[index] += 1;
417 dayLog.entries.push(current);
418 dayLog.counters[dayLog.entries.length - 1] = 1;
421 // Create UL list with dividers;
422 len = groupsOfDays.length;
423 for (i = 0; i < len; i += 1) {
424 dayLog = groupsOfDays[i];
425 tempLength = dayLog.entries.length;
426 entryShortDate = this.helpers.getShortDate(dayLog.entries[0].startTime);
429 elements.push($(this.templateManager.get('dateRow', {
430 'date': today === entryShortDate ? 'Today' : dayLog.date
433 for (j = 0; j < tempLength; j = j + 1) {
434 elements.push(this.getCallItemRow(dayLog.entries[j], dayLog.counters[j]));
442 /* workaround solution for not auto refreshing list view*/
443 setTimeout(function () {
444 $(".ui-scrollview-view").listview().listview('refresh');
447 /* workaround for registering call during working app in removeMode */
448 if (this.removeMode) {
449 if ($('#selectAllDetails').attr('checked')){
451 $('.toRemove, .selectAllBox', $('#historyForCallerView'))
452 .removeClass('hidden');
454 $('#forCallerList .toRemove').show()
459 * @param: {CallHistoryEntry} entry
461 getNumber: function (entry) {
462 return entry.remoteParties[0].remoteParty;
466 * Returns HTML for single log entry
468 * @param {CallHistoryEntry} entry
469 * @param {number} counter
470 * @returns {HTMLPartial}
472 getCallItemRow: function Ui_getCallItemRow(entry, counter) {
473 var party = entry.remoteParties[0],
474 name = this.getNameByNumber(party.remoteParty),
478 name += ' (' + counter + ')';
481 tpl = this.templateManager.get('callItemRow', {
483 'callTime': entry.startTime.toLocaleTimeString(),
484 'cssClasses': this.cssClassesForEntry(entry),
489 .data('remoteParty', entry.remoteParties[0].remoteParty)
490 .data('entries', [entry])
491 .get(0); // return clean DOM element so array of those could be appended at once*/
494 getNameByNumber: function (number) {
495 var i, j, contact, name;
496 for (i in this.contactsLoaded) {
497 if (this.contactsLoaded.hasOwnProperty(i)) {
498 contact = this.contactsLoaded[i];
499 for (j in contact.phoneNumbers) {
500 if (contact.phoneNumbers.hasOwnProperty(j)) {
501 if (contact.phoneNumbers[j].number.substr(-9)
502 === number.substr(-9)) {
503 name = contact.name.displayName;
510 return name || number;
514 * Returns HTML for single caller log entry
516 * @param {CallHistoryEntry} entry
517 * @returns {HTMLElement}
519 getCallerCallLogRow: function Ui_getCallerCallLogRow(entry) {
520 return $(this.templateManager.get('callerCallItemRow', {
521 'cssClass': this.cssClassesForEntry(entry),
522 'callTime': entry.startTime.toLocaleTimeString(),
523 'callDuration': this.helpers.secondsToHours(entry.duration),
525 })).data('entries', [entry]).get(0);
529 * Renders call log list for specified caller
531 * @param {string} remoteParty
532 * @param {CallHistoryEntry[]} entries
534 showHistoryForCaller: function Ui_showHistoryForCaller(remoteParty, entries) {
538 len = entries.length,
542 this.updateCallerHeader(entries[0], entries.length);
544 // if last call log has been removed
545 this.removedLastLog();
546 this.app.lastViewedCaller = 0;
550 .data('remoteParty', remoteParty)
551 .data('modified', false)
554 // group caller log entries by date
555 for (i = 0; i < len; i = i + 1) {
556 date = entries[i].startTime.toLocaleDateString();
558 // if date is changed render new header
559 if (date !== pdate) {
560 elements.push($(this.templateManager.get('dateRow', {'date': date})).get(0));
563 elements.push(this.getCallerCallLogRow(entries[i]));
570 if (elements.length > 0) {
571 $('li#delete > a').addClass('ui-btn-active');
573 $('li#delete > a').removeClass('ui-btn-active');
576 $('#forCallerList').trigger('create');
578 // change to remove mode if it was active before registering call
579 if (this.removeMode) {
580 this.removeMode = !this.removeMode;
581 this.changeDetailsToRemoveState();
582 // check previous checked entries
583 this.checkedLogs.forEach(function(logUid){
584 var checkbox = $('#forCallerList li.call[data-uid="' + logUid + '"]')
586 checkbox.attr('checked', true)
587 .data('checkboxradio')
590 this.checkedLogs = [];
592 this.addEventsForCallerListCheckboxes();
597 * @param {string} accountId
599 updateCallerHeaderAccountId: function Ui_updateCallerHeaderAccountId(accountId) {
600 $('.infoContainer .accountId').html(accountId);
604 * Update number of entries
605 * @param numberOfEntries
607 updateCallerHeaderNumberOfEntries: function Ui_updateCallerHeaderNumberOfEntries(numberOfEntries) {
608 $('.infoContainer .numberOfEntries').html(numberOfEntries);
612 * Updates caller main info
613 * @param {CallHistoryEntry} entry
614 * @param {number} numberOfEntries
616 updateCallerHeader: function Ui_updateCallerHeader(entry, numberOfEntries) {
617 var name = '', party, imgPath, personId;
619 $('#header .photo').css('background-image', this.photoURIdefault);
621 if (entry.remoteParties !== null) {
622 party = entry.remoteParties[0];
623 personId = parseInt(party.personId, 10);
624 name = this.getNameByNumber(party.remoteParty);
625 if (party.displayName) {
626 this.updateCallerHeaderAccountId(party.remoteParty);
628 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
629 if (personId !== 0) {
630 imgPath = app.getPhotoURIForContact(personId);
631 if (imgPath !== false) {
632 $('#header .photo').css('background-image', 'url(' + imgPath + ')');
635 } else if (entry.contactId !== null) {
636 name = entry.accountId;
637 this.updateCallerHeaderAccountId(entry.accountId);
638 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
640 name = entry.accountId;
641 this.updateCallerHeaderAccountId('');
642 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
644 $('.contact > .infoContainer > .name').html(name);
648 loadContacts: function Model_loadContacts(callback) {
649 var contactsFoundCB, errorCB;
651 this.contactsLoaded = null;
653 contactsFoundCB = function (contacts) {
654 this.contactsLoaded = contacts;
658 errorCB = function (error) {
659 console.error('Model_loadContacts, problem with find() method: ' + error.message);
662 this.addressBook.find(contactsFoundCB.bind(this), errorCB);
666 * Remove search filter from content and appends it to header
668 removeSearchBarToHeader: function () {
669 $('#page-header').append($('#callView .ui-listview-filter'));
670 $.mobile.activePage.page('refresh');
671 $('.ui-input-cancel').remove(); // patch for WebUI bug;
674 scrollToBottom: function () {
675 $(".ui-scrollview-view")
676 .css("-webkit-transform", "translate3d(0px, -" + scrollView.height() + "px, 0px)");
679 onVisibilityChange: function () {
681 document.addEventListener('webkitvisibilitychange', function () {
682 if (document.webkitVisibilityState === 'hidden') {
683 $('#forCallerList li.call').each(function () {
684 if ($(this).find('form label')
685 .hasClass('ui-checkbox-on')) {
686 var checkedEntry = $(this).data('entries')[0];
687 self.checkedLogs.push(checkedEntry.uid);
691 $('#callActionBtn, #smsActionBtn')
692 .removeClass('ui-disabled');
697 lockButtons: function () {
698 $('#callActionBtn, #smsActionBtn').addClass('ui-disabled');
703 * Patch for UI, bad refresh scrollView
705 refreshScrollView: function () {
706 var scrollView = $('.ui-scrollview-view'),
714 removedLastLog: function () {
715 this.hideCheckboxes();
716 $(".ui-popup").popup('close');
717 $.mobile.changePage('#callView');