diff --git a/apps/communications/contacts/fb_link.html b/apps/communications/contacts/fb_link.html index 7d57dc932e18..9b9cc0857a6f 100644 --- a/apps/communications/contacts/fb_link.html +++ b/apps/communications/contacts/fb_link.html @@ -16,7 +16,9 @@ - + + + diff --git a/apps/communications/contacts/js/fb/fb_link.js b/apps/communications/contacts/js/fb/fb_link.js index a5cb56a48d61..2251598f56d9 100644 --- a/apps/communications/contacts/js/fb/fb_link.js +++ b/apps/communications/contacts/js/fb/fb_link.js @@ -35,18 +35,18 @@ if (!fb.link) { // Conditions var MAIL_COND = ['strpos(email, ' , "'", null, "'", ') >= 0']; var CELL_COND = ['strpos(cell, ' , "'", null, "'", ') >= 0']; - var NAME_COND = ['strpos(lower(name), ' , "'", null, - "'", ') >= 0']; - // Conditions over first name and last name (second query) - var FIRST_NAME_COND = ['strpos(lower(first_name), ' , "'", null, - "'", ') >= 0']; - var LAST_NAME_COND = ['strpos(lower(last_name), ' , "'", null, - "'", ') >= 0']; + var ALL_QUERY = ['SELECT uid, name, last_name, first_name,', + ' middle_name, email from user ', + ' WHERE uid IN (SELECT uid1 FROM friend WHERE uid2=me()) ', + ' ORDER BY name' + ]; - var ALL_QUERY = ['SELECT uid, name, email from user ', - ' WHERE uid IN (SELECT uid1 FROM friend WHERE uid2=me()) ', - ' ORDER BY name']; + var SEARCH_ACCENTS_FIELDS = { + 'last_name': 'familyName', + 'first_name': 'givenName', + 'middle_name': 'givenName' + }; var friendsList; var viewButton = document.querySelector('#view-all'); @@ -65,102 +65,67 @@ if (!fb.link) { function buildQuery(contact) { var filter = []; - if (contact.name && contact.name.length > 0 && - contact.name[0].length > 0) { - // First the name condition is put there - NAME_COND[2] = contact.name[0].trim().toLowerCase(); - } - else { - // The condition will be false by definition - NAME_COND[2] = 'A'; - } - - filter.push(NAME_COND.join('')); - if (contact.tel && contact.tel.length > 0) { contact.tel.forEach(function(tel) { - filter.push(' OR '); CELL_COND[2] = tel.value.trim(); filter.push(CELL_COND.join('')); + filter.push(' OR '); }); } if (contact.email && contact.email.length > 0) { contact.email.forEach(function(email) { - filter.push(' OR '); MAIL_COND[2] = email.value.trim(); filter.push(MAIL_COND.join('')); + filter.push(' OR '); }); } - SEARCH_QUERY[3] = filter.join(''); - - return SEARCH_QUERY.join(''); - } - - // Builds the second query (name-based) for findinding a linking contact - function buildQueryNames(contact) { - var filter = []; - - if (contact.givenName && contact.givenName.length > 0 && - contact.givenName[0].length > 0) { - // First the name condition is put there - FIRST_NAME_COND[2] = contact.givenName[0].trim().toLowerCase(); - } - else { - // The condition will be false by definition - FIRST_NAME_COND[2] = 'A'; + // Remove the last OR + if (filter.length > 0) { + filter[filter.length - 1] = null; } + var filterStr = filter.join(''); - filter.push(FIRST_NAME_COND.join('')); - filter.push(' OR '); - - if (contact.familyName && contact.familyName.length > 0 && - contact.familyName[0].length > 0) { - // First the name condition is put there - LAST_NAME_COND[2] = contact.familyName[0].trim().toLowerCase(); + var out; + if (filterStr) { + SEARCH_QUERY[3] = filterStr; + out = SEARCH_QUERY.join(''); } else { - // The condition will be false by definition - LAST_NAME_COND[2] = 'A'; + out = null; } - filter.push(LAST_NAME_COND.join('')); - - SEARCH_QUERY[3] = filter.join(''); - - var out = SEARCH_QUERY.join(''); - return out; } - // entry point for obtaining a remote proposal link.getRemoteProposal = function(acc_tk, contid) { var cid = contid || contactid; var req = fb.utils.getContactData(cid); - req.onsuccess = function() { if (req.result) { cdata = req.result; numQueries = 1; currentRecommendation = null; - doGetRemoteProposal(acc_tk, cdata, buildQuery(cdata)); + var query = buildQuery(cdata); + // Check whether we have enough info for the first query + // otherwise launch the getAll query + if (query === null) { + getRemoteProposalAll(acc_tk); + return; + } + doGetRemoteProposal(acc_tk, cdata, query); } else { throw ('FB: Contact to be linked not found: ', cid); } - } + }; req.onerror = function() { throw ('FB: Error while retrieving contact data: ', cid); - } - } - - function getRemoteProposalByNames(acc_tk, contact) { - numQueries++; - doGetRemoteProposal(acc_tk, cdata, buildQueryNames(contact)); - } + }; + }; function getRemoteProposalAll(acc_tk) { numQueries++; @@ -226,7 +191,7 @@ if (!fb.link) { // Obtains a linking proposal to be shown to the user link.getProposal = function(cid, acc_tk) { link.getRemoteProposal(acc_tk, cid); - } + }; // Executed when the server response is available link.proposalReady = function(response) { @@ -247,23 +212,59 @@ if (!fb.link) { } if (response.data.length === 0 && numQueries === 1) { - getRemoteProposalByNames(access_token, cdata); - } else if (response.data.length === 0 && numQueries === 2) { getRemoteProposalAll(access_token); - } else { + } + else { var data = response.data; currentRecommendation = data; - var numFriendsProposed = response.data.length; + var sortedByName = []; + var numFriendsProposed = data.length; + var searchAccentsArrays = {}; + var index = 0; data.forEach(function(item) { if (!item.email) { item.email = ''; } + // Only do this if we need to prepare the search accents phase + if (numQueries === 2) { + // Saving the original order + sortedByName.push(item); + // Populate the arrays for doing the accents related search + Object.keys(SEARCH_ACCENTS_FIELDS).forEach(function(field) { + searchAccentsArrays[field] = searchAccentsArrays[field] || []; + if (item[field]) { + // The different words for each item + var words = item[field].split(/[ ]+/); + // The whole word itself is added + words.push(item[field]); + words.forEach(function(word) { + var obj = { + originalIndex: index + }; + obj[field] = utils.text.normalize(word).toLowerCase(); + searchAccentsArrays[field].push(obj); + }); + } + }); + index++; + } }); - if (numQueries === 3) { - mainSection.classList.add('no-proposal'); - numFriendsProposed = 0; + if (numQueries === 2) { + var accentsProposal = searchAccents(searchAccentsArrays, cdata); + if (accentsProposal.length === 0) { + data = sortedByName; + mainSection.classList.add('no-proposal'); + numFriendsProposed = 0; + } + else { + currentRecommendation = []; + accentsProposal.forEach(function(proposalIndex) { + currentRecommendation.push(sortedByName[proposalIndex]); + }); + numFriendsProposed = currentRecommendation.length; + } } else { viewButton.textContent = _('viewAll'); viewButton.onclick = UI.viewAllFriends; @@ -273,11 +274,66 @@ if (!fb.link) { numFriends: numFriendsProposed }); - utils.templates.append('#friends-list', data); + utils.templates.append('#friends-list', currentRecommendation); imgLoader.reload(); Curtain.hide(sendReadyEvent); } + }; + + + // This function needs to be called because link proposals through FB Query + // do not work properly with words with special characters (bug 796714) + function searchAccents(searchArrays, contactData) { + var out = []; + var searchFields = Object.keys(SEARCH_ACCENTS_FIELDS); + + function compareItems(target, item) { + var out; + + if (typeof target === 'string') { + out = target.localeCompare(item); + if (out !== 0) { + if (item.indexOf(target) === 0) { + out = 0; + } + } + } + + return out; + } // compareItems Function + + searchFields.forEach(function(searchField) { + // The array is ordered according to the search field + // this enables an efficient binary search + var searchArray = searchArrays[searchField].sort(function(a, b) { + return a[searchField].localeCompare(b[searchField]); + }); + + var fieldToSearch = contactData[SEARCH_ACCENTS_FIELDS[searchField]]; + if (fieldToSearch && fieldToSearch[0]) { + // Splitting in the different words + var dataToSearch = fieldToSearch[0].trim().split(/[ ]+/); + + dataToSearch.forEach(function(aData) { + var targetString = utils.text.normalize(aData).toLowerCase(); + var searchResult = utils.binarySearch(targetString, searchArray, { + arrayField: searchField, + compareFunction: compareItems + }); + + searchResult.forEach(function(aResult) { + var candidate = searchArray[aResult].originalIndex; + // Avoiding to show two times the same result element + if (out.indexOf(candidate) === -1) { + out.push(candidate); + } + }); + }); + } + }); + + return out; } function sendReadyEvent() { @@ -289,16 +345,16 @@ if (!fb.link) { function setCurtainHandlersErrorProposal() { Curtain.oncancel = function() { cancelCb(true); - } + }; Curtain.onretry = function getRemoteProposal() { Curtain.oncancel = function() { cancelCb(true); - } + }; Curtain.show('wait', state); link.getRemoteProposal(access_token, contactid); - } + }; } link.baseHandler = function(type) { @@ -318,20 +374,20 @@ if (!fb.link) { } } }); - } + }; Curtain.oncancel = Curtain.hide; } Curtain.show(type, state); - } + }; link.timeoutHandler = function() { link.baseHandler('timeout'); - } + }; link.errorHandler = function() { link.baseHandler('error'); - } + }; /** * Clears the list of contacts @@ -363,7 +419,7 @@ if (!fb.link) { }); clearList(); - + var fragment = document.createDocumentFragment(); utils.templates.append(friendsList, response.data, fragment); friendsList.appendChild(fragment); @@ -386,7 +442,7 @@ if (!fb.link) { } Curtain.show('error', 'friends'); } - } + }; function setCurtainHandlers() { Curtain.oncancel = function curtain_cancel() { @@ -412,7 +468,7 @@ if (!fb.link) { else { link.getProposal(contactId, acc_tk); } - } + }; function retryOnErrorCb() { UI.selected({ @@ -433,7 +489,7 @@ if (!fb.link) { type: 'token_error', data: '' }, fb.CONTACTS_APP_ORIGIN); - } + }; window.asyncStorage.removeItem(fb.utils.TOKEN_DATA_KEY, cb); } @@ -464,7 +520,7 @@ if (!fb.link) { Curtain.hide(function() { notifyParent(importReq.result); }); - } + }; importReq.onerror = function(e) { var error = e.target.error; @@ -478,21 +534,21 @@ if (!fb.link) { Curtain.onretry = handleTokenError; } Curtain.show('error', 'linking'); - } + }; importReq.ontimeout = function() { link.baseHandler('timeout'); - } + }; } - } + }; req.onerror = function() { window.console.error('FB: Error while importing friend data'); Curtain.oncancel = Curtain.hide; Curtain.onretry = retryOnErrorCb; Curtain.show('error', 'linking'); - } - } + }; + }; UI.end = function(event) { @@ -502,7 +558,7 @@ if (!fb.link) { }; parent.postMessage(msg, fb.CONTACTS_APP_ORIGIN); - } + }; function notifyParent(data) { var msg = { @@ -525,7 +581,7 @@ if (!fb.link) { } return false; - } + }; UI.viewRecommended = function(event) { // event.target === viewButton @@ -537,7 +593,7 @@ if (!fb.link) { imgLoader.reload(); return false; - } + }; })(document); } diff --git a/apps/communications/contacts/js/utilities/binary_search.js b/apps/communications/contacts/js/utilities/binary_search.js new file mode 100644 index 000000000000..2a303665f667 --- /dev/null +++ b/apps/communications/contacts/js/utilities/binary_search.js @@ -0,0 +1,124 @@ +'use strict'; + +var utils = this.utils || {}; + +/** + * This function performs a binary search over an already sorted array + * target is the target item to search for + * array is the sorted array + * options is an optional object which may contain + * the start and end position (from, to) + * an optional arrayField which indicates the object property that contains the + * comparable item and transform and compare functions + * + * Returns an array with the positions on which the target item was found + * + */ +utils.binarySearch = function(target, array, options) { + var arrayField = options.arrayField, + transformFunction = options.transformFunction, + compareFunction = options.compareFunction; + + // Obtains the comparable item by transforming if necessary + function getItem(array, index) { + var item = array[index]; + if (arrayField) { + item = item[arrayField]; + if (typeof transformFunction === 'function') { + item = transformFunction(item); + } + } + return item; + } + + // Compares the target with an array item + function compare(target, item) { + var out; + if (typeof compareFunction === 'function') { + out = compareFunction(target, item); + } + else { + if (typeof target === 'string') { + out = target.localeCompare(item); + } + else { + out = target.toString().localeCompare(item); + } + } + + return out; + } + + var from = options.from; + if (typeof from === 'undefined') { + from = 0; + } + var to = options.to; + if (typeof to === 'undefined') { + to = array.length - 1; + } + + if (to < from) { + // Not found + return []; + } + + var middleIndex = Math.floor((to - from) / 2); + var item = getItem(array, from + middleIndex); + + var compareResult = compare(target, item); + + if (compareResult === 0) { + // Once a result is found let's iterate in both directions to get the rest + // Just in case there are more than one result + var results = [from + middleIndex]; + + var next = from + middleIndex + 1; + var finish = false; + while (next <= (array.length - 1) && !finish) { + var item = getItem(array, next); + + if (compare(target, item) === 0) { + results.push(next); + } + else { + finish = true; + } + next++; + } + + finish = false; + next = from + middleIndex - 1; + + while (next >= 0 && !finish) { + var item = getItem(array, next); + + if (compare(target, item) === 0) { + results.push(next); + } + else { + finish = true; + } + next--; + } + return results; + } + else if (compareResult < 0) { + return utils.binarySearch(target, array, { + from: from, + to: to - middleIndex - 1, + arrayField: arrayField, + transformFunction: transformFunction, + compareFunction: compareFunction + }); + } + else { + return utils.binarySearch(target, array, { + from: from + middleIndex + 1, + to: to, + arrayField: arrayField, + transformFunction: transformFunction, + compareFunction: compareFunction + }); + } +}; diff --git a/apps/costcontrol/js/app.js b/apps/costcontrol/js/app.js index 2961a32ed561..17062c22d61c 100644 --- a/apps/costcontrol/js/app.js +++ b/apps/costcontrol/js/app.js @@ -11,24 +11,26 @@ var CostControlApp = (function() { 'use strict'; + // XXX: This is the point of entry, check common.js for more info + waitForDOMAndMessageHandler(window, onReady); var costcontrol, initialized = false; - window.addEventListener('DOMContentLoaded', function _onDOMReady() { + function onReady() { var mobileConnection = window.navigator.mozMobileConnection; // SIM is not ready if (mobileConnection.cardState !== 'ready') { debug('SIM not ready:', mobileConnection.cardState); - mobileConnection.oniccinfochange = _onDOMReady; + mobileConnection.oniccinfochange = onReady; // SIM is ready } else { mobileConnection.oniccinfochange = undefined; - _startApp(); + startApp(); } - }); + } - function _startApp() { + function startApp() { checkSIMChange(function _onSIMChecked() { CostControl.getInstance(function _onCostControlReady(instance) { if (ConfigManager.option('fte')) { @@ -104,7 +106,6 @@ var CostControlApp = (function() { initialized = true; } - var currentMode; function updateUI() { ConfigManager.requestSettings(function _onSettings(settings) { diff --git a/apps/costcontrol/js/common.js b/apps/costcontrol/js/common.js index 0026e0be9d66..1a8c70020bc8 100644 --- a/apps/costcontrol/js/common.js +++ b/apps/costcontrol/js/common.js @@ -11,7 +11,8 @@ function checkSIMChange(callback) { } ConfigManager.requestSettings(function _onSettings(settings) { if (settings.nextReset) { - setNextReset(settings.nextReset); + setNextReset(settings.nextReset, callback); + return; } if (callback) { @@ -21,21 +22,41 @@ function checkSIMChange(callback) { }); } +// Waits for DOMContentLoaded and messagehandlerready, then call the callback +function waitForDOMAndMessageHandler(window, callback) { + var remainingSteps = 2; + function checkReady(evt) { + debug(evt.type, 'event received!'); + remainingSteps--; + + // Once all events are received, execute the callback + if (!remainingSteps) { + window.removeEventListener('DOMContentLoaded', checkReady); + window.removeEventListener('messagehandlerready', checkReady); + debug('DOMContentLoaded and messagehandlerready received. Starting'); + callback(); + } + } + + window.addEventListener('DOMContentLoaded', checkReady); + window.addEventListener('messagehandlerready', checkReady); +} + function addAlarmTimeout(type, delay) { var proxy = document.getElementById('message-handler').contentWindow; return proxy.addAlarmTimeout(type, delay); } -function setNextReset(when) { +function setNextReset(when, callback) { var proxy = document.getElementById('message-handler'); - return proxy ? proxy.contentWindow.setNextReset(when) : setNextReset(when); + return proxy ? proxy.contentWindow.setNextReset(when, callback) : + setNextReset(when, callback); } // Next automatic reset date based on user preferences -function updateNextReset(trackingPeriod, value) { +function updateNextReset(trackingPeriod, value, callback) { if (trackingPeriod === 'never') { - setNextReset(null); // remove oldAlarm - debug('Automatic reset disabled'); + setNextReset(null, callback); // remove any alarm return; } @@ -63,10 +84,11 @@ function updateNextReset(trackingPeriod, value) { daysToTarget = 7 + daysToTarget; nextReset = new Date(); nextReset.setTime(nextReset.getTime() + oneDay * daysToTarget); + toMidnight(nextReset); } // remove oldAlarm and set the new one - setNextReset(nextReset); + setNextReset(nextReset, callback); } function resetData() { diff --git a/apps/costcontrol/js/fte.js b/apps/costcontrol/js/fte.js index 0194a52a877c..aa6025c236ce 100644 --- a/apps/costcontrol/js/fte.js +++ b/apps/costcontrol/js/fte.js @@ -8,6 +8,10 @@ var costcontrol; var hasSim = true; + + // Fallback from some values, just in case they are missed from configuration + var DEFAULT_LOW_LIMIT_THRESHOLD = 3; + var defaultLowLimitThreshold = DEFAULT_LOW_LIMIT_THRESHOLD; window.addEventListener('DOMContentLoaded', function _onDOMReady() { var mobileConnection = window.navigator.mozMobileConnection; var stepsLeft = 2; @@ -46,11 +50,17 @@ ConfigManager.requestAll(function _onSettings(configuration, settings) { wizard = document.getElementById('firsttime-view'); vmanager = new ViewManager(); + + // Getting some values from config + if (configuration && configuration.default_low_limit_threshold) { + defaultLowLimitThreshold = configuration.default_low_limit_threshold; + } + AutoSettings.addType('data-limit', dataLimitConfigurer); // Currency is set by config as well - if (configuration && configuration.credit - && configuration.credit.currency) { + if (configuration && configuration.credit && + configuration.credit.currency) { document.getElementById('currency').textContent = configuration.credit.currency; @@ -118,7 +128,12 @@ currentTrack = ['step-1', 'step-2', 'prepaid-step-2', 'prepaid-step-3']; AutoSettings.initialize(ConfigManager, vmanager, '#prepaid-step-2'); AutoSettings.initialize(ConfigManager, vmanager, '#prepaid-step-3'); - ConfigManager.setOption({ dataLimitValue: 40, dataLimitUnit: 'MB' }); + + ConfigManager.setOption({ + dataLimitValue: 40, + dataLimitUnit: 'MB', + lowLimit: true, + lowLimitThreshold: defaultLowLimitThreshold }); } else if (evt.target.value === 'postpaid') { currentTrack = ['step-1', 'step-2', 'postpaid-step-2', 'postpaid-step-3']; AutoSettings.initialize(ConfigManager, vmanager, '#postpaid-step-2'); @@ -199,11 +214,15 @@ step -= 1; } - function onFinish() { + function onFinish(evt) { + evt.target.disabled = true; ConfigManager.requestSettings(function _onSettings(settings) { - updateNextReset(settings.trackingPeriod, settings.resetTime); ConfigManager.setOption({ fte: false }, function _returnToApp() { - window.location = 'index.html'; + updateNextReset(settings.trackingPeriod, settings.resetTime, + function _returnToTheApplication() { + window.location = 'index.html'; + } + ); }); }); } diff --git a/apps/costcontrol/js/message_handler.js b/apps/costcontrol/js/message_handler.js index 8f9df107b81d..2af3eb62abf7 100644 --- a/apps/costcontrol/js/message_handler.js +++ b/apps/costcontrol/js/message_handler.js @@ -6,6 +6,12 @@ function inStandAloneMode() { return window.parent.location.pathname === '/message_handler.html'; } + + // Redirect global objects to parent versions to avoid conflicts + if (!inStandAloneMode()) { + ConfigManager = window.parent.ConfigManager; + } + // XXX: This case implies that message handler triggered by system // (inStandAlone check) has replaced CC application (history's length check). // @@ -15,7 +21,7 @@ // inside an iframe (no standalone mode), all the messages should be attended // so we can conclude **there is nothing to do**. if (inStandAloneMode() && window.history.length > 1) { - debug('Nothing to do, closing...') + debug('Nothing to do, closing...'); window.history.back(); } @@ -46,30 +52,46 @@ // XXX: Remove from here when this is solved // https://bugzilla.mozilla.org/show_bug.cgi?id=800431 - function setNextReset(when) { + function setNextReset(when, callback) { + + // XXX: This is not part of configuration by SIM so we bypass ConfigManager asyncStorage.getItem('nextResetAlarm', function(id) { + // There is already an alarm, remove it debug('Current nextResetAlarm', id + '.', id ? 'Removing.' : ''); - if (id) + if (id) { navigator.mozAlarms.remove(id); + } + // If no when, disable alarms passing null if (!when) { - ConfigManager.setOption({ nextReset: null }); + debug('Automatic reset disabled'); + updateResetAttributes(null, null, callback); return; } - var request = navigator.mozAlarms.add(when, 'ignoreTimezone', - {type: 'nextReset' }); + // If when is provided, request an alarm an set the new values + var alarms = navigator.mozAlarms; + var request = alarms.add(when, 'ignoreTimezone', {type: 'nextReset' }); request.onsuccess = function _onSuccess() { - ConfigManager.setOption({ nextReset: when }, function _sync() { - localStorage['sync'] = 'nextReset#' + Math.random(); - }); debug('Setting nextResetAlarm', request.result, 'to', when); - asyncStorage.setItem('nextResetAlarm', request.result); + updateResetAttributes(request.result, when, callback); }; }); - }; + } window.setNextReset = setNextReset; + // Update the nextResetAlarm and nextReset values and request for + // synchronization. + function updateResetAttributes(alarmId, date, callback) { + asyncStorage.setItem('nextResetAlarm', alarmId, function _updateOption() { + ConfigManager.setOption({ nextReset: date }, function _sync() { + localStorage['sync'] = 'nextReset#' + Math.random(); + if (callback) + callback(); + }); + }); + } + // Register in standalone or for application if (inStandAloneMode() || inApplicationMode()) { debug('Installing handlers'); @@ -253,4 +275,8 @@ ); } + + // Notify message handler is ready + var readyEvent = new CustomEvent('messagehandlerready'); + window.parent.dispatchEvent(readyEvent); }()); diff --git a/apps/costcontrol/js/views/balance.js b/apps/costcontrol/js/views/balance.js index 7bcebc1ecb13..a46f5eb3d2ea 100644 --- a/apps/costcontrol/js/views/balance.js +++ b/apps/costcontrol/js/views/balance.js @@ -231,7 +231,6 @@ var BalanceTab = (function() { setBalanceMode(status === 'error' ? 'warning' : 'updating'); if (status === 'error') setErrors(status.details); - debug(settings); updateBalance(balance, settings.lowLimit && settings.lowLimitThreshold); }); diff --git a/apps/costcontrol/js/widget.js b/apps/costcontrol/js/widget.js index 30cf0d6407dd..8cdc279c452d 100644 --- a/apps/costcontrol/js/widget.js +++ b/apps/costcontrol/js/widget.js @@ -12,30 +12,33 @@ 'use strict'; + // XXX: This is the point of entry, check common.js for more info + waitForDOMAndMessageHandler(window, onReady); + var costcontrol; var hasSim = true; - window.addEventListener('DOMContentLoaded', function _onDOMReady() { + function onReady() { var mobileConnection = window.navigator.mozMobileConnection; // No SIM if (!mobileConnection || mobileConnection.cardState === 'absent') { hasSim = false; - _startWidget(); + startWidget(); // SIM is not ready } else if (mobileConnection.cardState !== 'ready') { debug('SIM not ready:', mobileConnection.cardState); - mobileConnection.oniccinfochange = _onDOMReady; + mobileConnection.oniccinfochange = onReady; // SIM is ready } else { debug('SIM ready. ICCID:', mobileConnection.iccInfo.iccid); mobileConnection.oniccinfochange = undefined; - _startWidget(); + startWidget(); } - }); + }; - function _startWidget() { + function startWidget() { checkSIMChange(function _onSIMChecked() { CostControl.getInstance(function _onCostControlReady(instance) { costcontrol = instance; @@ -175,7 +178,7 @@ setupFte(configuration.provider, mode); return; } else { - fte.setAttribute('aria-hidden', true) + fte.setAttribute('aria-hidden', true); } // Always data usage diff --git a/apps/homescreen/everything.me/config/config.js b/apps/homescreen/everything.me/config/config.js index 465a7708dd56..92fa678be1b7 100644 --- a/apps/homescreen/everything.me/config/config.js +++ b/apps/homescreen/everything.me/config/config.js @@ -60,7 +60,6 @@ Evme.__config = { } } }, - "infoLogger": false, "maxHistoryEntries": "10", "iconsGroupSettings": [ { diff --git a/apps/homescreen/everything.me/js/Brain.js b/apps/homescreen/everything.me/js/Brain.js index 26b85469ff19..e761ace2e0f4 100644 --- a/apps/homescreen/everything.me/js/Brain.js +++ b/apps/homescreen/everything.me/js/Brain.js @@ -7,7 +7,6 @@ Evme.Brain = new function Evme_Brain() { var self = this, Brain = this, _config = {}, - logger = null, elContainer = null, QUERIES_TO_NOT_CACHE = "", DEFAULT_NUMBER_OF_APPS_TO_LOAD = 16, @@ -70,8 +69,6 @@ Evme.Brain = new function Evme_Brain() { DISPLAY_INSTALLED_APPS = _config.displayInstalledApps; - logger = _config && _config.logger || console; - ICON_SIZE = Evme.Utils.sendToOS(Evme.Utils.OSMessages.GET_ICON_SIZE); }; @@ -106,16 +103,13 @@ Evme.Brain = new function Evme_Brain() { * @_event (string) : the event that the class sent * @_data (object) : data sent with the event */ - function catchCallback(_class, _event, _data) { - logger.debug(_class + "." + _event + "(", (_data || ""), ")"); - - Evme.Utils.log(_class + '.' + _event); + function catchCallback(_class, _event, _data) { + Evme.Utils.log('Callback: ' + _class + '.' + _event); try { self[_class] && self[_class][_event] && self[_class][_event](_data || {}); } catch(ex){ Evme.Utils.log('CB Error! ' + ex.message); - logger.error(ex); } } @@ -631,6 +625,11 @@ Evme.Brain = new function Evme_Brain() { Evme.Banner.show('app-install-success', { 'name': data.data.name }); + + Evme.EventHandler.trigger("App", "addToHomeScreen", { + "id": data.data.id, + "name": data.data.name + }); }); }; @@ -682,6 +681,7 @@ Evme.Brain = new function Evme_Brain() { "favUrl": data.app.getFavLink(), "name": data.data.name, "id": data.appId, + "appType": data.data.appType || "cloud", "query": Searcher.getDisplayedQuery(), "source": Searcher.getDisplayedSource(), "icon": data.data.icon, @@ -689,6 +689,7 @@ Evme.Brain = new function Evme_Brain() { }; var elApp = data.el, + appGridPosition = data.app.getPositionOnGrid(), appBounds = elApp.getBoundingClientRect(), elAppsList = elApp.parentNode.parentNode, @@ -703,6 +704,12 @@ Evme.Brain = new function Evme_Brain() { "left": (appsListBounds.width - appBounds.width)/2 }; + // update analytics data + loadingAppAnalyticsData.rowIndex = appGridPosition.row; + loadingAppAnalyticsData.colIndex = appGridPosition.col; + loadingAppAnalyticsData.totalRows = appGridPosition.rows; + loadingAppAnalyticsData.totalCols = appGridPosition.cols; + Evme.$remove("#loading-app"); var elPseudo = Evme.$create('li', {'class': "inplace", 'id': "loading-app"}, loadingApp.getCurrentHtml()), @@ -1559,6 +1566,7 @@ Evme.Brain = new function Evme_Brain() { 'name': name, 'installed': true, 'appUrl': app.origin, + 'appType': app.isBookmark ? 'bookmark' : 'installed', 'preferences': '', 'icon': Evme.Utils.sendToOS(Evme.Utils.OSMessages.GET_APP_ICON, app), 'requiresLocation': false, diff --git a/apps/homescreen/everything.me/js/Core.js b/apps/homescreen/everything.me/js/Core.js index 319722d97c4e..c065ec590f93 100644 --- a/apps/homescreen/everything.me/js/Core.js +++ b/apps/homescreen/everything.me/js/Core.js @@ -1,5 +1,5 @@ window.Evme = new function Evme_Core() { - var NAME = "Core", self = this, logger, + var NAME = "Core", self = this, recalculateHeightRetries = 1, TIMEOUT_BEFORE_INIT_SESSION = "FROM CONFIG", OPACITY_CHANGE_DURATION = 300, @@ -10,8 +10,6 @@ window.Evme = new function Evme_Core() { this.init = function init() { data = Evme.__config; - logger = (typeof Logger !== "undefined") ? new Logger() : console; - var apiHost = Evme.Utils.getUrlParam("apiHost") || data.apiHost; apiHost && Evme.api.setHost(apiHost); @@ -19,7 +17,6 @@ window.Evme = new function Evme_Core() { Evme.Brain.init({ "numberOfAppsToLoad": data.numberOfAppsToLoad, - "logger": logger, "minimumLettersForSearch": data.minimumLettersForSearch, "timeBeforeAllowingDialogsRemoval": data.timeBeforeAllowingDialogsRemoval, "tips": data.tips, @@ -140,7 +137,6 @@ window.Evme = new function Evme_Core() { Evme.Analytics.init({ "config": data.analytics, - "logger": logger, "namespace": Evme, "DoATAPI": Evme.DoATAPI, "getCurrentAppsRowsCols": Evme.Apps.getCurrentRowsCols, diff --git a/apps/homescreen/everything.me/js/api/DoATAPI.js b/apps/homescreen/everything.me/js/api/DoATAPI.js index 2c0a6bc29255..4a052fc826b0 100644 --- a/apps/homescreen/everything.me/js/api/DoATAPI.js +++ b/apps/homescreen/everything.me/js/api/DoATAPI.js @@ -23,6 +23,11 @@ Evme.DoATAPI = new function Evme_DoATAPI() { requestsToPerformOnOnline = [], sessionInitRequest = null, + // here we will save the actual params to pass + savedParamsToPass = {}, + // which param to pass from normal requests to stats and logs + PARAM_TO_PASS_FROM_REQUEST_TO_STATS = "requestId", + requestsToCache = { "Search.apps": true, "Search.bgimage": true, @@ -37,6 +42,14 @@ Evme.DoATAPI = new function Evme_DoATAPI() { doesntNeedSession = { "Session.init": true, "Search.trending": true + }, + + /* + * config of params to pass from requests to reports + * "Search.apps": ["appClick", "returnFromApp"] + */ + paramsToPassBetweenRequests = { + "Search.apps": ["appClick", "loadMore", "addToHomeScreen"] }; this.ERROR_CODES = { @@ -395,6 +408,7 @@ Evme.DoATAPI = new function Evme_DoATAPI() { methodArr.forEach(function oggerMethodIteration(method){ self[method] = function report(options, callback){ options = addGlobals(options); + options = addSavedParams(options); return request({ "methodNamespace": "Logger", @@ -408,6 +422,7 @@ Evme.DoATAPI = new function Evme_DoATAPI() { this.report = function report(options, callback) { options = addGlobals(options); + options = addSavedParams(options); return request({ "methodNamespace": "Stats", @@ -430,6 +445,46 @@ Evme.DoATAPI = new function Evme_DoATAPI() { return options; } + // add the saved params from earlier responses to the event's data + function addSavedParams(options) { + var events = options.data; + if (events) { + try { + events = JSON.parse(events); + } catch(ex) { + events = null; + } + + if (events && typeof events === "object") { + for (var i=0,e; e=events[i++];) { + var savedValue = savedParamsToPass[e.userEvent]; + if (savedValue) { + e[PARAM_TO_PASS_FROM_REQUEST_TO_STATS] = savedValue; + } + } + + options.data = JSON.stringify(events); + } + } + return options; + } + + // takes a method's response, and saves data according to paramsToPassBetweenRequests + function saveParamFromRequest(method, response) { + var events = paramsToPassBetweenRequests[method], + paramValue = response && response[PARAM_TO_PASS_FROM_REQUEST_TO_STATS]; + + if (!paramValue || !events) { + return; + } + + // this will create a map of userEvents => requestId + // to be added to the actual event request later + for (var i=0,ev; ev=events[i++];) { + savedParamsToPass[ev] = paramValue; + } + } + this.searchLocations = function searchLocations(options, callback) { !options && (options = {}); @@ -718,6 +773,7 @@ Evme.DoATAPI = new function Evme_DoATAPI() { if (!ignoreCache) { var fromCache = getFromCache(cacheKey); if (fromCache) { + saveParamFromRequest(methodNamespace + '.' + methodName, fromCache); callback && window.setTimeout(function() { callback(fromCache); }, 10); @@ -913,6 +969,8 @@ Evme.DoATAPI = new function Evme_DoATAPI() { } function cbSuccess(methodNamespace, method, url, params, retryNumber, data, requestDuration) { + saveParamFromRequest(methodNamespace + '.' + method, data); + Evme.EventHandler.trigger(NAME, "success", { "method": methodNamespace + "/" + method, "params": params, diff --git a/apps/homescreen/everything.me/js/developer/log4js2.js b/apps/homescreen/everything.me/js/developer/log4js2.js deleted file mode 100644 index b2cf87c0fd6d..000000000000 --- a/apps/homescreen/everything.me/js/developer/log4js2.js +++ /dev/null @@ -1,372 +0,0 @@ -/** - * @fileoverview Javascript Logger (in the spirit of log4j) - * This library is designed to make the writing and debugging - * of javascript code easier, by allowing the programmer to perform - * debug or log output at any place in their code. This supports - * the concept of different levels of logging (debug < info < warn < error < fatal << none) - * as well as different log outputs. Three log outputs are included, but you can - * add your own. The included log outputs are {@link Log#writeLogger}, - * {@link Log#alertLogger}, and {@link Log#popupLogger}. For debugging on Safari, - * the log ouput {@link Log#consoleLogger} is also included. To turn off debugging - * but still leave the logger calls in your script, use the log level {@link Log#NONE}. - * - * Example usage: - *
- * <html>
- *  <head>
- *      <script src="log4js.js" type="text/javascript"></script>
- *  </head>
- *  <body>
- *     Log4JS test...<hr/>
- *     <script>
- *        // Setup log objects
- *        //
- *        //  log object of priority debug and the popup logger
- *        var log = new Log(Log.DEBUG, Log.popupLogger);
- *        //  log object of priority warn and the alert logger
- *        var log2 = new Log(Log.WARN, Log.alertLogger);
- *        //  log object of priority debug and the console logger (Safari)
- *        var log3 = new Log(Log.DEBUG, Log.consoleLogger);
- *
- *        log.debug('foo1');     // will popup a new window and log 'foo'
- *        log.warn('bar1');      // will add a new 'bar' message to the popup
- *        log2.debug('foo2');    // will do nothing (Log object's priority threshold is WARN)
- *        log2.warn('bar2');     // will display a javascript alert with the string 'bar'
- *        log3.debug('foo3');    // will log message to Safari console or existing popup
- *        log3.warn('bar3');     // same
- *
- *        log.info(Log.dumpObject(new Array('apple','pear','orange','banana')));
- *     </script>
- *  </body>
- * </html>
- * 
- * - * @author Marcus R Breese mailto:mbreese@users.sourceforge.net - * @license Apache License 2.0 - * @version 0.31 - *
- **************************************************************
- *
- * Copyright 2005 Fourspaces Consulting, LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
- *
- * http://www.apache.org/licenses/LICENSE-2.0 
- *
- * 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
- *
- **************************************************************
- *
- * Changelog:
- * 0.31 Bug fix (resizeable should be resizable - Darryl Lyons)
- * 0.3  Migrated to SF.net SVN repository - test cleanups
- * 0.2  - Added consoleLogger for Safari
- *      - Changed popupLogger so that it only notifies once (or twice)
- *        that a popup blocker is active.   
- *      - Added Log.NONE level for silencing all logging
- * 
- */ - - - -/** - * Create a new logger - * @constructor - * @class The main Log class. Create a new instance of this class to send all logging events. - * @param level The cut-off logger level. You can adjust this level in the constructor and leave all other logging events in place. Defaults to {@link Log#WARN}. - * @param logger The logger to use. The logger is a function that accepts the logging events and informs the user or developer. Defaults to {@link Log#writeLogger}. - */ -function Log(level,logger,prefix) { - var _currentLevel = Log.WARN; - var _logger = Log.writeLogger; // default to write Logger - var _prefix = false; - this._isMobileBrowser = Log.isMobileBrowser(); - /** - * Sets the current logger prefix - * @param {String} prefix This prefix will be prepended to all messages. - */ - this.setPrefix = function setPrefix(pre) { - if (pre!='undefined') { _prefix = pre; } - else { _prefix = false; } - } - /** - * Sets the current logger function - * @param logger The function that will be called when a log event needs to be displayed - */ - this.setLogger = function setLogger(logger) { - if (logger!='undefined') { _logger = logger; } - if (logger === Log.writeLogger){ - var loggerWrapper = document.createElement("div"); - loggerWrapper.id = "logger"; - loggerWrapper.style.backgroundColor = "white"; - loggerWrapper.style.position = "fixed"; - loggerWrapper.style.top = "100px"; - loggerWrapper.style.left = "0"; - loggerWrapper.style.zIndex = "20"; - loggerWrapper.style.overflow = "scroll"; - loggerWrapper.style.height = "400px"; - - document.body.appendChild(loggerWrapper); - - var clear = document.createElement("a"); - clear.innerHTML = "clear"; - clear.href = "javascript://"; - clear.addEventListener("click", function onClick(){ - loggerList.innerHTML = ""; - }, false); - loggerWrapper.appendChild(clear); - - loggerList = document.createElement("ul"); - loggerWrapper.appendChild(loggerList); - } - } - - /** - * Sets the current threshold log level for this Log instance. Only events that have a priority of this level or greater are logged. - * @param level The new threshold priority level for logging events. This can be one of the static members {@link Log#DEBUG}, {@link Log#INFO}, {@link Log#WARN}, {@link Log#ERROR}, {@link Log#FATAL}, {@link Log#NONE}, or it can be one of the strings ["debug", "info", "warn", "error", "fatal", "none"]. - */ - this.setLevel = function setLevel(level) { - if (level!='undefined' && typeof level =='number') { - _currentLevel = level; - } else if (level!='undefined') { - if (level=='debug') { _currentLevel = Log.DEBUG; } - else if (level=='info') { _currentLevel = Log.INFO; } - else if (level=='error') { _currentLevel = Log.ERROR; } - else if (level=='fatal') { _currentLevel = Log.FATAL; } - else if (level=='warn') { _currentLevel = Log.WARN; } - else { _currentLevel = Log.NONE; } - } - } - - /** - * Gets the current prefix - * @return current prefix - */ - - this.getPrefix = function getPrefix() { return _prefix; } - - /** - * Gets the current event logger function - * @return current logger - */ - - this.getLogger = function getLogger() { return _logger; } - - /** - * Gets the current threshold priority level - * @return current level - */ - - this.getLevel = function getLevel() { return _currentLevel; } - - if (level!='undefined') { this.setLevel(level); } - if (logger!='undefined') { this.setLogger(logger); } - if (prefix!='undefined') { this.setPrefix(prefix); } -} -/** - * Log an event with priority of "debug" - * @param s the log message - */ -Log.prototype.debug = function debug() { if (this.getLevel()<=Log.DEBUG) { this._log("DEBUG",this, arguments); } } -/** - * Log an event with priority of "info" - * @param s the log message - */ -Log.prototype.info = function info() { if (this.getLevel()<=Log.INFO ) { this._log("INFO",this, arguments); } } -/** - * Log an event with priority of "warn" - * @param s the log message - */ -Log.prototype.warn = function warn() { if (this.getLevel()<=Log.WARN ) { this._log("WARN",this, arguments); } } -/** - * Log an event with priority of "error" - * @param s the log message - */ -Log.prototype.error = function error() { if (this.getLevel()<=Log.ERROR) { this._log("ERROR",this, arguments); } } -/** - * Log an event with priority of "fatal" - * @param s the log message - */ -Log.prototype.fatal = function fatal() { if (this.getLevel()<=Log.FATAL) { this._log("FATAL",this, arguments); } } - -/** - * _log is the function that actually calling the configured logger function. - * It is possible that this function could be extended to allow for more - * than one logger. - * - * This method is used by {@link Log#debug}, {@link Log#info}, {@link Log#warn}, {@link Log#error}, and {@link Log#fatal} - * @private - * @param {String} msg The message to display - * @param level The priority level of this log event - * @param {Log} obj The originating {@link Log} object. - */ -Log.prototype._log = function _log(level,obj,msgObj) { - // INFO: 2010-12-26 14:11:42,690 in User::resetDailyVotes() (User.php:850): Reset Daily Votes for 0 Use - var date = new Date(); - var d = ""; - d += ((date.getHours() < 10)? "0" + date.getHours() : date.getHours()); - d += ":" + ((date.getMinutes() < 10)? "0" + date.getMinutes() : date.getMinutes()); - d += ":" + ((date.getSeconds() < 10)? "0" + date.getSeconds() : date.getSeconds()); - d += "." + ((date.getMilliseconds() < 100)? ((date.getMilliseconds() < 10)? "00" + date.getMilliseconds() : "0" + date.getMilliseconds()) : date.getMilliseconds()); - - var msgArr = [], dateStr = '('+d+')'; - if (this._isMobileBrowser){ - var msgStr = dateStr+" "; - for (var i=0, len=msgObj.length; iLevelMessage"); - obj._window.document.close(); - } - } - var tbl = obj._window.document.getElementById("loggerTable"); - var row = tbl.insertRow(-1); - - //var cell_1 = row.insertCell(-1); - var cell_2 = row.insertCell(-1); - var cell_3 = row.insertCell(-1); - - /*var d = new Date(); - var h = d.getHours(); - if (h<10) { h="0"+h; } - var m = d.getMinutes(); - if (m<10) { m="0"+m; } - var s = d.getSeconds(); - if (s<10) { s="0"+s; } - var date = (d.getMonth()+1)+"/"+d.getDate()+"/"+d.getFullYear()+" - "+h+":"+m+":"+s;*/ - - /*cell_1.style.fontSize="8pt"; - cell_1.style.fontWeight="bold"; - cell_1.style.paddingRight="6px";*/ - - cell_2.style.fontSize="8pt"; - - cell_3.style.fontSize="8pt"; - cell_3.style.whiteSpace="nowrap"; - cell_3.style.width="100%"; - - if (tbl.rows.length % 2 == 0) { - //cell_1.style.backgroundColor="#eeeeee"; - cell_2.style.backgroundColor="#eeeeee"; - cell_3.style.backgroundColor="#eeeeee"; - } - - //cell_1.innerHTML=date - cell_2.innerHTML=level; - cell_3.innerHTML=msg; -} - -/** - * This method is a utility function that takes an object and creates a string representation of it's members. - * @param {Object} the Object that you'd like to see - * @return {String} a String representation of the object passed - */ -Log.dumpObject = function dumpObject(obj,indent) { - if (!indent) { indent="";} - if (indent.length>20) { return ; } // don't go too far... - var s="{\n"; - for (var p in obj) { - s+=indent+p+":"; - var type=typeof(obj[p]); - type=type.toLowerCase(); - if (type=='object') { - s+= Log.dumpObject(obj[p],indent+"----"); - } else { - s+= obj[p]; - } - s+="\n"; - } - s+=indent+"}"; - return s; -} -Log.isMobileBrowser=function (uaStr) { - !uaStr && (uaStr = navigator.userAgent); - uaStr = uaStr.toLowerCase(); - var m = /(iphone|ipad|android|symbian|webos|windows phone os)/.exec(uaStr) || []; - return m[1]; -} diff --git a/apps/homescreen/everything.me/js/developer/utils.1.3.js b/apps/homescreen/everything.me/js/developer/utils.1.3.js index 93df29013221..7aebf0d87819 100644 --- a/apps/homescreen/everything.me/js/developer/utils.1.3.js +++ b/apps/homescreen/everything.me/js/developer/utils.1.3.js @@ -89,48 +89,6 @@ function trim(str){ } } -function Logger(){ - function getLoggerLevel(){ - if (/http:\/\/.+\.(loc)\.flyapps\.me\//.test(location.href) || /http:\/\/loc\.flyapps\.me\//.test(location.href) || /http:\/\/.+test\.flyapps\.me\//.test(location.href)){ - return Log.DEBUG; - } - else if (/http:\/\/.+\.(stg|test)\.flyapps\.me\//.test(location.href)){ - return Log.INFO; - } - else if (/http:\/\/.+\.flyapps\.me\//.test(location.href) || /http:\/\/everything\.me\//.test(location.href)){ - return Log.ERROR; - } - return Log.DEBUG; - } - - function getLoggerOutput(){ - var loggerOutput = parseQuery()['doatloggeroutput']; - if (loggerOutput){ - switch (loggerOutput){ - case 'console': - return Log.consoleLogger; - break; - case 'inline': - return Log.writeLogger; - break; - case 'alert': - return Log.alertLogger; - break; - case 'popup': - return Log.popupLogger; - break; - default: - if (window[loggerOutput]){ - return window[loggerOutput] - } - } - } - return Log.consoleLogger; - } - - return new Log(getLoggerLevel(), getLoggerOutput()); -} - function addListener(){ if (typeof arguments[0] === 'string'){ arguments[2] = arguments[1]; diff --git a/apps/homescreen/everything.me/js/everything.me.js b/apps/homescreen/everything.me/js/everything.me.js index b8ae88c71dc3..69bdf319ced3 100644 --- a/apps/homescreen/everything.me/js/everything.me.js +++ b/apps/homescreen/everything.me/js/everything.me.js @@ -93,7 +93,6 @@ var EverythingME = { 'js/developer/utils.1.3.js', 'js/plugins/Scroll.js', 'js/external/iscroll.js', - 'js/developer/log4js2.js', 'js/api/apiv2.js', 'js/api/DoATAPI.js', 'js/helpers/Utils.js', diff --git a/apps/homescreen/everything.me/js/plugins/APIStatsEvents.js b/apps/homescreen/everything.me/js/plugins/APIStatsEvents.js index ed2d184bd5d4..93fdd4f1c744 100644 --- a/apps/homescreen/everything.me/js/plugins/APIStatsEvents.js +++ b/apps/homescreen/everything.me/js/plugins/APIStatsEvents.js @@ -2,7 +2,7 @@ * APIStatsEvents class */ Evme.APIStatsEvents = function Evme_APIStatsEvents(Sandbox){ - var self = this, config, logger, processedItems, tracker = Sandbox.DoATAPI, tempEventArr = [], templatesStr = "", + var self = this, config, processedItems, tracker = Sandbox.DoATAPI, tempEventArr = [], templatesStr = "", templates = { "Results_search": { "userEvent": "pageView", @@ -12,67 +12,9 @@ Evme.APIStatsEvents = function Evme_APIStatsEvents(Sandbox){ "feature": "{feature}", "src": "{source}" }, - - "Searchbar_returnPressed": { - "userEvent": "keyboardReturnClick" - }, - - "suggestions_click": { - "userEvent":"suggestionsClick", - "idx": "{index}", - "visible": "{visible}" - }, - - "history_click": { - "userEvent":"historyClick", - "idx": "{index}" - }, - - "didyoumean_click": { - "userEvent":"spellingClick", - "idx": "{index}" - }, - - "refine_click": { - "userEvent":"disambiguationClick", - "idx": "{index}" - }, - - "Shortcut_click": { - "userEvent": "shortcutsClick", - "idx": "{index}" - }, - "Shortcuts_categoryPageShow": { - "userEvent": "shortcutsCategoryPageShow", - "query": "{query}" - }, - "ShortcutsCustomize_show": { - "userEvent": "shortcutsFavoritesShow" - }, - "ShortcutsCustomize_done": { - "userEvent": "shortcutsFavoritesDoneClick" - }, - - "HomepageTip_show": { - "userEvent": "hptipShow" - }, - "HomepageTip_buttonClick": { - "userEvent": "hptipHide", - "src": "button" - }, - "HomepageTip_backgroundClick": { - "userEvent": "hptipHide", - "src": "background" - }, - - "BackgroundImage_showFullScreen": { - "userEvent":"imageFullScreen" - }, - "AppsMore_show": { "userEvent":"loadMore" }, - "Core_redirectedToApp": { "userEvent": "appClick", "url": "{url}", @@ -84,72 +26,22 @@ Evme.APIStatsEvents = function Evme_APIStatsEvents(Sandbox){ "more": "{more}", "appName": "{appName}", "appId": "{appId}", + "appType": "{appType}", "query": "{query}", "feature": "{source}" }, - - "Core_returnedFromApp": { - "userEvent": "returnedFromApp", - "lengthInSeconds": "{elapsedTime}", - "query": "{query}", - "feature": "{source}", - "appName": "{appName}", - "appId": "{appId}" - }, - - "DoATAPI_sessionInitOnPageLoad": { - "userEvent": "sessionInitOnPageLoad" - }, - - "Tips_show": { - "userEvent": "tipImpression", - "tipId": "{id}" - }, - "Tips_hide": { - "userEvent": "tipHide", - "tipId": "{id}", - "source": "{source}" - }, - "Tips_click": { - "userEvent": "tipClick", - "tipId": "{id}" - }, - - "Prompt_show": { - "userEvent": "promptShow", - "prompt": "{id}", - "text": "{text}" - }, - "Prompt_click": { - "userEvent": "promptClick", - "prompt": "{id}", - "text": "{text}" - }, - "Prompt_dismiss": { - "userEvent": "promptDismiss", - "prompt": "{id}", - "text": "{text}" - }, - "Core_requestInvite": { - "userEvent": "promptRequestInvite", - "text": "{promptText}", - "systemText": "{systemText}", - "email": "{email}", - }, - - "Url_goTo": { - "userEvent": "pageView", - "page": "{page}", - "src": "{source}" + "App_addToHomeScreen": { + "userEvent": "addToHomeScreen", + "appName": "{name}", + "appId": "{id}" } }; this.name = "APIStatsEvents"; - this.init = function init(_config, _logger){ + this.init = function init(_config){ // set config config = _config; - logger = _logger; // add common params for (var k in templates){ @@ -160,9 +52,6 @@ Evme.APIStatsEvents = function Evme_APIStatsEvents(Sandbox){ // stringify templates templatesStr = stringify(templates); - - // log - logger.debug(self.name+".init(",config,")"); }; function stringify(old){ @@ -189,9 +78,6 @@ Evme.APIStatsEvents = function Evme_APIStatsEvents(Sandbox){ items.length && tracker.report({ "data": "["+ items.toString()+"]" }); - - // log - logger.debug(self.name+".dispatch(", items,")"); }; function process(items){ diff --git a/apps/homescreen/everything.me/js/plugins/Analytics.js b/apps/homescreen/everything.me/js/plugins/Analytics.js index 2b57ae996e03..8b40aa8afb57 100644 --- a/apps/homescreen/everything.me/js/plugins/Analytics.js +++ b/apps/homescreen/everything.me/js/plugins/Analytics.js @@ -2,7 +2,7 @@ * Analytics class */ Evme.Analytics = new function Evme_Analytics() { - var self = this, logger, ga, idle, providers = [], immediateProviders = [], queueArr = [], maxQueueCount, getCurrentAppsRowsCols, STORAGE_QUERY = "analyticsLastSearchQuery", + var self = this, ga, idle, providers = [], immediateProviders = [], queueArr = [], maxQueueCount, getCurrentAppsRowsCols, STORAGE_QUERY = "analyticsLastSearchQuery", // Google Analytics load props GAScriptLoadStatus, GAScriptLoadSubscribers = []; @@ -29,12 +29,6 @@ Evme.Analytics = new function Evme_Analytics() { for (i in _options.config){ options[i] = _options.config[i]; } } - // logger object passed from common.js - logger = options && options.logger || console; - - // log - logger.debug("Analytics.init(",options,")"); - // if enabled if (options.enabled){ // we send data according to the settings flag (Submit performance data) @@ -97,20 +91,17 @@ Evme.Analytics = new function Evme_Analytics() { try { self[_class] && self[_class][_event] && self[_class][_event](_data || {}); } catch(ex){ - logger.error(ex); } } function registerProvider(object, params){ var provider = new object(self.Sandbox); - provider.init(params, logger); + provider.init(params); providers.push(provider); if (provider.immediateDispatch){ immediateProviders.push(provider); } - - logger.debug("Analytics.registerProvider(", object.name, params, ")"); } function getProviderByName(name){ @@ -133,8 +124,6 @@ Evme.Analytics = new function Evme_Analytics() { immediateProviders.forEach(function itemIterator(provider){ provider.dispatch([params]); }); - - logger.debug("Analytics.queue(", params, ") (", queueArr.length,")"); } function processItem(params){ @@ -149,14 +138,11 @@ Evme.Analytics = new function Evme_Analytics() { function dispatch(){ // leave if not idle or there are no items to dispatch if (!idle.isIdle || !queueArr.length) { - logger.debug("Analytics.dispatch aborted", idle.isIdle, queueArr.length); return false; } var dispatchedItems = queueArr.splice(0, maxQueueCount); - logger.debug("Analytics.dispatch(", dispatchedItems, ")", queueArr.length); - providers.forEach(function itemIterator(provider){ !provider.immediateDispatch && provider.dispatch(dispatchedItems); }); @@ -190,8 +176,6 @@ Evme.Analytics = new function Evme_Analytics() { }); Evme.Storage.add("analyticsQueue", str); Evme.Storage.add("analyticsQueueTimestamp", new Date().getTime()); - - logger.debug("Analytics.storeQueue", Evme.Storage.get("analyticsQueue")); } // Restore queueArr from localStorage @@ -209,11 +193,6 @@ Evme.Analytics = new function Evme_Analytics() { tempArr.forEach(function itemIterator(item){ queueArr.push(JSON.parse(item)); }); - - logger.debug("Analytics.restoreQueue", queueArr, elapsed); - } - else{ - logger.debug("Analytics.restoreQueue - storage ttl exceeded", elapsed); } Evme.Storage.add("analyticsQueue", null); @@ -409,17 +388,18 @@ Evme.Analytics = new function Evme_Analytics() { var queueData = { "url": data.appUrl, - "rowIndex": rowIndex+1, - "colIndex": colIndex+1, - "totalRows": total[ROWS], - "totalCols": total[COLS], "more": data.isMore ? 1 : 0, "appName": data.name, "appId": data.id, + "appType": data.appType, "appIdName": data.id+":"+data.name, "keyboardVisible": data.keyboardVisible, "query": data.query, - "source": data.source + "source": data.source, + "rowIndex": data.rowIndex, + "colIndex": data.colIndex, + "totalRows": data.totalRows, + "totalCols": data.totalCols }; queue({ @@ -458,13 +438,9 @@ Evme.Analytics = new function Evme_Analytics() { "appName": queueData.appName, "appId": queueData.appId }; - - //storeQueue(); }; this.returnedFromApp = function returnedFromApp() { - // onunload restore queueArr from localStorage - //restoreQueue(); if (redirectData){ // end timer @@ -738,6 +714,16 @@ Evme.Analytics = new function Evme_Analytics() { }); }; }; + + this.App = new function App() { + this.addToHomeScreen = function addToHomeScreen(data) { + queue({ + "class": "App", + "event": "addToHomeScreen", + "data": data + }); + }; + }; this.AppsMore = new function AppsMore() { this.show = function show(data) { diff --git a/apps/homescreen/everything.me/modules/Apps/Apps.js b/apps/homescreen/everything.me/modules/Apps/Apps.js index 529ee45eb10f..f5d9db484a83 100644 --- a/apps/homescreen/everything.me/modules/Apps/Apps.js +++ b/apps/homescreen/everything.me/modules/Apps/Apps.js @@ -159,7 +159,7 @@ Evme.Apps = new function Evme_Apps() { }; this.addInstalledSeparator = function addInstalledSeparator() { - elList.appendChild(Evme.$create('li', {'class': "installed-separator"})); + elList.appendChild(Evme.$create('li', {'class': 'installed-separator'})); }; this.disableScroll = function disableScroll() { @@ -602,6 +602,8 @@ Evme.App = function Evme_App(__cfg, __index, __isMore, parent) { this.init = function init(_cfg) { cfg = normalize(_cfg); + + // generate id if there was none if (!cfg.id) { @@ -631,9 +633,7 @@ Evme.App = function Evme_App(__cfg, __index, __isMore, parent) { el = Evme.$create('li', {'class': "new", 'id': "app_" + cfg.id}); self.update(); - if (cfg.installed) { - el.classList.add("installed"); - } + el.classList.add(cfg.installed ? 'installed' : 'cloud'); if ("ontouchstart" in window) { el.addEventListener("touchstart", touchstart); @@ -731,6 +731,40 @@ Evme.App = function Evme_App(__cfg, __index, __isMore, parent) { return cfg; }; + this.getPositionOnGrid = function getPositionOnGrid() { + var pos = { + 'row': -1, + 'col': -1, + 'rows': -1, + 'cols': -1 + }, + elParent = el.parentNode; + + if (elParent) { + var bounds = el.getBoundingClientRect(), + parentBounds = elParent.getBoundingClientRect(), + seperatorEl = elParent.querySelector('.installed-separator'), + // if there's a seprator, it shall be the top bound for cloud apps + topBound= (!cfg.installed && seperatorEl && seperatorEl.getBoundingClientRect() || parentBounds).top, + width = bounds.width, + height = bounds.height, + left = bounds.left - parentBounds.left, + top = bounds.top - topBound, + + elParentWidth = elParent.offsetWidth, + // number of apps of the same type + numberOfApps = elParent.querySelectorAll('.'+(cfg.installed ? 'installed' : 'cloud')).length; + + + pos.col = Math.floor(left / width); + pos.row = Math.floor(top / height); + pos.cols = Math.round(elParentWidth / width) + pos.rows = totalRows = Math.ceil(numberOfApps / pos.cols); + } + + return pos; + }; + this.setIcon = function setIcon(icon, bRedraw) { cfg.icon = icon; diff --git a/apps/settings/js/icc.js b/apps/settings/js/icc.js index ce95a8e0b0f1..c99760ee4790 100644 --- a/apps/settings/js/icc.js +++ b/apps/settings/js/icc.js @@ -604,9 +604,6 @@ var p = document.createElement('p'); p.id = 'stk-item-title'; p.textContent = options.text; - if (options.minLength && options.maxLength) { - p.textContent += ' [' + options.minLength + '-' + options.maxLength + ']'; - } li.appendChild(p); var input = document.createElement('input'); @@ -736,6 +733,9 @@ var tonePlayer = new Audio(); var selectedPhoneSound; + if (typeof options.tone == "string") { + options.tone = options.tone.charCodeAt(0); + } switch (options.tone) { case icc.STK_TONE_TYPE_DIAL_TONE: selectedPhoneSound = 'resources/dtmf_tones/350Hz+440Hz_200ms.ogg'; @@ -772,10 +772,12 @@ tonePlayer.loop = true; tonePlayer.play(); - timeout = calculateDurationInMS(options.duration); - setTimeout(function() { - tonePlayer.pause(); - },timeout); + if (options.duration) { + timeout = calculateDurationInMS(options.duration); + setTimeout(function() { + tonePlayer.pause(); + }, timeout); + } if (options.isVibrate == true) { window.navigator.vibrate([200]); diff --git a/apps/system/js/attention_screen.js b/apps/system/js/attention_screen.js index feabab716c0b..3444c3f11fb2 100644 --- a/apps/system/js/attention_screen.js +++ b/apps/system/js/attention_screen.js @@ -217,16 +217,16 @@ var AttentionScreen = { if (!this.isFullyVisible()) return; + // entering "active-statusbar" mode, + // with a transform: translateY() slide up transition. + this.mainScreen.classList.add('active-statusbar'); + // The only way to hide attention screen is the home/holdhome event. // So we don't fire any origin information here. // The expected behavior is restore homescreen visibility to 'true' // in the Window Manager. this.dispatchEvent('status-active'); - // entering "active-statusbar" mode, - // with a transform: translateY() slide up transition. - this.mainScreen.classList.add('active-statusbar'); - var attentionScreen = this.attentionScreen; attentionScreen.addEventListener('transitionend', function trWait() { attentionScreen.removeEventListener('transitionend', trWait); diff --git a/apps/system/js/cards_view.js b/apps/system/js/cards_view.js index 1cbcce43133f..bfba16b6dd62 100644 --- a/apps/system/js/cards_view.js +++ b/apps/system/js/cards_view.js @@ -241,7 +241,7 @@ var CardsView = (function() { header.innerHTML += ''; card.appendChild(header); card.classList.add('trustedui'); - } else { + } else if (attentionScreenApps.indexOf(origin) == -1) { var closeButton = document.createElement('div'); closeButton.classList.add('close-card'); card.appendChild(closeButton); diff --git a/apps/system/js/icc_cache.js b/apps/system/js/icc_cache.js index 9ccf6827d35f..b7da847b6b88 100644 --- a/apps/system/js/icc_cache.js +++ b/apps/system/js/icc_cache.js @@ -27,43 +27,51 @@ } var icc = window.navigator.mozMobileConnection.icc; - window.navigator.mozSetMessageHandler('icc-stkcommand', - function handleSTKCommand(command) { - debug('STK Proactive Command:', command); - if (command.typeOfCommand == icc.STK_CMD_SET_UP_MENU) { - debug('STK_CMD_SET_UP_MENU:', command.options); - var reqApplications = window.navigator.mozSettings.createLock().set({ - 'icc.applications': JSON.stringify(command.options) - }); - reqApplications.onsuccess = function icc_getApplications() { - debug('Cached'); - icc.sendStkResponse(command, { - resultCode: icc.STK_RESULT_OK + // Remove previous menu + var resetApplications = window.navigator.mozSettings.createLock().set({ + 'icc.applications': {} + }); + resetApplications.onsuccess = function icc_resetApplications() { + debug('STK Cache Reseted'); + // Register to receive STK commands + window.navigator.mozSetMessageHandler('icc-stkcommand', + function handleSTKCommand(command) { + debug('STK Proactive Command:', command); + if (command.typeOfCommand == icc.STK_CMD_SET_UP_MENU) { + debug('STK_CMD_SET_UP_MENU:', command.options); + var reqApplications = window.navigator.mozSettings.createLock().set({ + 'icc.applications': JSON.stringify(command.options) }); - } - } else { - // Unsolicited command? -> Open settings - debug('CMD: ', command); - var application = document.location.protocol + '//' + - document.location.host.replace('system', 'settings'); - debug('application: ', application); - if (WindowManager.getRunningApps()[application]) { - return; // If settings is opened, we don't manage it - } - navigator.mozApps.mgmt.getAll().onsuccess = function gotApps(evt) { - var apps = evt.target.result; - apps.forEach(function appIterator(app) { - if (app.origin == application) { - var reqIccData = window.navigator.mozSettings.createLock().set({ - 'icc.data': JSON.stringify(command) - }); - reqIccData.onsuccess = function icc_getIccData() { - debug('Launching ', app.origin); - app.launch(); + reqApplications.onsuccess = function icc_getApplications() { + debug('Cached'); + icc.sendStkResponse(command, { + resultCode: icc.STK_RESULT_OK + }); + } + } else { + // Unsolicited command? -> Open settings + debug('CMD: ', command); + var application = document.location.protocol + '//' + + document.location.host.replace('system', 'settings'); + debug('application: ', application); + if (WindowManager.getRunningApps()[application]) { + return; // If settings is opened, we don't manage it + } + navigator.mozApps.mgmt.getAll().onsuccess = function gotApps(evt) { + var apps = evt.target.result; + apps.forEach(function appIterator(app) { + if (app.origin == application) { + var reqIccData = window.navigator.mozSettings.createLock().set({ + 'icc.data': JSON.stringify(command) + }); + reqIccData.onsuccess = function icc_getIccData() { + debug('Launching ', app.origin); + app.launch(); + } } - } - }, this); + }, this); + } } - } - }); + }); + } })(); diff --git a/apps/system/js/identity.js b/apps/system/js/identity.js index f23eafaeb39a..3538307c611a 100644 --- a/apps/system/js/identity.js +++ b/apps/system/js/identity.js @@ -13,25 +13,27 @@ var Identity = (function() { var iframe; return { - chromeEventId: null, + trustedUILayerID: null, init: function() { window.addEventListener('mozChromeEvent', this); }, handleEvent: function onMozChromeEvent(e) { - // We save the mozChromeEvent identifiers to send replies back from - // content with this exact value. - this.chromeEventId = e.detail.id; - if (!this.chromeEventId) - return; - + var chromeEventId = e.detail.id; switch (e.detail.type) { // Chrome asks Gaia to show the identity dialog. case 'open-id-dialog': + // When opening the dialog, we record the chrome event id, which + // we will need to send back to the TrustedUIManager when asking + // to close. + this.trustedUILayerID = chromeEventId; + if (!this.trustedUILayerID) + return; + if (!e.detail.showUI && iframe) { this._dispatchEvent({ - id: this.chromeEventId, + id: chromeEventId, frame: iframe }); return; @@ -46,7 +48,7 @@ var Identity = (function() { // After creating the new frame containing the identity flow, we // send it back to chrome so the identity callbacks can be injected. this._dispatchEvent({ - id: this.chromeEventId, + id: chromeEventId, frame: evt.target }); }.bind(this)); @@ -54,7 +56,7 @@ var Identity = (function() { if (e.detail.showUI) { // The identity flow is shown within the trusted UI. - TrustedUIManager.open(navigator.mozL10n.get('persona-signin'), frame, this.chromeEventId); + TrustedUIManager.open(navigator.mozL10n.get('persona-signin'), frame, this.trustedUILayerID); } else { var container = document.getElementById('screen'); container.appendChild(frame); @@ -65,9 +67,9 @@ var Identity = (function() { case 'received-id-assertion': if (e.detail.showUI) { - TrustedUIManager.close(null); + TrustedUIManager.close(this.trustedUILayerID, null); } - this._dispatchEvent({ id: this.chromeEventId }); + this._dispatchEvent({ id: chromeEventId }); break; } }, diff --git a/apps/system/js/lockscreen.js b/apps/system/js/lockscreen.js index 2bb6d3f6f84b..82f83aa09b20 100644 --- a/apps/system/js/lockscreen.js +++ b/apps/system/js/lockscreen.js @@ -935,10 +935,6 @@ var LockScreen = { } }; -if (navigator.mozL10n.readyState == 'complete' || - navigator.mozL10n.readyState == 'interactive') { - LockScreen.init(); -} else { - window.addEventListener('localized', LockScreen.init.bind(LockScreen)); -} +LockScreen.init(); +window.addEventListener('localized', LockScreen.init.bind(LockScreen)); diff --git a/apps/system/js/payment.js b/apps/system/js/payment.js index 9b10cabfd81e..f3c1ccb6c99c 100644 --- a/apps/system/js/payment.js +++ b/apps/system/js/payment.js @@ -8,15 +8,21 @@ const kPaymentConfirmationScreen = '../payment.html'; -var Payment = (function Payment() { - var chromeEventId = null; +var Payment = { + chromeEventId: null, + trustedUILayerID: null, - window.addEventListener('mozChromeEvent', function onMozChromeEvent(e) { + init: function init() { + window.addEventListener('mozChromeEvent', this); + }, + + handleEvent: function onMozChromeEvent(e) { // We save the mozChromeEvent identifiers to send replies back from content // with this exact value. - chromeEventId = e.detail.id; - if (!chromeEventId) + this.chromeEventId = e.detail.id; + if (!this.chromeEventId) return; + switch (e.detail.type) { // Chrome asks Gaia to show the payment request confirmation dialog. case 'open-payment-confirmation-dialog': @@ -24,17 +30,15 @@ var Payment = (function Payment() { if (!requests) return; - var returnSelection = function returnSelection(selection) { + var returnSelection = (function returnSelection(selection) { if (!selection) return; - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('mozContentEvent', true, true, { - id: chromeEventId, + this._dispatchEvent({ + id: this.chromeEventId, userSelection: selection }); - window.dispatchEvent(event); - }; + }).bind(this); // If there is only one request, we skip the confirmation dialog and // send the request type back to the chrome as a user selection, so @@ -57,7 +61,7 @@ var Payment = (function Payment() { // TODO: Temp layout until issue #2692 is solved. var frameDocument = frame.contentWindow.document; var requestsList = frameDocument.getElementById('requests') - .getElementsByTagName('ul')[0]; + .getElementsByTagName('ul')[0]; for (var i in requests) { var requestElement = frameDocument.createElement('li'); var button = frameDocument.createElement('button'); @@ -78,9 +82,7 @@ var Payment = (function Payment() { } }); - // The payment request confirmation screen is shown within the trusted - // UI. - TrustedUIManager.open('payment-confirmation', frame, chromeEventId); + this._openTrustedUI(frame); break; // Chrome asks Gaia to show the payment flow according to the @@ -88,38 +90,58 @@ var Payment = (function Payment() { case 'open-payment-flow-dialog': if (!e.detail.uri) return; + // TODO: For now, known payment providers (BlueVia and Mozilla Market) // only accepts the JWT by GET, so we just add it to the URI. e.detail.uri += e.detail.jwt; + this.trustedUILayerID = this.chromeEventId; + var frame = document.createElement('iframe'); frame.setAttribute('mozbrowser', 'true'); frame.classList.add('screen'); frame.src = e.detail.uri; - frame.addEventListener('mozbrowserloadstart', function loadStart(evt) { + frame.addEventListener('mozbrowserloadstart', (function loadStart(evt) { // After creating the new frame containing the payment provider buy // flow, we send it back to chrome so the payment callbacks can be // injected. - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('mozContentEvent', true, true, { - id: chromeEventId, + this._dispatchEvent({ + id: this.chromeEventId, frame: evt.target }); - window.dispatchEvent(event); - }); + }).bind(this)); - // The payment flow is shown within the trusted UI. - TrustedUIManager.open('PaymentFlow', frame, chromeEventId); + // The payment flow is shown within the trusted UI + this._openTrustedUI(frame); break; case 'close-payment-flow-dialog': - TrustedUIManager.close(function dialogClosed() { - var event = document.createEvent('customEvent'); - event.initCustomEvent('mozContentEvent', true, true, - { id: chromeEventId }); - window.dispatchEvent(event); - }); + TrustedUIManager.close(this.trustedUILayerID, (function dialogClosed() { + this._dispatchEvent({ id: this.chromeEventId }); + }).bind(this)); break; } - }); -})(); + }, + + _openTrustedUI: function _openTrustedUI(frame) { + // The payment flow is shown within the trusted UI with the name of + // the mozPay caller application as title. + var title = WindowManager.getCurrentDisplayedApp().name; + title = title ? title : navigator.mozL10n.get('payment-flow'); + TrustedUIManager.open(title, frame, this.chromeEventId); + }, + + _dispatchEvent: function _dispatchEvent(obj) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('mozContentEvent', true, true, obj); + window.dispatchEvent(event); + } +}; + +// Make sure L10n is ready before init +if (navigator.mozL10n.readyState == 'complete' || + navigator.mozL10n.readyState == 'interactive') { + Payment.init(); +} else { + window.addEventListener('localized', Payment.init.bind(Payment)); +} diff --git a/apps/system/js/popup_manager.js b/apps/system/js/popup_manager.js index bd9aa8893104..583c9c853ae5 100644 --- a/apps/system/js/popup_manager.js +++ b/apps/system/js/popup_manager.js @@ -224,7 +224,8 @@ var PopupManager = { return; } - var contentOrigin = this._currentPopup[this._currentOrigin].dataset.url; + var contentOrigin = + this.getTitleFromUrl(this._currentPopup[this._currentOrigin].dataset.url); var _ = navigator.mozL10n.get; if (AirplaneMode.enabled) { diff --git a/apps/system/js/trusted_ui.js b/apps/system/js/trusted_ui.js index 199d5f18bf61..43bea21ed1af 100644 --- a/apps/system/js/trusted_ui.js +++ b/apps/system/js/trusted_ui.js @@ -93,9 +93,7 @@ var TrustedUIManager = { } }, - close: function trui_close(callback) { - // XXX this assumes that close() will only be called from the - // topmost element in the frame stack. woooog. + close: function trui_close(chromeEventId, callback) { var stackSize = this.currentStack.length; this._restoreOrientation(); @@ -114,11 +112,11 @@ var TrustedUIManager = { WindowManager.restoreCurrentApp(); container.addEventListener('transitionend', function wait(event) { this.removeEventListener('transitionend', wait); - self._closeTopDialog(); + self._closeDialog(chromeEventId); }); } else { WindowManager.restoreCurrentApp(this._lastDisplayedApp); - this._closeTopDialog(); + this._closeDialog(chromeEventId); } // The css transition caused by the removal of the trustedui @@ -128,9 +126,7 @@ var TrustedUIManager = { window.focus(); } else { - // there are two or more dialogs, so remove the top one - // (which reveals the one beneath it) - this._closeTopDialog(); + this._closeDialog(chromeEventId); } }, @@ -181,8 +177,9 @@ var TrustedUIManager = { this.popupContainer.classList.remove('closing'); this.show(); - // ensure the frame is visible + // ensure the frame is visible and the dialog title is correct. dialog.frame.classList.add('selected'); + this.dialogTitle.textContent = dialog.name; }, _makeDialogHidden: function trui_makeDialogHidden(dialog) { @@ -197,14 +194,24 @@ var TrustedUIManager = { WindowManager.setOrientationForApp(app); }, - _closeTopDialog: function trui_closeTopDialog() { + /** + * close the dialog identified by the chromeEventId + */ + _closeDialog: function trui_closeDialog(chromeEventId) { if (this.currentStack.length === 0) return; - var dialog = this.currentStack.pop(); - this.container.removeChild(dialog.frame); + var found = false; + for (var i = 0; i < this.currentStack.length; i++) { + if (this.currentStack[i].chromeEventId === chromeEventId) { + var dialog = this.currentStack.splice(i, 1)[0]; + this.container.removeChild(dialog.frame); + found = true; + break; + } + } - if (this.currentStack.length) { + if (found && this.currentStack.length) { this._makeDialogVisible(this._getTopDialog()); } }, @@ -247,7 +254,7 @@ var TrustedUIManager = { this._dispatchCloseEvent(dialog.chromeEventId); // Now close and fire the cancel callback, if it exists - this.close(dialog.onCancelCB); + this.close(dialog.chromeEventId, dialog.onCancelCB); } this.hide(); this.popupContainer.classList.remove('closing'); diff --git a/apps/system/js/window_manager.js b/apps/system/js/window_manager.js index 5ab1382de13e..aef70a1ab776 100644 --- a/apps/system/js/window_manager.js +++ b/apps/system/js/window_manager.js @@ -1,8 +1,6 @@ /* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -'use strict'; - // // This file calls getElementById without waiting for an onload event, so it // must have a defer attribute or be included at the end of the . @@ -49,6 +47,12 @@ // var WindowManager = (function() { + 'use strict'; + + function debug(str) { + dump('WindowManager: ' + str + '\n'); + } + // Holds the origin of the home screen, which should be the first // app we launch through web activity during boot var homescreen = null; @@ -811,14 +815,12 @@ var WindowManager = (function() { var app = Applications.getByManifestURL(homescreenManifestURL); appendFrame(null, homescreen, homescreenURL, app.manifest.name, app.manifest, app.manifestURL); + setAppSize(homescreen); } else if (reset) { runningApps[homescreen].iframe.src = homescreenURL; + setAppSize(homescreen); } - // need to setAppSize or for the first time, or from FTU to homescreen - // the dock position would be incorrect. - setAppSize(homescreen); - return runningApps[homescreen].frame; } @@ -1832,6 +1834,7 @@ var WindowManager = (function() { if (document.mozFullScreen) { document.mozCancelFullScreen(); } + if (displayedApp !== homescreen || inTransition) { if (displayedApp != ftuURL) { setDisplayedApp(homescreen); diff --git a/apps/system/locales/system.en-US.properties b/apps/system/locales/system.en-US.properties index 4ce3435e5f1e..568143b2ff8e 100644 --- a/apps/system/locales/system.en-US.properties +++ b/apps/system/locales/system.en-US.properties @@ -278,6 +278,9 @@ activity-dial=Dial from: # Persona dialog and Identity persona-signin=Sign In +# Payment dialog +payment-flow=Purchase + # Remote Debugger Connection Dialog remoteDebuggerMessage=An incoming request to permit remote debugging connection was detected. Allow connection? diff --git a/apps/system/test/unit/identity_test.js b/apps/system/test/unit/identity_test.js index ea8a1b57824a..150944c4e782 100644 --- a/apps/system/test/unit/identity_test.js +++ b/apps/system/test/unit/identity_test.js @@ -3,6 +3,7 @@ requireApp('system/js/identity.js'); requireApp('system/test/unit/mock_chrome_event.js'); requireApp('system/test/unit/mock_trusted_ui_manager.js'); +requireApp('system/test/unit/mock_l10n.js'); // ensure its defined as a global so mocha will not complain about us // leaking new global variables during the test @@ -12,6 +13,7 @@ if (!window.TrustedUIManager) { suite('identity', function() { var subject; + var realL10n; var realTrustedUIManager; var realDispatchEvent; @@ -22,6 +24,9 @@ suite('identity', function() { realTrustedUIManager = window.TrustedUIManager; window.TrustedUIManager = MockTrustedUIManager; + realL10n = navigator.mozL10n; + navigator.mozL10n = MockL10n; + realDispatchEvent = subject._dispatchEvent; subject._dispatchEvent = function (obj) { lastDispatchedEvent = obj; @@ -31,6 +36,8 @@ suite('identity', function() { suiteTeardown(function() { window.TrustedUIManager = realTrustedUIManager; subject._dispatchEvent = realDispatchEvent; + + navigator.mozL10n = realL10n; }); setup(function() {}); @@ -51,7 +58,7 @@ suite('identity', function() { test('popup parameters', function() { assert.equal(MockTrustedUIManager.mOpened, true); - assert.equal(MockTrustedUIManager.mName, 'IdentityFlow'); + assert.equal(MockTrustedUIManager.mName, 'persona-signin'); assert.equal(MockTrustedUIManager.mChromeEventId, 'test-open-event-id'); }); diff --git a/apps/video/js/video.js b/apps/video/js/video.js index 2e58a5203bc9..f71c9ba4d1b6 100644 --- a/apps/video/js/video.js +++ b/apps/video/js/video.js @@ -460,6 +460,8 @@ function setVideoUrl(player, video, callback) { function showPlayer(data, autoPlay) { currentVideo = data; + dom.thumbnails.classList.add('hidden'); + // switch to the video player view updateDialog(); dom.player.preload = 'metadata'; @@ -528,6 +530,7 @@ function hidePlayer() { // switch to the video gallery view dom.videoFrame.classList.add('hidden'); dom.videoBar.classList.remove('paused'); + dom.thumbnails.classList.remove('hidden'); playerShowing = false; updateDialog(); } diff --git a/build/applications-data.js b/build/applications-data.js index a12f1f89db5f..3b05c143c266 100644 --- a/build/applications-data.js +++ b/build/applications-data.js @@ -163,7 +163,8 @@ content = { senders: ['1515', '7000'], confirmation_regexp: 'Voce recarregou R\\$\\s*([0-9]+)(?:[,\\.]([0-9]+))?', incorrect_code_regexp: '(Favor enviar|envie novamente|Verifique) o codigo de recarga' - } + }, + default_low_limit_threshold: 3 }; writeContent(init, JSON.stringify(content)); diff --git a/build/settings.py b/build/settings.py index df5022f72173..a9d480aece45 100644 --- a/build/settings.py +++ b/build/settings.py @@ -75,7 +75,7 @@ "powersave.enabled": False, "powersave.threshold": 0, "privacy.donottrackheader.enabled": False, - "ril.callwaiting.enabled": True, + "ril.callwaiting.enabled": None, "ril.data.enabled": False, "ril.data.apn": "", "ril.data.carrier": "", diff --git a/shared/js/l10n.js b/shared/js/l10n.js index 960980e63f42..6d03c7325730 100644 --- a/shared/js/l10n.js +++ b/shared/js/l10n.js @@ -939,7 +939,7 @@ // load the default locale and translate the document if required if (document.documentElement.lang === navigator.language) { - loadLocale(navigator.language, fireL10nReadyEvent); + loadLocale(navigator.language); } else { loadLocale(navigator.language, translateFragment); }