X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=project%2Fjs%2Fapp.ui.js;h=073572a5ef576837dcd796cfeeb1d568da430411;hb=HEAD;hp=483675fdbf066f4fe34b8dcc024c8a03293dae47;hpb=335f789d65024a4f29b1fc71773bac03430de476;p=apps%2Fweb%2Fsample%2FCallLog.git diff --git a/project/js/app.ui.js b/project/js/app.ui.js index 483675f..073572a 100644 --- a/project/js/app.ui.js +++ b/project/js/app.ui.js @@ -1,1045 +1,792 @@ -/* -* Copyright 2013 Samsung Electronics Co., Ltd -* -* Licensed under the Flora License, Version 1.1 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://floralicense.org/license/ -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - /*jslint devel: true*/ /*global tizen, document, $, jQuery, app, UiPanel, UiContact, TemplateManager, window, Helpers */ /** -* @class Ui -*/ + * @class Ui + */ + function Ui(contacts) { - 'use strict'; - this.init(); + 'use strict'; + this.init(); } (function () { // strict mode wrapper - 'use strict'; - - Ui.prototype = { - - /** - * UI remove mode - * @type {boolean} - */ - removeMode: false, - - /** - * Default tizen address book - * @type {AddressBook} - */ - addressBook: tizen.contact.getDefaultAddressBook(), - - /** - * Default photo uri - * @type {String} - */ - photoURIdefault: null, - - /** - * Cached contacts from address book - * @type {Array} - */ - contactsLoaded: null, - - /** - * identifiers of currently checked checkboxes - * @type {Array} - */ - checkedLogs: [], - - /** - * @type {TemplateManager} - */ - templateManager: null, - - /** - * UI Initializer - */ - init: function Ui_init() { - this.loadContacts(); - this.templateManager = new TemplateManager(); - this.helpers = new Helpers(); - $(document).ready(this.domInit.bind(this)); - $.mobile.tizen.disableSelection(document); - }, - - /** - * When DOM is ready, initialise it (bind events) - */ - domInit: function Ui_domInit() { - this.templateManager.loadToCache(['callView', - 'callerHistory', - 'callItemRow', - 'callerCallItemRow', - 'messageWindow', - 'errorWindow', - 'dateRow'], this.initPages.bind(this)); - }, - - /** - * UI pages initializer - */ - initPages: function Ui_initPages() { - var pages = [], body = $('body'); - - body - .append(this.templateManager.get('messageWindow')) - .append(this.templateManager.get('errorWindow')) - .trigger('create'); - $('#callView') - .append( - $(this.templateManager.get('callView')).children() - ) - .trigger('pagecreate') - .trigger('pageshow'); - pages.push(this.templateManager.get('callerHistory')); - body.append(pages.join('')); - this.removeSearchBarToHeader(); - - this.addEvents(); - app.showCallHistory(); - - this.photoURIdefault = $("#header .photo").css('background-image'); - }, - - /** - * Add UI events - */ - addEvents: function Ui_addEvents() { - var self = this; - - // recalculating page size when window resize - // (eg. when soft keybord appear) - $(window).on('resize', function () { - $.mobile.activePage.page('refresh'); - }); - - // creating call history view - $('#callView').on('pagebeforeshow', function () { - app.showCallHistory(); - }); - - // creating single contact history view - $('#historyForCallerView').on('pagebeforeshow', function () { - self.hideCheckboxes(); - // move scrollbar to top - $('#historyForCallerView') - .find('.ui-content.ui-scrollview-clip') - .find('.ui-scrollview-view') - .css('-webkit-transform', 'translate3d(0px, 0px, 0px)'); - $('#selectAllDetails').on('change', function () { - self.selectAll(); - }); - }); - - - // HACK not dissapearing scrollview indicator - $('#historyForCallerView').on('pageshow', function () { - $('#content').css('top', '160px'); - $('#header').css('height', '160px'); - $('#callerListContainer') - .children( - '.ui-overflow-indicator-top', - '.ui-overflow-indicator-bottom' - ).hide(); - }); - - // HACK not dissapearing scrollview indicator - $('#callerListContainer').on('scrollstart', function () { - $(this) - .children( - '.ui-overflow-indicator-top', - '.ui-overflow-indicator-bottom' - ).fadeIn(200); - }); - - // HACK not dissapearing scrollview indicator - $('#callerListContainer').on('scrollstop', function () { - $(this) - .children( - '.ui-overflow-indicator-top', - '.ui-overflow-indicator-bottom' - ).fadeOut(200); - }); - - // selecting all checkboxes - $('.selectAllBox').children().on('click', function () { - $('.selectAllBox input[type=checkbox]').trigger('click'); - self.selectAll(); - self.selectAllDetailsEach(); - }); - - $('#calllogList').on('click', '.date', function (event) { - event.stopPropagation(); - }); - - // when clicked on a log display all history from that contact - $('#calllogList').on( - 'click keypress', - '.call', - function onCalllogEntryClick(event) { - if (event.type === 'keypress' && event.keyCode !== 13) { - return; - } - var remoteParty = $(this) - .data('entries')[0] - .remoteParties[0] - .remoteParty; - app.showHistoryForCaller(remoteParty); - $.mobile.changePage('#historyForCallerView'); - } - ); - - // run sms service on click - $('#smsActionBtn').on('click', function (event) { - event.stopPropagation(); - event.preventDefault(); - self.lockButtons('#smsActionBtn, #callActionBtn'); - self.hideCheckboxes(); - self.lockButtons('#deleteActionBtn'); - app.sendSms($('#forCallerList').data('remoteParty')); - }); - - // run call service on btn click - $('#callActionBtn').on("click", function (event) { - self.lockButtons('#callActionBtn, #smsActionBtn'); - self.hideCheckboxes(); - self.lockButtons('#deleteActionBtn'); - app.makeCall($('#forCallerList').data('remoteParty')); - }); - - $('#deleteActionBtn').on('click', function () { - self.changeDetailsToRemoveState(); - }); - - // selecting all checkboxes - $('.selectAllBox').on('click', 'li', function () { - var checkbox = $(this).find(':checkbox'); - if (self.removeMode === true) { - if (checkbox.attr('checked')) { - checkbox.attr('checked', false) - .data('checkboxradio') - .refresh(); - } else { - checkbox.attr('checked', true) - .data('checkboxradio') - .refresh(); - } - self.setSelectAllDetails(); - } - }); - - $('#popup') - .on( - 'click', - '#popupCancelActionBtn', - this.closePopup.bind(this) - ).on( - 'click', - '#popupSubmitActionBtn', - this.deleteCheckedLogs.bind(this) - ); - - $('#errorPopup').on( - 'click', - '#errorPopupOkBtn', - this.closeErrorPopup - ); - - $('#errorPopup').bind( - { - popupafterclose: function () { - self.unlockButtons(); - } - } - ); - - $(window).keyup(function (e) { - if (e.which === 13) { - $('input:focus').blur(); - } - }); - - // bind hardware back button - window.addEventListener('tizenhwkey', function (e) { - if (e.keyName === "back") { - // if there is any popup close it - if ($.mobile.popup.active) { - $.mobile.popup.active.close(); - // if app is in remove mode close it - } else if (self.removeMode === true) { - app.ui.changeDetailsToRemoveState(undefined, true); - // if app is on calls page close app - } else if ($.mobile.activePage.attr('id') === 'callView') { - tizen.application.getCurrentApplication().exit(); - // else back to calls page - } else { - history.back(); - } - } - }); - // bind callback to visbility change event - self.onVisibilityChange(); - }, - - /** - * Bind change event - */ - addEventsForCallerListCheckboxes: - function Ui_addEventsForCallerListCheckboxes() { - var self = this; - $('#forCallerList :checkbox').on('change', function (event) { - if ($(this).attr('checked')) { - $(this).attr('checked', true); - } else { - $(this).attr('checked', false); - } - self.setSelectAllDetails(); - }); - }, - - /** - * Callback function for click on select all element - */ - selectAll: function () { - // if select all checkbox is checked - if ($('#selectAllDetails').attr('checked')) { - this.selectCheckbox($('#selectAllDetails'), true); - } else { - this.selectCheckbox($('#selectAllDetails'), false); - } - // select each checkbox separatly - this.selectAllDetailsEach(); - }, - - /** - * Select single checkbox and enable delete button - */ - selectCheckbox: function (obj, state) { - var deleteButton = $('#deleteActionBtn'), numChecked; - // check checkbox and refresh its view - obj.attr('checked', state) - .data('checkboxradio') - .refresh(); - - // check if there is any checked checkbox - // and toggle delete button availability - numChecked = $('#forCallerList input:checked').length; - if (this.removeMode && numChecked === 0) { - deleteButton - .addClass('ui-disabled') - .attr('tabIndex', '-1') - .blur(); - } else if (deleteButton.hasClass('ui-disabled')) { - deleteButton - .removeClass('ui-disabled') - .attr('tabIndex', '0'); - } - }, - - /** - * Returns number of selected call logs - * @return {number} length - */ - getCountSelectedLogEntries: function Ui_getCountSelectedLogEntries() { - return $('#forCallerList li .toRemove label.ui-checkbox-on').length; - }, - - /** - * Select each checkbox separatly - */ - selectAllDetailsEach: function Ui_selectAllDetailsEach() { - var self = this; - $('#forCallerList').find('input').each(function () { - if ($('#selectAllDetails').attr('checked')) { - self.selectCheckbox($(this), true); - } else { - self.selectCheckbox($(this), false); - } - }); - }, - - /** - * Hides checkboxes - */ - hideCheckboxes: function Ui_hideCheckboxes() { - var self = this; - this.selectCheckbox($('#selectAllDetails'), false); - - $('#forCallerList').find('input').each(function () { - self.selectCheckbox($(this), false); - }); - this.changeDetailsToRemoveState('hide'); - }, - - /** - * Returns css classes for specified entry - * - * @param {CallHistoryEntry} entry - * @returns {string} - */ - cssClassesForEntry: function Ui_cssClassesForEntry(entry) { - return 'call dir_' + - entry.direction.toLowerCase() + - ' type_' + - entry.type.replace('.', '-').toLowerCase(); - }, - - /** - * Check if all details checkboxes are selected - * and if so check selectAll element - */ - setSelectAllDetails: function Ui_setSelectAllDetails() { - if ( - $('#forCallerList input[type="checkbox"]').length === - $('#forCallerList input[checked="checked"]').length - ) { - this.selectCheckbox($('#selectAllDetails'), true); - } else { - this.selectCheckbox($('#selectAllDetails'), false); - } - }, - - /** - * Shows popup with specified message - * @param {string} message - */ - showPopup: function Ui_showPopup(message) { - $('#popupMessage').html(message); - $('#popup').popup('open', {'positionTo': 'window'}); - }, - - /** - * Hides popup - */ - closePopup: function Ui_closePopup() { - $('#popup').popup('close'); - }, - - /** - * Display error popup - */ - showErrorPopup: function Ui_showErrorPopup(message) { - $('#errorPopupMessage').html(message); - $('#errorPopup').popup('open', {'positionTo': 'window'}); - }, - - /** - * Hides error popup - */ - closeErrorPopup: function Ui_closeErrorPopup() { - $('#errorPopup').popup('close'); - }, - - /** - * Deletes checked log entries - */ - deleteCheckedLogs: function Ui_deleteCheckedLogs(e) { - // if there is popup open close it - this.closePopup(); - - // uncheck SelectAll checkbox - this.selectCheckbox($('#selectAllDetails'), false); - - // iterate through all entries - $('#forCallerList li.call').each(function () { - // if entry contains selected checkbox - if ($(this).find('form label').hasClass('ui-checkbox-on')) { - // remove that entry - app.deleteLog($(this).data('entries')[0]); - // and remove connected html element - $(this).remove(); - } - }); - - // if there are still some entries - if ($('#forCallerList li.call').length > 0) { - // update header info - this.updateCallerHeaderNumberOfEntries( - $('#forCallerList li.call').length - ); - } else { - // if no entries change page - e.preventDefault(); - $('.ui-listview-filter .ui-input-text').val(''); - $('.ui-listview-filter .ui-input-text').trigger('change'); - $.mobile.changePage('#callView'); - } - - this.changeDetailsToRemoveState(true); - this.scrollToBottom(); - }, - - /** - * TODO Dont really know what that method exacly doing - * and what should do - * TODO need refactor - */ - changeDetailsToRemoveState: function Ui_changeDetailsToRemoveState( - set, - clear - ) { - var counter = this.getCountSelectedLogEntries(), - numChecked = $('#forCallerList input:checked').length, - matrix, - pos; - if (clear === true) { - counter = 0; - // uncheck all checkboxes - $('#forCallerList').find(':checkbox').attr('checked', false) - .data('checkboxradio').refresh(); - $('.selectAllBox').find(':checkbox').attr('checked', false) - .data('checkboxradio').refresh(); - } - // TODO it is hard ot understand this - if (set !== undefined) { - this.removeMode = false; - } else if (counter === 0) { - this.removeMode = !this.removeMode; - } - - // if app is in remove mode and there are no selected checkboxes - if (this.removeMode && numChecked === 0) { - // disable delete button - $('#deleteActionBtn') - .addClass('ui-disabled') - .attr('tabIndex', '-1') - .blur(); - // if app is not in removeMode - } else if (!this.removeMode) { - // set delete button to enabled - $('#deleteActionBtn') - .removeClass('ui-disabled') - .attr('tabIndex', '0'); - this.selectAllDetailsEach(); - } - - // if there are no selected entries - if (counter === 0) { - // again checking removeMode - if (this.removeMode) { - // show buttons from remove mode - $('#historyForCallerView .toRemove').removeClass('hidden'); - $('#historyForCallerView .selectAllBox') - .removeClass('hidden'); - } else { - $('#historyForCallerView .toRemove').addClass('hidden'); - $('#historyForCallerView .selectAllBox').addClass('hidden'); - } - } else { - // TODO I dont understand - this.showPopup( - counter > 1 ? - 'Are you sure you want to delete selected logs?' : - 'Are you sure you want to delete selected log?' - ); - } - - // TODO need refactorin - // HACK probably scrollview hack - matrix = - $('#historyForCallerView .ui-scrollview-view') - .css('transform'); - pos = matrix.substr(7, matrix.length - 8).split(',')[5]; - if (pos !== undefined) { - $('#callerListContainer') - .scrollview('scrollTo', 100, parseInt(pos, 10), 10); - } else { - this.refreshScrollView(); - } - }, - - /** - * Renders call history list - * - * @param {CallHistoryEntry[]} callEntries - */ - showCallHistory: function Ui_showCallHistory(callEntries) { - var self = this, - pdate = null, // previous date - date = '', - elements = [], // list elements - len = callEntries.length, // entries length - tempLength = 0, // length of temporary table; - i, // loop counter - j, // loop counter - current, // current entry object - today = this.helpers.getShortDate(new Date()), - entryShortDate, - filterResult, - groupsOfDays = [], - dayLog, - index = 0, - calllogList = $('#calllogList'), - calllogListContent = $('#calllogListContent'), - calllogListContentPos; - - // return duplicated entries - function filterForSameEntry(element) { - return self.getNumber(current) === self.getNumber(element) - && current.direction === element.direction; - } - - $('.selectedCount').hide(); - - for (i = 0; i < len; i = i + 1) { - current = callEntries[i]; - date = this.helpers.toNativeDate(current.startTime); - - // if date is changed create new deyLog; - if (date !== pdate) { - dayLog = {}; - dayLog.date = date; - dayLog.entries = []; - dayLog.counters = []; - groupsOfDays.push(dayLog); - pdate = date; - } - - // group entries by remote Party; - filterResult = dayLog.entries.filter(filterForSameEntry); - if (filterResult.length) { - index = dayLog.entries.indexOf(filterResult[0]); - dayLog.counters[index] += 1; - } else { - dayLog.entries.push(current); - dayLog.counters[dayLog.entries.length - 1] = 1; - } - } - // Create UL list with dividers; - len = groupsOfDays.length; - for (i = 0; i < len; i += 1) { - dayLog = groupsOfDays[i]; - tempLength = dayLog.entries.length; - entryShortDate = this.helpers.getShortDate( - dayLog.entries[0].startTime - ); - for (j = 0; j < tempLength; j = j + 1) { - elements.push( - this.getCallItemRow( - dayLog.entries[j], - dayLog.counters[j] - ) - ); - } - } - calllogListContentPos = this.helpers.getScrollPosition( - calllogListContent - ); - calllogList.empty().append(elements); - - //workaround solution for searching phrase remain - // TODO FIXME - if ($("[data-type='search']").val().length !== "") { - calllogList.listview('refresh'); - $("[data-type='search']").trigger("keyup"); - $(".ui-li-divider") - .removeClass("ui-li ui-li-divider ui-bar-s") - .addClass("date"); - } else { - calllogList.listview({ - autodividers: true, - //filter: true, - autodividersSelector: function (li) { - return $(li).find('.callDate').text() === - app.ui.helpers.toNativeDate(new Date()) ? - "Today" : $(li).find('.callDate').text(); - } - }).listview('refresh'); - $(".ui-li-divider").removeClass().addClass("date"); - } - - setTimeout( - this.helpers.scrollTo.bind( - this, - calllogListContent, - calllogListContentPos - ), - 10 - ); - }, - - /** - * @param: {CallHistoryEntry} entry - */ - getNumber: function (entry) { - return entry.remoteParties[0].remoteParty; - }, - - /** - * Returns HTML for single log entry - * - * @param {CallHistoryEntry} entry - * @param {number} counter - * @returns {HTMLPartial} - */ - getCallItemRow: function Ui_getCallItemRow(entry, counter) { - var party = entry.remoteParties[0], - name = this.getNameByNumber(party.remoteParty), - tpl; - - if (counter > 1) { - name += ' (' + counter + ')'; - } - - // prepare html string - tpl = this.templateManager.get('callItemRow', { - 'name': name, - 'callTime': this.helpers.toNativeTime(entry.startTime), - 'callDate': this.helpers.toNativeDate(entry.startTime), - 'cssClasses': this.cssClassesForEntry(entry), - 'uid': entry.uid - }); - - // return clean DOM element so that array of those could be appended - // at once - return $(tpl) - .data('remoteParty', entry.remoteParties[0].remoteParty) - .data('entries', [entry]) - .get(0); - }, - - /** - * Return readable number identifier - * - * @param {string} number - * @returns {string} - */ - getNameByNumber: function (number) { - var i, j, contact, name; - // iterate through loaded contacts - for (i in this.contactsLoaded) { - if (this.contactsLoaded.hasOwnProperty(i)) { - contact = this.contactsLoaded[i]; - // iterate through numbers of contact - for (j in contact.phoneNumbers) { - if (contact.phoneNumbers.hasOwnProperty(j)) { - // check if first 9 characters match number - if (contact.phoneNumbers[j].number.substr(-9) - === number.substr(-9)) { - // get display name - name = contact.name.displayName; - break; - } - } - } - } - } - return name || number || 'Unknown'; - }, - - /** - * Returns HTML for single caller log entry - * - * @param {CallHistoryEntry} entry - * @returns {HTMLElement} - */ - getCallerCallLogRow: function Ui_getCallerCallLogRow(entry) { - return $(this.templateManager.get('callerCallItemRow', { - 'cssClass': this.cssClassesForEntry(entry), - 'callTime': this.helpers.toNativeTime(entry.startTime), - 'callDuration': this.helpers.secondsToHours(entry.duration), - 'uid': entry.uid - })).data('entries', [entry]).get(0); - }, - - /** - * Renders call log list for specified caller - * TODO that methods is too long! - * - * @param {string} remoteParty - * @param {CallHistoryEntry[]} entries - */ - showHistoryForCaller: function Ui_showHistoryForCaller( - remoteParty, - entries - ) { - var pdate = '', // previous data - date = '', - elements = [], - len = entries.length, // number of entries - i, - checkbox; - - if (len) { - this.updateCallerHeader(entries[0], entries.length); - } else { - // if last call log has been removed - this.removedLastLog(); - this.app.lastViewedCaller = 0; - } - - // clean the list - $('#forCallerList') - .data('remoteParty', remoteParty) - .data('modified', false) - .empty(); - - // group caller log entries by date - for (i = 0; i < len; i = i + 1) { - date = this.helpers.toNativeDate(entries[i].startTime); - - // if date is changed render new header - if (date !== pdate) { - elements.push( - $(this.templateManager.get( - 'dateRow', - {'date': date} - )).get(0) - ); - pdate = date; - } - elements.push(this.getCallerCallLogRow(entries[i])); - } - - $('#forCallerList') - .empty() - .append(elements); - - // set state of delete button - if (elements.length > 0) { - $('li#delete > a').addClass('ui-btn-active'); - } else { - $('li#delete > a').removeClass('ui-btn-active'); - } - - $('#forCallerList').trigger('create'); - - // change to remove mode if it was active before registering call - if (this.removeMode) { - this.removeMode = !this.removeMode; - this.changeDetailsToRemoveState(); - // check previous checked entries - this.checkedLogs.forEach(function (logUid) { - checkbox = - $('#forCallerList li.call[data-uid="' + logUid + '"]') - .find(':checkbox'); - if (checkbox.length > 0) { - checkbox.attr('checked', true) - .data('checkboxradio') - .refresh(); - $('#deleteActionBtn') - .removeClass('ui-disabled') - .attr('tabIndex', '0'); - } - }); - - this.setSelectAllDetails(); - - // close popup if there are no checked checkboxes - if (!$("#forCallerList input:checked").length) { - if ($.mobile.popup.active) { - $.mobile.popup.active.close(); - } - } - } - this.addEventsForCallerListCheckboxes(); - // lock buttons if unknown caller - if (remoteParty) { - this.unlockButtons(); - } else { - this.lockButtons( - '#callActionBtn, #smsActionBtn, #deleteActionBtn' - ); - } - }, - - /** - * Update accoundId - * @param {string} accountId - */ - updateCallerHeaderAccountId: function Ui_updateCallerHeaderAccountId( - accountId - ) { - $('.infoContainer .accountId').html(accountId); - }, - - /** - * Update number of entries - * @param numberOfEntries - */ - updateCallerHeaderNumberOfEntries: - function Ui_updateCallerHeaderNumberOfEntries(numberOfEntries) { - $('.infoContainer .numberOfEntries').html( - numberOfEntries + - ' ' + - (numberOfEntries === 1 ? 'call' : 'calls') - ); - }, - - /** - * Updates caller main info - * @param {CallHistoryEntry} entry - * @param {number} numberOfEntries - */ - updateCallerHeader: function Ui_updateCallerHeader( - entry, - numberOfEntries - ) { - // TODO need to refactor - // looks complicated - var name = '', party, imgPath, personId; - - $('#header .photo').css('background-image', this.photoURIdefault); - - if (entry.remoteParties !== null) { - party = entry.remoteParties[0]; - personId = parseInt(party.personId, 10); - name = this.getNameByNumber(party.remoteParty); - if (party.displayName) { - this.updateCallerHeaderAccountId(party.remoteParty); - } - this.updateCallerHeaderNumberOfEntries(numberOfEntries); - if (personId !== 0) { - imgPath = app.getPhotoURIForContact(personId); - if (imgPath !== false) { - $('#header .photo') - .css('background-image', 'url(' + imgPath + ')'); - } - } - } else if (entry.contactId !== null) { - name = entry.accountId; - this.updateCallerHeaderAccountId(entry.accountId); - this.updateCallerHeaderNumberOfEntries(numberOfEntries); - } else { - name = entry.accountId; - this.updateCallerHeaderAccountId(''); - this.updateCallerHeaderNumberOfEntries(numberOfEntries); - } - $('.contact > .infoContainer > .name').html( - this.templateManager.modifiers.escape(name) - ); - }, - - // TODO FIXME why that method is in the UI ? - loadContacts: function Model_loadContacts(callback) { - var contactsFoundCB, errorCB; - - this.contactsLoaded = null; - - contactsFoundCB = function (contacts) { - this.contactsLoaded = contacts; - if (callback instanceof Function) { - callback(); - } - }; - - errorCB = function (error) { - console.error( - 'Model_loadContacts, problem with find() method: ' + - error.message - ); - }; - - this.addressBook.find(contactsFoundCB.bind(this), errorCB); - }, - - /** - * Remove search filter from content and appends it to header - */ - // TODO FIXME HACK it is one big hack for web-ui-fw - // title need to be changed - removeSearchBarToHeader: function () { - $('#page-header').append($('#callView .ui-listview-filter')); - $.mobile.activePage.page('refresh'); - $('.ui-input-cancel').remove(); // patch for WebUI bug - $('#calllogListContent').trigger('resize'); // WebUi scrollview fix - }, - - /** - * Scroll to bottom - */ - scrollToBottom: function () { - var scrollView = $(".ui-scrollview-view"); - scrollView.css("-webkit-transform", "translate3d(0px, -" + - scrollView.height() + "px, 0px)"); - }, - - /** - * Binding visibility state change event - */ - onVisibilityChange: function () { - var self = this; - document.addEventListener('webkitvisibilitychange', function () { - if (document.webkitVisibilityState === 'hidden') { - self.updateCheckboxes(); - } else { - self.loadContacts(app.updateCallLists.bind(app)); - $('#callActionBtn, #smsActionBtn') - .removeClass('ui-disabled'); - } - }); - }, - - /** - * Store uid of checked entries in checkedLogs Array - */ - updateCheckboxes: function Ui_updateCheckboxes() { - // empty checkedLogs logs array - var checkedLogs = this.checkedLogs = []; - // iterate through the entries - $('#forCallerList li.call').each(function () { - // if entry cotains checked checkbox - if ($(this).find('form label').hasClass('ui-checkbox-on')) { - var checkedEntry = $(this).data('entries')[0]; - // push the entry uid to checkedLogs array - checkedLogs.push(checkedEntry.uid); - } - }); - }, - - /** - * Disabling element - * @param {jQuery} element - */ - lockButtons: function Ui_lockButtons(buttons) { - $(buttons).addClass('ui-disabled').attr('tabIndex', '-1').blur(); - }, - - /** - * Enabling element - * @param {jQuery} element - */ - unlockButtons: function Ui_unlockButtons() { - $('#callActionBtn, #smsActionBtn, #deleteActionBtn') - .removeClass('ui-disabled') - .attr('tabIndex', '0'); - }, - - /** - * HACK TODO FIXME; - * Patch for UI, bad refresh scrollView - */ - refreshScrollView: function () { - var scrollView = $('.ui-scrollview-view'), - show = function () { - scrollView.show(); - }; - scrollView.hide(); - setTimeout(show, 0); - }, - - /** - * Handle event when last log is removed - */ - removedLastLog: function () { - this.hideCheckboxes(); - $(".ui-popup").popup('close'); - $.mobile.changePage('#callView'); - } - }; + 'use strict'; + Ui.prototype = { + /** + * UI remove mode + * @type {boolean} + */ + removeMode: false, + + addressBook: tizen.contact.getDefaultAddressBook(), + + photoURIdefault: null, + + contactsLoaded: null, + + checkedLogs: [], + + /** + * @type {TemplateManager} + */ + templateManager: null, + + /** + * UI Initializer + */ + init: function Ui_init() { + this.loadContacts(); + this.templateManager = new TemplateManager(); + this.helpers = new Helpers(); + $(document).ready(this.domInit.bind(this)); + $.mobile.tizen.disableSelection(document); + }, + + /** + * When DOM is ready, initialise it (bind events) + */ + domInit: function Ui_domInit() { + this.templateManager.loadToCache(['callView', + 'callerHistory', + 'callItemRow', + 'callerCallItemRow', + 'messageWindow', + 'errorWindow', + 'dateRow'], this.initPages.bind(this)); + }, + + /** + * UI pages initializer + */ + initPages: function Ui_initPages() { + var pages = [], body = $('body'); + + body + .append(this.templateManager.get('messageWindow')) + .append(this.templateManager.get('errorWindow')) + .trigger('create'); + $('#callView') + .append($(this.templateManager.get('callView')) + .children()) + .trigger('pagecreate') + .trigger('pageshow'); + pages.push(this.templateManager.get('callerHistory')); + body.append(pages.join('')); + this.removeSearchBarToHeader(); + + this.addEvents(); + app.showCallHistory(); + + this.photoURIdefault = $("#header .photo").css('background-image'); + }, + + /** + * Add UI events + */ + addEvents: function Ui_addEvents() { + var self = this; + + $(window).on('resize', function () { + $.mobile.activePage.page('refresh'); + }); + + $('#callView').on('pagebeforeshow', function () { + app.showCallHistory(); + }); + + //original code, do not remove until web-ui release; N_SE-48946 + //$(".ui-scrollview-view").listview(); + + $('#historyForCallerView').on('pagebeforeshow', function () { + self.hideCheckboxes(); + $('#historyForCallerView .ui-content.ui-scrollview-clip .ui-scrollview-view') + .css('-webkit-transform', 'translate3d(0px, 0px, 0px)'); + $('#selectAllDetails').on('change', function () { + self.selectAll(); + }); + }); + + $('#historyForCallerView').on('pageshow', function () { + $('#content').css('top', '160px'); + $('#header').css('height', '160px'); + $('#callerListContainer') + .children('.ui-overflow-indicator-top', '.ui-overflow-indicator-bottom') + .hide(); + }); + + $('#callerListContainer').on('scrollstart', function () { + $(this) + .children('.ui-overflow-indicator-top', '.ui-overflow-indicator-bottom') + .fadeIn(200); + }); + + $('#callerListContainer').on('scrollstop', function () { + $(this) + .children('.ui-overflow-indicator-top', '.ui-overflow-indicator-bottom') + .fadeOut(200); + }); + + $('.selectAllBox').children().on('click', function () { + $('.selectAllBox input[type=checkbox]').trigger('click'); + self.selectAll(); + self.selectAllDetailsEach(); + }); + + $('#calllogList').on('click', '.date', function (event) { + event.stopPropagation(); + }); + + $('#calllogList').on('click', '.call', function onCalllogEntryClick(event) { + var remoteParty = $(this) + .data('entries')[0] + .remoteParties[0] + .remoteParty; + app.showHistoryForCaller(remoteParty); + $.mobile.changePage('#historyForCallerView'); + }); + + $('#smsActionBtn').on('click', function (event) { + event.stopPropagation(); + event.preventDefault(); + self.lockButtons('#smsActionBtn'); + self.hideCheckboxes(); + app.sendSms($('#forCallerList').data('remoteParty')); + }); + + $('#callActionBtn').on("click", function (event) { + self.lockButtons('#callActionBtn'); + self.hideCheckboxes(); + app.makeCall($('#forCallerList').data('remoteParty')); + }); + + $('#deleteActionBtn').on('click', function () { + self.changeDetailsToRemoveState(); + }); + + $('.selectAllBox').on('click', 'li', function () { + var checkbox = $(this).find(':checkbox'); + if (self.removeMode === true) { + if (checkbox.attr('checked')) { + checkbox.attr('checked', false) + .data('checkboxradio') + .refresh(); + } else { + checkbox.attr('checked', true) + .data('checkboxradio') + .refresh(); + } + self.setSelectAllDetails(); + } + }); + + $('#popup') + .on('click', '#popupCancelActionBtn', this.closePopup.bind(this)) + .on('click', '#popupSubmitActionBtn', this.deleteCheckedLogs.bind(this)); + + $('#errorPopup').on('click', '#errorPopupOkBtn', this.closeErrorPopup); + + $( "#errorPopup" ).bind({ + popupafterclose: function(){ + self.unlockButtons(); + } + }); + + $(window).keyup(function(e){ + if (e.which === 13) { + $('input:focus').blur(); + } + }); + + window.addEventListener('tizenhwkey', function(e) { + if (e.keyName == "back") { + if ($.mobile.popup.active) { + $.mobile.popup.active.close(); + } else if (self.removeMode === true) { + app.ui.changeDetailsToRemoveState(undefined, true); + } else if ($.mobile.activePage.attr('id') === 'callView') { + tizen.application.getCurrentApplication().exit(); + } else { + history.back(); + } + } + }); + self.onVisibilityChange(); + }, + + addEventsForCallerListCheckboxes: function Ui_addEventsForCallerListCheckboxes() { + var self = this; + $('#forCallerList :checkbox').on('change', function (event) { + if ($(this).attr('checked')) { + $(this).attr('checked', true); + } else { + $(this).attr('checked', false); + } + self.setSelectAllDetails(); + }); + }, + + selectAll: function () { + if ($('#selectAllDetails').attr('checked')) { + this.selectCheckbox($('#selectAllDetails'), true); + } else { + this.selectCheckbox($('#selectAllDetails'), false); + } + this.selectAllDetailsEach(); + }, + + selectCheckbox: function (obj, state) { + var deleteButton = $('#deleteActionBtn'), numChecked; + obj.attr('checked', state) + .data('checkboxradio') + .refresh(); + + numChecked = $('#forCallerList input:checked').length; + if (this.removeMode && numChecked === 0 && !deleteButton.hasClass('ui-disabled')) { + deleteButton.addClass('ui-disabled').attr('tabIndex', '-1').blur(); + } else if (deleteButton.hasClass('ui-disabled')) { + deleteButton.removeClass('ui-disabled').attr('tabIndex', '0'); + } + }, + + /** + * Returns number of selected call logs + * @return {number} length + */ + getCountSelectedLogEntries: function Ui_getCountSelectedLogEntries() { + return $('#forCallerList li .toRemove label.ui-checkbox-on').length; + }, + + selectAllDetailsEach: function Ui_selectAllDetailsEach() { + var self = this; + $('#forCallerList').find('input').each(function () { + if ($('#selectAllDetails').attr('checked')) { + self.selectCheckbox($(this), true); + } else { + self.selectCheckbox($(this), false); + } + }); + }, + + /** + * Hides checkboxes + */ + hideCheckboxes: function Ui_hideCheckboxes() { + var self = this; + this.selectCheckbox($('#selectAllDetails'), false); + + $('#forCallerList').find('input').each(function () { + self.selectCheckbox($(this), false); + }); + this.changeDetailsToRemoveState('hide'); + }, + + /** + * Returns css classes for specified entry + * + * @param {CallHistoryEntry} entry + * @returns {string} + */ + cssClassesForEntry: function Ui_cssClassesForEntry(entry) { + return 'call dir_' + entry.direction.toLowerCase() + ' type_' + entry.type.replace('.', '-').toLowerCase(); + }, + + setSelectAllDetails: function Ui_setSelectAllDetails() { + if ($('#forCallerList input[type="checkbox"]').length === + $('#forCallerList input[checked="checked"]').length) { + this.selectCheckbox($('#selectAllDetails'), true); + } else { + this.selectCheckbox($('#selectAllDetails'), false); + } + }, + + /** + * Shows popup with specified message + * @param {string} message + */ + showPopup: function Ui_showPopup(message) { + $('#popupMessage').html(message); + $('#popup').popup('open', {'positionTo': 'window'}); + }, + + /** + * Hides popup + */ + closePopup: function Ui_closePopup() { + $('#popup').popup('close'); + }, + + showErrorPopup: function Ui_showErrorPopup(message) { + $('#errorPopupMessage').html(message); + $('#errorPopup').popup('open', {'positionTo': 'window'}); + }, + + closeErrorPopup: function Ui_closeErrorPopup() { + $('#errorPopup').popup('close'); + }, + + /** + * Deletes checked log entries + */ + deleteCheckedLogs: function Ui_deleteCheckedLogs(e) { + this.closePopup(); + + this.selectCheckbox($('#selectAllDetails'), false); + + $('#forCallerList li.call').each(function () { + if ($(this).find('form label').hasClass('ui-checkbox-on')) { + app.deleteLog($(this).data('entries')[0]); + $(this).remove(); + } + }); + + if ($('#forCallerList li.call').length > 0) { + this.updateCallerHeaderNumberOfEntries($('#forCallerList li.call').length); + } else { + e.preventDefault(); + $('.ui-listview-filter .ui-input-text').val(''); + $('.ui-listview-filter .ui-input-text').trigger('change'); + $.mobile.changePage('#callView'); + } + + this.changeDetailsToRemoveState(true); + this.scrollToBottom(); + }, + + changeDetailsToRemoveState: function Ui_changeDetailsToRemoveState(set, clear) { + var counter = this.getCountSelectedLogEntries(), + numChecked = $('#forCallerList input:checked').length, + matrix, pos; + if (clear === true) { + counter = 0; + $('#forCallerList').find(':checkbox').attr('checked', false) + .data('checkboxradio').refresh(); + $('.selectAllBox').find(':checkbox').attr('checked', false) + .data('checkboxradio').refresh(); + } + if (set !== undefined) { + this.removeMode = false; + } else if (counter === 0) { + this.removeMode = !this.removeMode; + } + + if (this.removeMode && numChecked === 0) { + $('#deleteActionBtn').addClass('ui-disabled').attr('tabIndex', '-1').blur(); + } else if (!this.removeMode) { + $('#deleteActionBtn').removeClass('ui-disabled').attr('tabIndex', '0'); + this.selectAllDetailsEach(); + } + + if (counter === 0) { + if (this.removeMode) { + $('#historyForCallerView .toRemove').removeClass('hidden'); + $('#historyForCallerView .selectAllBox') + .removeClass('hidden'); + } else { + $('#historyForCallerView .toRemove').addClass('hidden'); + $('#historyForCallerView .selectAllBox').addClass('hidden'); + } + } else if (counter > 1) { + this.showPopup('Are you sure you want to delete selected logs?'); + } else { + this.showPopup('Are you sure you want to delete selected log?'); + } + + matrix = $('#historyForCallerView .ui-scrollview-view').css('transform'); + pos = matrix.substr(7, matrix.length -8).split(',')[5]; + if (pos !== undefined) { + $('#callerListContainer').scrollview('scrollTo', 100, parseInt(pos), 10); + } else { + this.refreshScrollView(); + } + }, + + /** + * Renders call history list + * + * @param {CallHistoryEntry[]} callEntries + */ + showCallHistory: function Ui_showCallHistory(callEntries) { + var self = this, + pdate = null, // previous date + date = '', + elements = [], // list elements + len = callEntries.length, // entries length + tempLength = 0, // length of temporary table; + i, // loop counter + j, // loop counter + current, // current entry object + today = this.helpers.getShortDate(new Date()), // today short date + entryShortDate, + filterResult, + groupsOfDays = [], + dayLog, + index = 0, + calllogList = $('#calllogList'), + calllogListContent = $('#calllogListContent'), + calllogListContentPos; + + function filterForSameEntry(element) { + return self.getNumber(current) === self.getNumber(element) + && current.direction === element.direction; + } + + $('.selectedCount').hide(); + + for (i = 0; i < len; i = i + 1) { + current = callEntries[i]; + date = this.helpers.toNativeDate(current.startTime); + + // if date is changed create new deyLog; + if (date !== pdate) { + dayLog = {}; + dayLog.date = date; + dayLog.entries = []; + dayLog.counters = []; + groupsOfDays.push(dayLog); + pdate = date; + } + + // group entries by remote Party; + filterResult = dayLog.entries.filter(filterForSameEntry); + if (filterResult.length) { + index = dayLog.entries.indexOf(filterResult[0]); + dayLog.counters[index] += 1; + } else { + dayLog.entries.push(current); + dayLog.counters[dayLog.entries.length - 1] = 1; + } + } + // Create UL list with dividers; + len = groupsOfDays.length; + for (i = 0; i < len; i += 1) { + dayLog = groupsOfDays[i]; + tempLength = dayLog.entries.length; + entryShortDate = this.helpers.getShortDate(dayLog.entries[0].startTime); + // add date header; + //original code, do not remove until web-ui release; N_SE-48946 +// elements.push($(this.templateManager.get('dateRow', { +// 'date': today === entryShortDate ? 'Today' : dayLog.date +// })).get(0)); + + for (j = 0; j < tempLength; j = j + 1) { + elements.push(this.getCallItemRow(dayLog.entries[j], dayLog.counters[j])); + } + } + calllogListContentPos = this.helpers.getScrollPosition(calllogListContent); + calllogList.empty().append(elements); + + /* workaround solution for searching phrase remain*/ + if ($("[data-type='search']").val().length != "") { + calllogList.listview('refresh'); + $("[data-type='search']").trigger("keyup"); + $(".ui-li-divider").removeClass("ui-li ui-li-divider ui-bar-s").addClass("date"); + } else { + calllogList.listview({ + autodividers: true, + //filter: true, + autodividersSelector: function ( li ) { + return $(li).find('.callDate').text() === app.ui.helpers.toNativeDate(new Date()) + ? "Today" : $(li).find('.callDate').text(); + } + }).listview('refresh'); + $(".ui-li-divider").removeClass().addClass("date"); + } + + setTimeout(this.helpers.scrollTo.bind(this, calllogListContent, calllogListContentPos), 10); + }, + + /** + * @param: {CallHistoryEntry} entry + */ + getNumber: function (entry) { + return entry.remoteParties[0].remoteParty; + }, + + /** + * Returns HTML for single log entry + * + * @param {CallHistoryEntry} entry + * @param {number} counter + * @returns {HTMLPartial} + */ + getCallItemRow: function Ui_getCallItemRow(entry, counter) { + var party = entry.remoteParties[0], + name = this.getNameByNumber(party.remoteParty), + tpl; + + if (counter > 1) { + name += ' (' + counter + ')'; + } + + tpl = this.templateManager.get('callItemRow', { + 'name': name, + 'callTime': this.helpers.toNativeTime(entry.startTime), + 'callDate': this.helpers.toNativeDate(entry.startTime), + 'cssClasses': this.cssClassesForEntry(entry), + 'uid': entry.uid + }); + + return $(tpl) + .data('remoteParty', entry.remoteParties[0].remoteParty) + .data('entries', [entry]) + .get(0); // return clean DOM element so array of those could be appended at once*/ + }, + + getNameByNumber: function (number) { + var i, j, contact, name; + for (i in this.contactsLoaded) { + if (this.contactsLoaded.hasOwnProperty(i)) { + contact = this.contactsLoaded[i]; + for (j in contact.phoneNumbers) { + if (contact.phoneNumbers.hasOwnProperty(j)) { + if (contact.phoneNumbers[j].number.substr(-9) + === number.substr(-9)) { + name = contact.name.displayName; + break; + } + } + } + } + } + return name || number || 'Unknown'; + }, + + /** + * Returns HTML for single caller log entry + * + * @param {CallHistoryEntry} entry + * @returns {HTMLElement} + */ + getCallerCallLogRow: function Ui_getCallerCallLogRow(entry) { + return $(this.templateManager.get('callerCallItemRow', { + 'cssClass': this.cssClassesForEntry(entry), + 'callTime': this.helpers.toNativeTime(entry.startTime), + 'callDuration': this.helpers.secondsToHours(entry.duration), + 'uid': entry.uid + })).data('entries', [entry]).get(0); + }, + + /** + * Renders call log list for specified caller + * + * @param {string} remoteParty + * @param {CallHistoryEntry[]} entries + */ + showHistoryForCaller: function Ui_showHistoryForCaller(remoteParty, entries) { + var pdate = '', + date = '', + elements = [], + len = entries.length, + i, + checkbox; + + if (len) { + this.updateCallerHeader(entries[0], entries.length); + } else { + // if last call log has been removed + this.removedLastLog(); + this.app.lastViewedCaller = 0; + } + + $('#forCallerList') + .data('remoteParty', remoteParty) + .data('modified', false) + .empty(); + + // group caller log entries by date + for (i = 0; i < len; i = i + 1) { + date = this.helpers.toNativeDate(entries[i].startTime); + + // if date is changed render new header + if (date !== pdate) { + elements.push($(this.templateManager.get('dateRow', {'date': date})).get(0)); + pdate = date; + } + elements.push(this.getCallerCallLogRow(entries[i])); + } + + $('#forCallerList') + .empty() + .append(elements); + + if (elements.length > 0) { + $('li#delete > a').addClass('ui-btn-active'); + } else { + $('li#delete > a').removeClass('ui-btn-active'); + } + + $('#forCallerList').trigger('create'); + + // change to remove mode if it was active before registering call + if (this.removeMode) { + this.removeMode = !this.removeMode; + this.changeDetailsToRemoveState(); + // check previous checked entries + this.checkedLogs.forEach(function(logUid){ + checkbox = $('#forCallerList li.call[data-uid="' + logUid + '"]') + .find(':checkbox'); + + if (checkbox.length > 0) { + checkbox.attr('checked', true) + .data('checkboxradio') + .refresh(); + $('#deleteActionBtn').removeClass('ui-disabled').attr('tabIndex', '0'); + } + }); + + this.setSelectAllDetails(); + + // close popup if there are no checked checkboxes + if (!$("#forCallerList input:checked").length) { + if ($.mobile.popup.active) { + $.mobile.popup.active.close(); + } + } + } + this.addEventsForCallerListCheckboxes(); + // lock buttons if unknown caller + if (remoteParty) { + this.unlockButtons(); + } else { + this.lockButtons('#callActionBtn, #smsActionBtn'); + } + }, + + /** + * Update accoundId + * @param {string} accountId + */ + updateCallerHeaderAccountId: function Ui_updateCallerHeaderAccountId(accountId) { + $('.infoContainer .accountId').html(accountId); + }, + + /** + * Update number of entries + * @param numberOfEntries + */ + updateCallerHeaderNumberOfEntries: function Ui_updateCallerHeaderNumberOfEntries(numberOfEntries) { + $('.infoContainer .numberOfEntries').html('' + numberOfEntries + ' ' + (numberOfEntries === 1 ? 'call' : 'calls')); + }, + + /** + * Updates caller main info + * @param {CallHistoryEntry} entry + * @param {number} numberOfEntries + */ + updateCallerHeader: function Ui_updateCallerHeader(entry, numberOfEntries) { + var name = '', party, imgPath, personId; + + $('#header .photo').css('background-image', this.photoURIdefault); + + if (entry.remoteParties !== null) { + party = entry.remoteParties[0]; + personId = parseInt(party.personId, 10); + name = this.getNameByNumber(party.remoteParty); + if (party.displayName) { + this.updateCallerHeaderAccountId(party.remoteParty); + } + this.updateCallerHeaderNumberOfEntries(numberOfEntries); + if (personId !== 0) { + imgPath = app.getPhotoURIForContact(personId); + if (imgPath !== false) { + $('#header .photo').css('background-image', 'url(' + imgPath + ')'); + } + } + } else if (entry.contactId !== null) { + name = entry.accountId; + this.updateCallerHeaderAccountId(entry.accountId); + this.updateCallerHeaderNumberOfEntries(numberOfEntries); + } else { + name = entry.accountId; + this.updateCallerHeaderAccountId(''); + this.updateCallerHeaderNumberOfEntries(numberOfEntries); + } + $('.contact > .infoContainer > .name').html(this.templateManager.modifiers.escape(name)); + + }, + + loadContacts: function Model_loadContacts(callback) { + var contactsFoundCB, errorCB; + + this.contactsLoaded = null; + + contactsFoundCB = function (contacts) { + this.contactsLoaded = contacts; + if (callback instanceof Function) { + callback(); + } + }; + + errorCB = function (error) { + console.error('Model_loadContacts, problem with find() method: ' + error.message); + }; + + this.addressBook.find(contactsFoundCB.bind(this), errorCB); + }, + + /** + * Remove search filter from content and appends it to header + */ + removeSearchBarToHeader: function () { + $('#page-header').append($('#callView .ui-listview-filter')); + $.mobile.activePage.page('refresh'); + $('.ui-input-cancel').remove(); // patch for WebUI bug + $('#calllogListContent').trigger('resize'); // WebUi scrollview fix + }, + + scrollToBottom: function () { + var scrollView = $(".ui-scrollview-view"); + scrollView.css("-webkit-transform", "translate3d(0px, -" + + scrollView.height() + "px, 0px)"); + }, + + onVisibilityChange: function () { + var self = this; + document.addEventListener('webkitvisibilitychange', function () { + if (document.webkitVisibilityState === 'hidden') { + self.checkedLogs = []; + $('#forCallerList li.call').each(function () { + if ($(this).find('form label') + .hasClass('ui-checkbox-on')) { + var checkedEntry = $(this).data('entries')[0]; + self.checkedLogs.push(checkedEntry.uid); + } + }); + } else { + self.loadContacts(app.updateCallLists.bind(app)); + $('#callActionBtn, #smsActionBtn') + .removeClass('ui-disabled'); + } + }); + }, + + lockButtons: function Ui_lockButtons(buttons) { + $(buttons).addClass('ui-disabled').attr('tabIndex', '-1').blur(); + }, + + unlockButtons: function Ui_unlockButtons(){ + $('#callActionBtn, #smsActionBtn').removeClass('ui-disabled').attr('tabIndex', '0'); + }, + + /** + * WORKAROUND; + * Patch for UI, bad refresh scrollView + */ + refreshScrollView: function () { + var scrollView = $('.ui-scrollview-view'), + show = function () { + scrollView.show(); + }; + scrollView.hide(); + setTimeout(show, 0); + }, + + removedLastLog: function () { + this.hideCheckboxes(); + $(".ui-popup").popup('close'); + $.mobile.changePage('#callView'); + } + }; }());