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('softkeyboardchange', 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 $('#historyForCallerView').on('tap', '.ui-btn-back', function (event) {
94 event.preventDefault();
95 event.stopPropagation();
96 $.mobile.changePage('#callView');
99 $('#historyForCallerView').on('pagebeforeshow', function () {
100 self.hideCheckboxes();
101 $('#historyForCallerView .ui-content.ui-scrollview-clip .ui-scrollview-view')
102 .css('-webkit-transform', 'translate3d(0px, 0px, 0px)');
103 $('#selectAllDetails').on('change', function () {
108 $('#historyForCallerView').on('pageshow', function () {
109 $('#content').css('top', '160px');
110 $('#header').css('height', '160px');
111 $('#delete-toolbar').css('width', '70px');
112 $('#callerListContainer')
113 .children('.ui-overflow-indicator-top', '.ui-overflow-indicator-bottom')
117 $('#callerListContainer').on('scrollstart', function () {
119 .children('.ui-overflow-indicator-top', '.ui-overflow-indicator-bottom')
123 $('#callerListContainer').on('scrollstop', function () {
125 .children('.ui-overflow-indicator-top', '.ui-overflow-indicator-bottom')
129 $(window).on('resize', function () {
130 $('#delete-toolbar').css('width', '70px');
133 $('.selectAllBox').children().on('tap', function () {
135 self.selectAllDetailsEach();
138 $('#calllogList').on('tap', '.date', function (event) {
139 event.stopPropagation();
142 $('#calllogList').on('click', '.call', function onCalllogEntryClick(event) {
143 if ($(this).data('entries')[0].remoteParties[0].remoteParty !== "") {
144 app.showHistoryForCaller($(this).data('entries')[0].remoteParties[0].remoteParty);
145 $.mobile.changePage('#historyForCallerView');
149 $('#smsActionBtn').on('tap', function (event) {
150 event.preventDefault();
151 event.stopPropagation();
152 if ($(this).data('activated')) {
156 self.lockOptionButtons();
157 self.hideCheckboxes();
158 app.sendSms($('#forCallerList').data('remoteParty'));
161 $('#callActionBtn').on("tap", function (event) {
162 event.preventDefault();
163 event.stopPropagation();
164 if ($(this).data('activated')) {
168 self.lockOptionButtons();
169 self.hideCheckboxes();
170 app.makeCall($('#forCallerList').data('remoteParty'));
175 $('#deleteActionBtn').on('click', function () {
176 self.changeDetailsToRemoveState();
179 $('.selectAllBox').on('tap', 'li', function () {
180 var checkbox = $(this).find(':checkbox');
181 if (self.removeMode === true) {
182 if (checkbox.attr('checked')) {
183 checkbox.attr('checked', false)
184 .data('checkboxradio')
187 checkbox.attr('checked', true)
188 .data('checkboxradio')
191 self.setSelectAllDetails();
196 .on('click', '#popupCancelActionBtn', this.closePopup.bind(this))
197 .on('click', '#popupSubmitActionBtn', this.deleteCheckedLogs.bind(this));
199 $('#errorPopup').on('tap', '#errorPopupOkBtn', this.closeErrorPopup);
201 $(window).keyup(function(e){
202 if (e.which === 13) {
203 $('input:focus').blur();
207 document.addEventListener('tizenhwkey', function(e) {
208 if (e.keyName == "back") {
209 if ($.mobile.activePage.attr('id') === 'callView') {
210 tizen.application.getCurrentApplication().exit();
217 self.onVisibilityChange();
220 lockOptionButtons: function () {
221 var buttons = $('#callActionBtn, #smsActionBtn');
222 buttons.data('activated', true);
223 setTimeout(function () {
224 buttons.data('activated', false);
228 addEventsForCallerListCheckboxes: function Ui_addEventsForCallerListCheckboxes() {
230 $('#forCallerList :checkbox').on('change', function (event) {
231 if ($(this).attr('checked')) {
232 $(this).attr('checked', true);
234 $(this).attr('checked', false);
236 self.setSelectAllDetails();
240 selectAll: function () {
241 if ($('#selectAllDetails').attr('checked')) {
242 this.selectCheckbox($('#selectAllDetails'), true);
244 this.selectCheckbox($('#selectAllDetails'), false);
246 this.selectAllDetailsEach();
249 selectCheckbox: function (obj, state) {
250 obj.attr('checked', state)
251 .data('checkboxradio')
256 * Returns number of selected call logs
257 * @return {number} length
259 getCountSelectedLogEntries: function Ui_getCountSelectedLogEntries() {
260 return $('#forCallerList li .toRemove label.ui-checkbox-on').length;
263 selectAllDetailsEach: function Ui_selectAllDetailsEach() {
265 $('#forCallerList').find('input').each(function () {
266 if ($('#selectAllDetails').attr('checked')) {
267 self.selectCheckbox($(this), true);
269 self.selectCheckbox($(this), false);
277 hideCheckboxes: function Ui_hideCheckboxes() {
279 this.selectCheckbox($('#selectAllDetails'), false);
281 $('#forCallerList').find('input').each(function () {
282 self.selectCheckbox($(this), false);
284 this.changeDetailsToRemoveState('hide');
288 * Returns css classes for specified entry
290 * @param {CallHistoryEntry} entry
293 cssClassesForEntry: function Ui_cssClassesForEntry(entry) {
294 return 'call dir_' + entry.direction.toLowerCase() + ' type_' + entry.type.replace('.', '-').toLowerCase();
297 setSelectAllDetails: function Ui_setSelectAllDetails() {
298 if ($('#forCallerList input[type="checkbox"]').length ===
299 $('#forCallerList input[checked="checked"]').length) {
300 this.selectCheckbox($('#selectAllDetails'), true);
302 this.selectCheckbox($('#selectAllDetails'), false);
307 * Shows popup with specified message
308 * @param {string} message
310 showPopup: function Ui_showPopup(message) {
311 $('#popupMessage').html(message);
312 $('#popup').popup('open', {'positionTo': 'window'});
318 closePopup: function Ui_closePopup() {
319 $('#popup').popup('close');
322 showErrorPopup: function Ui_showErrorPopup(message) {
323 $('#errorPopupMessage').html(message);
324 $('#errorPopup').popup('open', {'positionTo': 'window'});
327 closeErrorPopup: function Ui_closeErrorPopup() {
328 $('#errorPopup').popup('close');
332 * Deletes checked log entries
334 deleteCheckedLogs: function Ui_deleteCheckedLogs(e) {
337 this.selectCheckbox($('#selectAllDetails'), false);
339 $('#forCallerList li.call').each(function () {
340 if ($(this).find('form label').hasClass('ui-checkbox-on')) {
341 app.deleteLog($(this).data('entries')[0]);
346 if ($('#forCallerList li.call').length > 0) {
347 this.updateCallerHeaderNumberOfEntries($('#forCallerList li.call').length);
350 $('.ui-listview-filter .ui-input-text').val('');
351 $('.ui-listview-filter .ui-input-text').trigger('change');
352 $.mobile.changePage('#callView');
355 this.changeDetailsToRemoveState(true);
356 this.scrollToBottom();
359 changeDetailsToRemoveState: function Ui_changeDetailsToRemoveState(set) {
360 var counter = this.getCountSelectedLogEntries();
361 if (set !== undefined) {
362 this.removeMode = false;
363 } else if (counter === 0) {
364 this.removeMode = !this.removeMode;
368 if (this.removeMode) {
369 $('#historyForCallerView .toRemove').removeClass('hidden');
370 $('#historyForCallerView .selectAllBox').removeClass('hidden');
372 $('#historyForCallerView .toRemove').addClass('hidden');
373 $('#historyForCallerView .selectAllBox').addClass('hidden');
375 } else if (counter > 1) {
376 this.showPopup('Are you sure you want to delete selected logs?');
378 this.showPopup('Are you sure you want to delete selected log?');
380 this.refreshScrollView();
384 * Renders call history list
386 * @param {CallHistoryEntry[]} callEntries
388 showCallHistory: function Ui_showCallHistory(callEntries) {
390 pdate = null, // previous date
392 elements = [], // list elements
393 len = callEntries.length, // entries length
394 tempLength = 0, // length of temporary table;
397 current, // current entry object
398 today = this.helpers.getShortDate(new Date()), // today short date
405 function filterForSameEntry(element) {
406 return self.getNumber(current) === self.getNumber(element)
407 && current.direction === element.direction;
410 $('.selectedCount').hide();
412 for (i = 0; i < len; i = i + 1) {
413 current = callEntries[i];
414 date = current.startTime.toLocaleDateString();
416 // if date is changed create new deyLog;
417 if (date !== pdate) {
421 dayLog.counters = [];
422 groupsOfDays.push(dayLog);
426 // group entries by remote Party;
427 filterResult = dayLog.entries.filter(filterForSameEntry);
428 if (filterResult.length) {
429 index = dayLog.entries.indexOf(filterResult[0]);
430 dayLog.counters[index] += 1;
432 dayLog.entries.push(current);
433 dayLog.counters[dayLog.entries.length - 1] = 1;
436 // Create UL list with dividers;
437 len = groupsOfDays.length;
438 for (i = 0; i < len; i += 1) {
439 dayLog = groupsOfDays[i];
440 tempLength = dayLog.entries.length;
441 entryShortDate = this.helpers.getShortDate(dayLog.entries[0].startTime);
444 elements.push($(this.templateManager.get('dateRow', {
445 'date': today === entryShortDate ? 'Today' : dayLog.date
448 for (j = 0; j < tempLength; j = j + 1) {
449 elements.push(this.getCallItemRow(dayLog.entries[j], dayLog.counters[j]));
457 /* workaround for registering call during working app in removeMode */
458 if (this.removeMode) {
459 if ($('#selectAllDetails').attr('checked')){
461 $('.toRemove, .selectAllBox', $('#historyForCallerView'))
462 .removeClass('hidden');
464 $('#forCallerList .toRemove').show()
467 /* workaround for UIFW & webkit scroll*/
468 $.mobile.activePage.css('min-height', 0);
472 * @param: {CallHistoryEntry} entry
474 getNumber: function (entry) {
475 return entry.remoteParties[0].remoteParty;
479 * Returns HTML for single log entry
481 * @param {CallHistoryEntry} entry
482 * @param {number} counter
483 * @returns {HTMLPartial}
485 getCallItemRow: function Ui_getCallItemRow(entry, counter) {
486 var party = entry.remoteParties[0],
487 name = this.getNameByNumber(party.remoteParty),
491 name += ' (' + counter + ')';
494 tpl = this.templateManager.get('callItemRow', {
496 'callTime': entry.startTime.toLocaleTimeString(),
497 'cssClasses': this.cssClassesForEntry(entry),
502 .data('remoteParty', entry.remoteParties[0].remoteParty)
503 .data('entries', [entry])
504 .get(0); // return clean DOM element so array of those could be appended at once*/
507 getNameByNumber: function (number) {
508 var i, j, contact, name;
509 for (i in this.contactsLoaded) {
510 if (this.contactsLoaded.hasOwnProperty(i)) {
511 contact = this.contactsLoaded[i];
512 for (j in contact.phoneNumbers) {
513 if (contact.phoneNumbers.hasOwnProperty(j)) {
514 if (contact.phoneNumbers[j].number.substr(-9)
515 === number.substr(-9)) {
516 name = contact.name.displayName;
523 return name || number;
527 * Returns HTML for single caller log entry
529 * @param {CallHistoryEntry} entry
530 * @returns {HTMLElement}
532 getCallerCallLogRow: function Ui_getCallerCallLogRow(entry) {
533 return $(this.templateManager.get('callerCallItemRow', {
534 'cssClass': this.cssClassesForEntry(entry),
535 'callTime': entry.startTime.toLocaleTimeString(),
536 'callDuration': this.helpers.secondsToHours(entry.duration),
538 })).data('entries', [entry]).get(0);
542 * Renders call log list for specified caller
544 * @param {string} remoteParty
545 * @param {CallHistoryEntry[]} entries
547 showHistoryForCaller: function Ui_showHistoryForCaller(remoteParty, entries) {
551 len = entries.length,
555 this.updateCallerHeader(entries[0], entries.length);
557 // if last call log has been removed
558 this.removedLastLog();
559 this.app.lastViewedCaller = 0;
563 .data('remoteParty', remoteParty)
564 .data('modified', false)
567 // group caller log entries by date
568 for (i = 0; i < len; i = i + 1) {
569 date = entries[i].startTime.toLocaleDateString();
571 // if date is changed render new header
572 if (date !== pdate) {
573 elements.push($(this.templateManager.get('dateRow', {'date': date})).get(0));
576 elements.push(this.getCallerCallLogRow(entries[i]));
583 if (elements.length > 0) {
584 $('li#delete > a').addClass('ui-btn-active');
586 $('li#delete > a').removeClass('ui-btn-active');
589 $('#forCallerList').trigger('create');
591 // change to remove mode if it was active before registering call
592 if (this.removeMode) {
593 this.removeMode = !this.removeMode;
594 this.changeDetailsToRemoveState();
595 // check previous checked entries
596 this.checkedLogs.forEach(function(logUid){
597 var checkbox = $('#forCallerList li.call[data-uid="' + logUid + '"]')
599 checkbox.attr('checked', true)
600 .data('checkboxradio')
603 this.checkedLogs = [];
605 this.addEventsForCallerListCheckboxes();
610 * @param {string} accountId
612 updateCallerHeaderAccountId: function Ui_updateCallerHeaderAccountId(accountId) {
613 $('.infoContainer .accountId').html(accountId);
617 * Update number of entries
618 * @param numberOfEntries
620 updateCallerHeaderNumberOfEntries: function Ui_updateCallerHeaderNumberOfEntries(numberOfEntries) {
621 $('.infoContainer .numberOfEntries').html(numberOfEntries);
625 * Updates caller main info
626 * @param {CallHistoryEntry} entry
627 * @param {number} numberOfEntries
629 updateCallerHeader: function Ui_updateCallerHeader(entry, numberOfEntries) {
630 var name = '', party, imgPath, personId;
632 $('#header .photo').css('background-image', this.photoURIdefault);
634 if (entry.remoteParties !== null) {
635 party = entry.remoteParties[0];
636 personId = parseInt(party.personId, 10);
637 name = this.getNameByNumber(party.remoteParty);
638 if (party.displayName) {
639 this.updateCallerHeaderAccountId(party.remoteParty);
641 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
642 if (personId !== 0) {
643 imgPath = app.getPhotoURIForContact(personId);
644 if (imgPath !== false) {
645 $('#header .photo').css('background-image', 'url(' + imgPath + ')');
648 } else if (entry.contactId !== null) {
649 name = entry.accountId;
650 this.updateCallerHeaderAccountId(entry.accountId);
651 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
653 name = entry.accountId;
654 this.updateCallerHeaderAccountId('');
655 this.updateCallerHeaderNumberOfEntries(numberOfEntries);
657 $('.contact > .infoContainer > .name').html(name);
661 loadContacts: function Model_loadContacts(callback) {
662 var contactsFoundCB, errorCB;
664 this.contactsLoaded = null;
666 contactsFoundCB = function (contacts) {
667 this.contactsLoaded = contacts;
671 errorCB = function (error) {
672 console.error('Model_loadContacts, problem with find() method: ' + error.message);
675 this.addressBook.find(contactsFoundCB.bind(this), errorCB);
679 * Remove search filter from content and appends it to header
681 removeSearchBarToHeader: function () {
682 $('#page-header').append($('#callView .ui-listview-filter'));
683 $.mobile.activePage.page('refresh');
684 $('.ui-input-cancel').remove(); // patch for WebUI bug;
687 scrollToBottom: function () {
688 var scrollView = $(".ui-scrollview-view");
689 scrollView.css("-webkit-transform", "translate3d(0px, -" + scrollView.height() + "px, 0px)");
692 onVisibilityChange: function () {
694 document.addEventListener('webkitvisibilitychange', function () {
695 if (document.webkitVisibilityState === 'hidden') {
696 $('#forCallerList li.call').each(function () {
697 if ($(this).find('form label').hasClass('ui-checkbox-on')) {
698 var checkedEntry = $(this).data('entries')[0];
699 self.checkedLogs.push(checkedEntry.uid);
708 * Patch for UI, bad refresh scrollView
710 refreshScrollView: function () {
711 var scrollView = $('.ui-scrollview-view'),
719 removedLastLog: function () {
720 this.hideCheckboxes();
721 $(".ui-popup").popup('close');
722 $.mobile.changePage('#callView');