Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
641
gaia/apps/communications/contacts/js/views/details.js
Executable file
641
gaia/apps/communications/contacts/js/views/details.js
Executable file
|
|
@ -0,0 +1,641 @@
|
|||
'use strict';
|
||||
|
||||
/* jshint nonew: false */
|
||||
|
||||
/* global ActivityHandler */
|
||||
/* global COMMS_APP_ORIGIN */
|
||||
/* global Contacts */
|
||||
/* global ContactsButtons */
|
||||
/* global ContactPhotoHelper */
|
||||
/* globals ContactToVcardBlob */
|
||||
/* global fb */
|
||||
/* global NFC */
|
||||
/* global ICEData */
|
||||
/* global LazyLoader */
|
||||
/* global MozActivity */
|
||||
/* global Normalizer */
|
||||
/* global SCALE_RATIO */
|
||||
/* global TAG_OPTIONS */
|
||||
/* global utils */
|
||||
/* global VcardFilename */
|
||||
/* global MatchService */
|
||||
/* global WebrtcClient */
|
||||
/* global MainNavigation */
|
||||
/* global ContactsService */
|
||||
|
||||
var contacts = window.contacts || {};
|
||||
|
||||
contacts.Details = (function() {
|
||||
var photoPos = 7;
|
||||
var initMargin = 8;
|
||||
var DEFAULT_TEL_TYPE = 'other';
|
||||
// If it is a favourite on/off change, I cancel the render
|
||||
var isAFavoriteChange = false;
|
||||
var contactData,
|
||||
contactDetails,
|
||||
listContainer,
|
||||
detailsName,
|
||||
detailsNameText,
|
||||
orgTitle,
|
||||
datesTemplate,
|
||||
addressesTemplate,
|
||||
socialTemplate,
|
||||
duplicateTemplate,
|
||||
notesTemplate,
|
||||
isFbContact,
|
||||
isFbLinked,
|
||||
editContactButton,
|
||||
cover,
|
||||
favoriteMessage,
|
||||
detailsInner,
|
||||
dom,
|
||||
currentSocial,
|
||||
header,
|
||||
_;
|
||||
|
||||
var init = function cd_init(currentDom) {
|
||||
_ = navigator.mozL10n.get;
|
||||
dom = currentDom || document;
|
||||
header = dom.querySelector('#details-view-header');
|
||||
contactDetails = dom.querySelector('#contact-detail');
|
||||
listContainer = dom.querySelector('#details-list');
|
||||
detailsName = dom.querySelector('#contact-name-title');
|
||||
detailsNameText = dom.querySelector('#contact-name-title bdi');
|
||||
orgTitle = dom.querySelector('#org-title');
|
||||
datesTemplate = dom.querySelector('#dates-template-\\#i\\#');
|
||||
addressesTemplate = dom.querySelector('#address-details-template-\\#i\\#');
|
||||
socialTemplate = dom.querySelector('#social-template-\\#i\\#');
|
||||
duplicateTemplate = dom.querySelector('#duplicate-contacts-template');
|
||||
editContactButton = dom.querySelector('#edit-contact-button');
|
||||
cover = dom.querySelector('#cover-img');
|
||||
detailsInner = dom.querySelector('#contact-detail-inner');
|
||||
favoriteMessage = dom.querySelector('#toggle-favorite');
|
||||
notesTemplate = dom.querySelector('#note-details-template-\\#i\\#');
|
||||
|
||||
initPullEffect(cover);
|
||||
|
||||
// to avoid race conditions with NFC, we load it before handleDetails
|
||||
LazyLoader.load('/contacts/js/nfc.js', () => {
|
||||
favoriteMessage.addEventListener('click', toggleFavorite);
|
||||
editContactButton.addEventListener('click', showEditContact);
|
||||
header.addEventListener('action', handleDetailsBack);
|
||||
});
|
||||
|
||||
ContactsButtons.init(listContainer, contactDetails, ActivityHandler);
|
||||
};
|
||||
|
||||
var getWebrtcClientResources = function getWebrtcClientResources(cb) {
|
||||
if (typeof cb !== 'function') {
|
||||
return;
|
||||
}
|
||||
LazyLoader.load(
|
||||
[
|
||||
'/contacts/style/webrtc-client/webrtc_client.css',
|
||||
'/contacts/js/webrtc-client/webrtc_client.js'
|
||||
],
|
||||
cb
|
||||
);
|
||||
};
|
||||
|
||||
var handleDetailsBack = function handleDetailsBack() {
|
||||
// disable NFC listeners when going out of Details view
|
||||
stopNFC();
|
||||
|
||||
if (WebrtcClient) {
|
||||
getWebrtcClientResources(WebrtcClient.stop);
|
||||
}
|
||||
|
||||
if (ActivityHandler.currentActivityIsNot(['import'])) {
|
||||
ActivityHandler.postCancel();
|
||||
MainNavigation.home();
|
||||
}
|
||||
else if (window.ICEView && window.ICEView.iceListDisplayed) {
|
||||
ICEData.getActiveIceContacts().then(function(list) {
|
||||
if (!Array.isArray(list) || list.length === 0) {
|
||||
MainNavigation.home();
|
||||
}
|
||||
else {
|
||||
doHandleDetailsBack();
|
||||
}
|
||||
}, doHandleDetailsBack);
|
||||
}
|
||||
else {
|
||||
doHandleDetailsBack();
|
||||
}
|
||||
};
|
||||
|
||||
var doHandleDetailsBack = function() {
|
||||
var hashParams = window.location.hash.split('?');
|
||||
var params = hashParams.length > 1 ?
|
||||
utils.extractParams(hashParams[1]) : -1;
|
||||
|
||||
// post message to parent page included Contacts app.
|
||||
if (params.back_to_previous_tab === '1') {
|
||||
var message = { 'type': 'contactsiframe', 'message': 'back' };
|
||||
window.parent.postMessage(message, COMMS_APP_ORIGIN);
|
||||
} else {
|
||||
MainNavigation.back(resetPhoto);
|
||||
}
|
||||
};
|
||||
|
||||
var showEditContact = function showEditContact() {
|
||||
// Disable NFC listeners when editing a contact
|
||||
stopNFC();
|
||||
Contacts.showForm(true, contactData);
|
||||
};
|
||||
|
||||
var setContact = function cd_setContact(currentContact) {
|
||||
contactData = currentContact;
|
||||
startNFC(currentContact);
|
||||
};
|
||||
|
||||
// Needed for now because of external call from contacts.js
|
||||
var startNFC = function(contact) {
|
||||
LazyLoader.load('/contacts/js/nfc.js', () => {
|
||||
NFC.startListening(contact);
|
||||
});
|
||||
};
|
||||
|
||||
var stopNFC = function() {
|
||||
LazyLoader.load('/contacts/js/nfc.js', () => {
|
||||
NFC.stopListening();
|
||||
});
|
||||
};
|
||||
|
||||
var initPullEffect = function cd_initPullEffect(cover) {
|
||||
var maxPosition = Math.round(150 * SCALE_RATIO);
|
||||
var startPosition = 0;
|
||||
|
||||
function onTouchStart(e) {
|
||||
if (contactDetails.classList.contains('no-photo')) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
startPosition = e.changedTouches[0].clientY;
|
||||
|
||||
contactDetails.classList.add('up');
|
||||
cover.classList.add('up');
|
||||
|
||||
window.addEventListener('touchmove', onTouchMove, true);
|
||||
window.addEventListener('touchend', onTouchEnd, true);
|
||||
}
|
||||
|
||||
function onTouchEnd(e) {
|
||||
e.preventDefault();
|
||||
|
||||
contactDetails.style.transform = null;
|
||||
contactDetails.classList.add('up');
|
||||
|
||||
cover.style.transform = null;
|
||||
cover.classList.add('up');
|
||||
|
||||
window.removeEventListener('touchmove', onTouchMove, true);
|
||||
window.removeEventListener('touchend', onTouchEnd, true);
|
||||
}
|
||||
|
||||
function onTouchMove(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var deltaY = e.changedTouches[0].clientY - startPosition;
|
||||
deltaY = Math.min(maxPosition, Math.max(0, deltaY));
|
||||
|
||||
var calc = 'calc(' + initMargin + 'rem + ' + deltaY + 'px)';
|
||||
contactDetails.style.transform = 'translateY(' + calc + ')';
|
||||
contactDetails.classList.remove('up');
|
||||
|
||||
// Divide by 40 (4 times slower and in rems)
|
||||
var coverPosition = (-photoPos + (deltaY / 40)) + 'rem';
|
||||
cover.style.transform = 'translateY(' + coverPosition + ')';
|
||||
cover.classList.remove('up');
|
||||
}
|
||||
|
||||
cover.addEventListener('touchstart', onTouchStart, true);
|
||||
};
|
||||
|
||||
// readOnly tells us if we should allow editing the rendered contact.
|
||||
var render = function cd_render(currentContact, fbContactData, readOnly) {
|
||||
|
||||
if(isAFavoriteChange){
|
||||
isAFavoriteChange = false;
|
||||
return Promise.resolve(isAFavoriteChange);
|
||||
}
|
||||
|
||||
|
||||
contactData = currentContact || contactData;
|
||||
|
||||
startNFC(contactData);
|
||||
|
||||
isFbContact = fb.isFbContact(contactData);
|
||||
isFbLinked = fb.isFbLinked(contactData);
|
||||
|
||||
// Initially enabled and only disabled if necessary
|
||||
editContactButton.removeAttribute('disabled');
|
||||
editContactButton.classList.remove('hide');
|
||||
header.setAttribute('action', 'back');
|
||||
socialTemplate.classList.remove('hide');
|
||||
|
||||
if (readOnly) {
|
||||
editContactButton.classList.add('hide');
|
||||
header.setAttribute('action', 'close');
|
||||
socialTemplate.classList.add('hide');
|
||||
}
|
||||
|
||||
if (!fbContactData && isFbContact) {
|
||||
var fbContact = new fb.Contact(contactData);
|
||||
var req = fbContact.getData();
|
||||
|
||||
req.onsuccess = function do_reload() {
|
||||
doReloadContactDetails(req.result);
|
||||
};
|
||||
|
||||
req.onerror = function() {
|
||||
window.console.error('FB: Error while loading FB contact data');
|
||||
doReloadContactDetails(contactData);
|
||||
};
|
||||
} else {
|
||||
doReloadContactDetails(fbContactData || contactData);
|
||||
}
|
||||
};
|
||||
|
||||
// Fills the contact data to display if no givenName and familyName
|
||||
var getDisplayName = function getDisplayName(contact) {
|
||||
var name = _('noName');
|
||||
|
||||
if (hasName(contact)) {
|
||||
name = contact.name[0];
|
||||
} else if (hasContent(contact.tel)) {
|
||||
name = contact.tel[0].value;
|
||||
} else if (hasContent(contact.email)) {
|
||||
name = contact.email[0].value;
|
||||
}
|
||||
return name;
|
||||
};
|
||||
|
||||
function hasContent(field) {
|
||||
return (Array.isArray(field) &&
|
||||
field.length > 0 &&
|
||||
field[0].value &&
|
||||
field[0].value.trim());
|
||||
}
|
||||
|
||||
function hasName(contact) {
|
||||
return (Array.isArray(contact.name) &&
|
||||
contact.name[0] &&
|
||||
contact.name[0].trim());
|
||||
}
|
||||
|
||||
//
|
||||
// Method that generates HTML markup for the contact
|
||||
//
|
||||
var doReloadContactDetails = function doReloadContactDetails(contact) {
|
||||
detailsNameText.textContent = getDisplayName(contact);
|
||||
contactDetails.classList.remove('no-photo');
|
||||
contactDetails.classList.remove('fb-contact');
|
||||
contactDetails.classList.remove('up');
|
||||
utils.dom.removeChildNodes(listContainer);
|
||||
|
||||
renderFavorite(contact);
|
||||
renderOrg(contact);
|
||||
|
||||
ContactsButtons.renderPhones(contact);
|
||||
ContactsButtons.renderEmails(contact);
|
||||
|
||||
renderWebrtcClient(contactData);// Don't share the FB info
|
||||
|
||||
renderAddresses(contact);
|
||||
|
||||
renderDates(contact);
|
||||
|
||||
renderNotes(contact);
|
||||
|
||||
renderShareButton(contact);
|
||||
|
||||
if (!fb.isFbContact(contact) || fb.isFbLinked(contact)) {
|
||||
renderDuplicate(contact);
|
||||
}
|
||||
|
||||
renderPhoto(contact);
|
||||
};
|
||||
|
||||
var renderFavorite = function cd_renderFavorite(contact) {
|
||||
var favorite = isFavorite(contact);
|
||||
toggleFavoriteMessage(favorite);
|
||||
|
||||
header.classList.toggle('favorite', !!favorite);
|
||||
};
|
||||
|
||||
var isFavorite = function isFavorite(contact) {
|
||||
return contact != null && contact.category != null &&
|
||||
contact.category.indexOf('favorite') != -1;
|
||||
};
|
||||
|
||||
var toggleFavorite = function toggleFavorite() {
|
||||
var contact = contactData;
|
||||
|
||||
var favorite = !isFavorite(contact);
|
||||
toggleFavoriteMessage(favorite);
|
||||
if (favorite) {
|
||||
contact.category = contact.category || [];
|
||||
contact.category.push('favorite');
|
||||
} else {
|
||||
if (!contact.category) {
|
||||
return;
|
||||
}
|
||||
var pos = contact.category.indexOf('favorite');
|
||||
if (pos > -1) {
|
||||
contact.category.splice(pos, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Disabling button while saving the contact
|
||||
favoriteMessage.style.pointerEvents = 'none';
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
ContactsService.save(
|
||||
utils.misc.toMozContact(contact),
|
||||
function(e) {
|
||||
if (e) {
|
||||
favoriteMessage.style.pointerEvents = 'auto';
|
||||
console.error('Error saving favorite');
|
||||
reject('Error saving favorite');
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
isAFavoriteChange = true;
|
||||
ContactsService.get(
|
||||
contact.id,
|
||||
function onSuccess(savedContact) {
|
||||
renderFavorite(savedContact);
|
||||
setContact(savedContact);
|
||||
favoriteMessage.style.pointerEvents = 'auto';
|
||||
},
|
||||
function onError() {
|
||||
console.error('Error reloading contact');
|
||||
favoriteMessage.style.pointerEvents = 'auto';
|
||||
}
|
||||
);
|
||||
resolve(isAFavoriteChange);
|
||||
}
|
||||
);
|
||||
}).then();
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
var toggleFavoriteMessage = function toggleFavMessage(isFav) {
|
||||
var cList = favoriteMessage.classList;
|
||||
var l10nId = isFav ? 'removeFavorite' : 'addFavorite';
|
||||
favoriteMessage.setAttribute('data-l10n-id', l10nId);
|
||||
isFav ? cList.add('on') : cList.remove('on');
|
||||
};
|
||||
|
||||
var renderOrg = function cd_renderOrg(contact) {
|
||||
if (contact.org && contact.org.length > 0 && contact.org[0] !== '') {
|
||||
orgTitle.textContent = contact.org[0];
|
||||
orgTitle.classList.remove('hide');
|
||||
} else {
|
||||
orgTitle.classList.add('hide');
|
||||
orgTitle.textContent = '';
|
||||
}
|
||||
};
|
||||
|
||||
var renderDates = function cd_renderDates(contact) {
|
||||
if (!contact.bday && !contact.anniversary) {
|
||||
return;
|
||||
}
|
||||
|
||||
var dateString = '';
|
||||
|
||||
var fields = ['bday', 'anniversary'];
|
||||
var l10nIds = ['birthday', 'anniversary'];
|
||||
|
||||
var rendered = 0;
|
||||
for (var j = 0; j < fields.length; j++) {
|
||||
var value = contact[fields[j]];
|
||||
if (!value) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
dateString = utils.misc.formatDate(value);
|
||||
} catch (err) {
|
||||
console.error('Error parsing date');
|
||||
continue;
|
||||
}
|
||||
var element = utils.templates.render(datesTemplate, {
|
||||
i: ++rendered,
|
||||
date: dateString,
|
||||
type: _(l10nIds[j])
|
||||
});
|
||||
|
||||
listContainer.appendChild(element);
|
||||
}
|
||||
};
|
||||
|
||||
var renderShareButton = function cd_renderShareButton(contact) {
|
||||
var social = utils.templates.render(socialTemplate, {
|
||||
i: contact.id
|
||||
});
|
||||
currentSocial = social;
|
||||
var shareButton = social.querySelector('#share_button');
|
||||
|
||||
shareButton.addEventListener('click', shareContact);
|
||||
shareButton.classList.remove('hide');
|
||||
|
||||
listContainer.appendChild(social);
|
||||
};
|
||||
|
||||
var renderWebrtcClient = function renderWebrtcClient(contact) {
|
||||
getWebrtcClientResources(function onLoaded() {
|
||||
WebrtcClient.start(contact);
|
||||
});
|
||||
};
|
||||
|
||||
var renderAddresses = function cd_renderAddresses(contact) {
|
||||
if (!contact.adr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < contact.adr.length; i++) {
|
||||
var currentAddress = contact.adr[i];
|
||||
// Sanity check
|
||||
if (utils.mozContact.haveEmptyFields(currentAddress,
|
||||
['streetAddress', 'postalCode', 'locality', 'countryName'])) {
|
||||
continue;
|
||||
}
|
||||
var address = currentAddress.streetAddress || '';
|
||||
var escapedStreet = Normalizer.escapeHTML(address, true);
|
||||
var locality = currentAddress.locality;
|
||||
var escapedLocality = Normalizer.escapeHTML(locality, true);
|
||||
var escapedType = Normalizer.escapeHTML(currentAddress.type, true);
|
||||
var country = currentAddress.countryName || '';
|
||||
var escapedCountry = Normalizer.escapeHTML(country, true);
|
||||
var postalCode = currentAddress.postalCode || '';
|
||||
var escapedPostalCode = Normalizer.escapeHTML(postalCode, true);
|
||||
|
||||
var addressField = {
|
||||
streetAddress: escapedStreet,
|
||||
postalCode: escapedPostalCode,
|
||||
locality: escapedLocality || '',
|
||||
countryName: escapedCountry,
|
||||
type: _(escapedType) || escapedType ||
|
||||
TAG_OPTIONS['address-type'][0].value,
|
||||
'type_l10n_id': currentAddress.type,
|
||||
i: i
|
||||
};
|
||||
var template = utils.templates.render(addressesTemplate, addressField);
|
||||
listContainer.appendChild(template);
|
||||
}
|
||||
};
|
||||
|
||||
var renderDuplicate = function cd_renderDuplicate(contact) {
|
||||
var dupItem = utils.templates.render(duplicateTemplate, {});
|
||||
var findMergeButton = dupItem.querySelector('#find-merge-button');
|
||||
findMergeButton.disabled = true;
|
||||
|
||||
if (contacts.List.total > 1) {
|
||||
// Only have this active if contact list has more than one entry
|
||||
findMergeButton.disabled = false;
|
||||
findMergeButton.addEventListener('click', function finding() {
|
||||
MatchService.match(contact.id);
|
||||
});
|
||||
}
|
||||
|
||||
listContainer.appendChild(dupItem);
|
||||
};
|
||||
|
||||
var renderNotes = function cd_rederNotes(contact) {
|
||||
if (!contact.note || contact.note.length === 0) {
|
||||
return;
|
||||
}
|
||||
var container = document.createElement('li');
|
||||
var title = document.createElement('h2');
|
||||
title.setAttribute('data-l10n-id', 'comments');
|
||||
container.appendChild(title);
|
||||
for (var i = 0; i < contact.note.length; i++) {
|
||||
var currentNote = contact.note[i];
|
||||
var noteField = {
|
||||
note: Normalizer.escapeHTML(currentNote, true) || '',
|
||||
i: i
|
||||
};
|
||||
var template = utils.templates.render(notesTemplate, noteField);
|
||||
container.appendChild(template);
|
||||
listContainer.appendChild(container);
|
||||
}
|
||||
};
|
||||
|
||||
var calculateHash = function calculateHash(photo, cb) {
|
||||
var START_BYTES = 127;
|
||||
var BYTES_HASH = 16;
|
||||
|
||||
var out = [photo.type, photo.size];
|
||||
|
||||
// We skip the first bytes that typically are headers
|
||||
var chunk = photo.slice(START_BYTES, START_BYTES + BYTES_HASH);
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function() {
|
||||
out.push(reader.result);
|
||||
cb(out.join(''));
|
||||
};
|
||||
reader.onerror = function() {
|
||||
window.console.error('Error while calculating the hash: ',
|
||||
reader.error.name);
|
||||
cb(out.join(''));
|
||||
};
|
||||
reader.readAsDataURL(chunk);
|
||||
};
|
||||
|
||||
var updateHash = function updateHash(photo, cover) {
|
||||
calculateHash(photo, function(hash) {
|
||||
cover.dataset.imgHash = hash;
|
||||
});
|
||||
};
|
||||
|
||||
var renderPhoto = function cd_renderPhoto(contact) {
|
||||
contactDetails.classList.remove('up');
|
||||
if (isFbContact) {
|
||||
contactDetails.classList.add('fb-contact');
|
||||
}
|
||||
|
||||
var photo = ContactPhotoHelper.getFullResolution(contact);
|
||||
if (photo) {
|
||||
var currentHash = cover.dataset.imgHash;
|
||||
if (!currentHash) {
|
||||
utils.dom.updatePhoto(photo, cover);
|
||||
updateHash(photo, cover);
|
||||
}
|
||||
else {
|
||||
// Need to recalculate the hash and see whether the images changed
|
||||
calculateHash(photo, function(newHash) {
|
||||
if (currentHash !== newHash) {
|
||||
utils.dom.updatePhoto(photo, cover);
|
||||
cover.dataset.imgHash = newHash;
|
||||
}
|
||||
else {
|
||||
// Only for testing purposes
|
||||
cover.dataset.photoReady = 'true';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
contactDetails.classList.add('up');
|
||||
cover.classList.add('translated');
|
||||
contactDetails.classList.add('translated');
|
||||
var clientHeight = contactDetails.clientHeight -
|
||||
(initMargin * 10 * SCALE_RATIO);
|
||||
if (detailsInner.offsetHeight < clientHeight) {
|
||||
cover.style.overflow = 'hidden';
|
||||
} else {
|
||||
cover.style.overflow = 'auto';
|
||||
}
|
||||
} else {
|
||||
resetPhoto();
|
||||
}
|
||||
};
|
||||
|
||||
var resetPhoto = function cd_resetPhoto() {
|
||||
cover.classList.remove('translated');
|
||||
contactDetails.classList.remove('translated');
|
||||
cover.style.backgroundImage = '';
|
||||
cover.style.overflow = 'auto';
|
||||
contactDetails.style.transform = '';
|
||||
contactDetails.classList.add('no-photo');
|
||||
cover.dataset.imgHash = '';
|
||||
};
|
||||
|
||||
var shareContact = function cd_shareContact() {
|
||||
const VCARD_DEPS = [
|
||||
'/shared/js/text_normalizer.js',
|
||||
'/shared/js/contact2vcard.js',
|
||||
'/shared/js/setImmediate.js'
|
||||
];
|
||||
|
||||
LazyLoader.load(VCARD_DEPS,function vcardLoaded() {
|
||||
ContactToVcardBlob([contactData], function blobReady(vcardBlob) {
|
||||
VcardFilename(contactData).then(filename => {
|
||||
new MozActivity({
|
||||
name: 'share',
|
||||
data: {
|
||||
type: 'text/vcard',
|
||||
number: 1,
|
||||
blobs: [new window.File([vcardBlob], filename, {
|
||||
type: 'text/x-vcard'
|
||||
})],
|
||||
filenames: [filename]
|
||||
}
|
||||
});
|
||||
});
|
||||
// The MIME of the blob should be this for some MMS gateways
|
||||
}, { type: 'text/x-vcard'} );
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
'init': init,
|
||||
'setContact': setContact,
|
||||
'toggleFavorite': toggleFavorite,
|
||||
'render': render,
|
||||
'defaultTelType': DEFAULT_TEL_TYPE,
|
||||
'startNFC': startNFC
|
||||
};
|
||||
})();
|
||||
1507
gaia/apps/communications/contacts/js/views/form.js
Executable file
1507
gaia/apps/communications/contacts/js/views/form.js
Executable file
File diff suppressed because it is too large
Load diff
108
gaia/apps/communications/contacts/js/views/ice.js
Executable file
108
gaia/apps/communications/contacts/js/views/ice.js
Executable file
|
|
@ -0,0 +1,108 @@
|
|||
/* global ICEData */
|
||||
/* global ImageLoader */
|
||||
/* global LazyLoader */
|
||||
/* global MainNavigation */
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
|
||||
var contactsIds = null;
|
||||
var rowBuilderFn = null;
|
||||
var imgLoader = null;
|
||||
var initialized = false;
|
||||
var iceListDisplayed = false;
|
||||
|
||||
/**
|
||||
* Initialises the component by passing a list of ICE ids,
|
||||
* a function that knows how to build contact list rows and
|
||||
* another function to perform actions when clicking on a
|
||||
* ICE contact.
|
||||
* This function should be the same than the contacts list one
|
||||
* to keep the same behavior (activities, select, etc.)
|
||||
* @param ids (Array) array of contact ids
|
||||
* @param rowBuilder (function) function that paints contac list
|
||||
* rows, shared with the contact list
|
||||
* @param clickHandler (function) action to perform when clicked
|
||||
* on a item
|
||||
*/
|
||||
function init(ids, rowBuilder, clickHandler) {
|
||||
rowBuilderFn = rowBuilder;
|
||||
contactsIds = ids;
|
||||
|
||||
imgLoader = new ImageLoader('#ice-list', 'li');
|
||||
buildICEContactsList();
|
||||
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
// Initialise common controls
|
||||
document.getElementById('ice-header').addEventListener(
|
||||
'action', hideICEList);
|
||||
document.getElementById('ice-list').addEventListener('click', clickHandler);
|
||||
|
||||
LazyLoader.load(['/contacts/js/utilities/ice_data.js'], function() {
|
||||
listenForChanges();
|
||||
});
|
||||
}
|
||||
|
||||
// Once the list is built, we need to be aware of possible changes in
|
||||
// contacts. In that case rebuild the whole list, since ICE list is meant
|
||||
// to be a small set (2 currently) of contacts.
|
||||
function listenForChanges() {
|
||||
ICEData.listenForChanges(function(newList) {
|
||||
contactsIds = [];
|
||||
newList.forEach(function(iceContact) {
|
||||
if (iceContact.id && iceContact.active) {
|
||||
contactsIds.push(iceContact.id);
|
||||
}
|
||||
});
|
||||
buildICEContactsList();
|
||||
});
|
||||
}
|
||||
|
||||
// Clone the nodes on the contacts list, also rebuild them with
|
||||
// the row builder function passed on initialization.
|
||||
// Due to the nature of the contacts list, despite of having the
|
||||
// nodes, those may have not being initialized, that's why we need
|
||||
// the use of this builder function
|
||||
function buildICEContactsList() {
|
||||
var iceList = document.getElementById('ice-group');
|
||||
iceList.innerHTML = '';
|
||||
|
||||
contactsIds.forEach(function(id) {
|
||||
var node = document.querySelector('[data-uuid="' + id + '"]');
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
node = rowBuilderFn(id, node);
|
||||
iceList.appendChild(node);
|
||||
});
|
||||
|
||||
imgLoader.reload();
|
||||
}
|
||||
|
||||
function showICEList() {
|
||||
MainNavigation.go('ice-view', 'right-left');
|
||||
iceListDisplayed = true;
|
||||
}
|
||||
|
||||
function hideICEList() {
|
||||
MainNavigation.back();
|
||||
iceListDisplayed = false;
|
||||
}
|
||||
|
||||
var ICEView = {
|
||||
init: init,
|
||||
showICEList: showICEList,
|
||||
hideICEList: hideICEList,
|
||||
get iceListDisplayed() {
|
||||
return iceListDisplayed;
|
||||
}
|
||||
};
|
||||
|
||||
exports.ICEView = ICEView;
|
||||
|
||||
})(window);
|
||||
354
gaia/apps/communications/contacts/js/views/ice_settings.js
Executable file
354
gaia/apps/communications/contacts/js/views/ice_settings.js
Executable file
|
|
@ -0,0 +1,354 @@
|
|||
/* global Contacts */
|
||||
/* global ICEData */
|
||||
/* global ConfirmDialog */
|
||||
/* global ContactsService */
|
||||
/* global HeaderUI */
|
||||
/* global Search */
|
||||
|
||||
/**
|
||||
* ICE Settings view. In charge of selecting
|
||||
* the contacts for emergency and keeping sync
|
||||
* the datastore to share those contacts with
|
||||
* dialer and lockscreen.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var contacts = window.contacts || {};
|
||||
|
||||
(function(exports) {
|
||||
var iceSettingsPanel,
|
||||
iceSettingsHeader,
|
||||
iceContactItems = [],
|
||||
iceContactCheckboxes = [],
|
||||
iceContactButtons = [],
|
||||
iceScreenInitialized = false,
|
||||
currentICETarget;
|
||||
|
||||
/**
|
||||
* Redraws the ICE contact list. This is not an expensive
|
||||
* operation since we have a maximun of 2 contacts.
|
||||
* The first time executed will attach listeners for the
|
||||
* frame ui.
|
||||
*/
|
||||
var init = function ice_init() {
|
||||
if (iceScreenInitialized) {
|
||||
return;
|
||||
}
|
||||
// ICE DOM elements
|
||||
iceSettingsPanel = document.getElementById('ice-settings');
|
||||
iceSettingsHeader = document.getElementById('ice-settings-header');
|
||||
|
||||
iceContactItems.push(document.getElementById('ice-contacts-1-switch'));
|
||||
iceContactItems.push(document.getElementById('ice-contacts-2-switch'));
|
||||
|
||||
iceContactCheckboxes.push(iceContactItems[0]
|
||||
.querySelector('[name="ice-contact-1-enabled"]'));
|
||||
iceContactCheckboxes.push(iceContactItems[1]
|
||||
.querySelector('[name="ice-contact-2-enabled"]'));
|
||||
iceContactButtons.push(document.getElementById('select-ice-contact-1'));
|
||||
iceContactButtons.push(document.getElementById('select-ice-contact-2'));
|
||||
|
||||
iceContactButtons[0].dataset.contactId = '';
|
||||
iceContactButtons[1].dataset.contactId = '';
|
||||
|
||||
// ICE Events handlers
|
||||
iceSettingsHeader.addEventListener('action', function(){
|
||||
contacts.Settings.navigation.back();
|
||||
});
|
||||
|
||||
// All the controls do the same, just modifications on the
|
||||
// specific order.
|
||||
iceContactItems.forEach(function(item, index) {
|
||||
iceContactCheckboxes[index].addEventListener('change', function(i) {
|
||||
return function(evt) {
|
||||
var localIceContacts = ICEData.iceContacts;
|
||||
var wasActive = !iceContactCheckboxes[i].checked;
|
||||
|
||||
if (wasActive) {
|
||||
resetIceGroupState(i);
|
||||
if (localIceContacts[i] && localIceContacts[i].id) {
|
||||
setICEContact(null, i, !wasActive);
|
||||
}
|
||||
}
|
||||
else {
|
||||
iceContactButtons[i].disabled = false;
|
||||
}
|
||||
};
|
||||
}(index));
|
||||
});
|
||||
|
||||
iceContactButtons.forEach(function(element){
|
||||
element.addEventListener('click', function(evt) {
|
||||
showSelectList(evt.target.id);
|
||||
});
|
||||
// Bug 1071064 If users clicked on disabled button, the switch was checked
|
||||
element.parentNode.addEventListener('click', (evt) => {
|
||||
evt.stopPropagation();
|
||||
});
|
||||
});
|
||||
|
||||
iceScreenInitialized = true;
|
||||
};
|
||||
|
||||
function reloadButtonsState(cb) {
|
||||
ICEData.load().then(retrieveContactData.bind(null, cb));
|
||||
}
|
||||
|
||||
function retrieveContactData(cb) {
|
||||
var iceContactsData = [];
|
||||
var iceContactsIds = ICEData.iceContacts;
|
||||
var numRetrievedContacts = 0;
|
||||
|
||||
iceContactsIds.forEach(function(iceContact, index) {
|
||||
ContactsService.get(iceContact.id, function(cindex, contact) {
|
||||
var theContact = {
|
||||
active: iceContactsIds[cindex].active,
|
||||
mozContact: contact
|
||||
};
|
||||
|
||||
iceContactsData[cindex] = theContact;
|
||||
|
||||
numRetrievedContacts++;
|
||||
|
||||
if (numRetrievedContacts === 2) {
|
||||
setButtonsState(iceContactsData, cb);
|
||||
}
|
||||
}.bind(null, index));
|
||||
});
|
||||
}
|
||||
|
||||
function refresh(done) {
|
||||
if (!iceScreenInitialized) {
|
||||
init();
|
||||
}
|
||||
reloadButtonsState(done);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an object representing the internal state
|
||||
* fills the UI elements.
|
||||
* @params iceContactsIds (Array) list of contacts and state
|
||||
*/
|
||||
function setButtonsState(iceContactsData, done) {
|
||||
iceContactsData.forEach(setIceButtonState);
|
||||
|
||||
typeof done === 'function' && done();
|
||||
}
|
||||
|
||||
function setIceButtonState(iceContactData, index) {
|
||||
if (!iceContactData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (iceContactData.mozContact) {
|
||||
var iceContact = iceContactData.mozContact;
|
||||
|
||||
var givenName = (Array.isArray(iceContact.givenName) &&
|
||||
iceContact.givenName[0]) || '';
|
||||
var familyName = (Array.isArray(iceContact.familyName) &&
|
||||
iceContact.familyName[0]) || '';
|
||||
|
||||
var display = [givenName, familyName];
|
||||
var iceLabel = display.join(' ').trim();
|
||||
// If contact has no name we the first tel number will be used
|
||||
if (!iceLabel) {
|
||||
if (Array.isArray(iceContact.tel) && iceContact.tel[0]) {
|
||||
iceLabel = iceContact.tel[0].value.trim();
|
||||
}
|
||||
}
|
||||
|
||||
buildIceContactUI(index, iceLabel, iceContact.id,
|
||||
iceContactData.active);
|
||||
}
|
||||
else {
|
||||
resetIceGroupState(index);
|
||||
}
|
||||
}
|
||||
|
||||
function buildIceContactUI(index, label, contactId, active) {
|
||||
iceContactCheckboxes[index].checked = active;
|
||||
iceContactButtons[index].disabled = !active;
|
||||
|
||||
var bdi = document.createElement('bdi');
|
||||
bdi.classList.add('ice-contact');
|
||||
bdi.textContent = label;
|
||||
iceContactButtons[index].innerHTML = '';
|
||||
iceContactButtons[index].appendChild(bdi);
|
||||
iceContactButtons[index].dataset.contactId = contactId;
|
||||
}
|
||||
|
||||
function resetIceGroupState(index) {
|
||||
iceContactCheckboxes[index].checked = false;
|
||||
|
||||
iceContactButtons[index].disabled = true;
|
||||
iceContactButtons[index].innerHTML = '';
|
||||
iceContactButtons[index].dataset.contactId = '';
|
||||
iceContactButtons[index].setAttribute('data-l10n-id', 'ICESelectContact');
|
||||
}
|
||||
|
||||
function resetIceGroupStates() {
|
||||
for(var j = 0; j < iceContactCheckboxes.length; j++) {
|
||||
resetIceGroupState(j);
|
||||
}
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
contacts.List.clearClickHandlers();
|
||||
contacts.List.handleClick(Contacts.showContactDetail);
|
||||
HeaderUI.setNormalHeader();
|
||||
|
||||
var hasICESet = ICEData.iceContacts.find(function(x) {
|
||||
return x.active === true;
|
||||
});
|
||||
|
||||
if (!hasICESet) {
|
||||
resetIceGroupStates();
|
||||
}
|
||||
|
||||
if (window.Search && Search.isInSearchMode()) {
|
||||
Search.exitSearchMode();
|
||||
}
|
||||
|
||||
contacts.Settings.navigation.back(() => {
|
||||
hasICESet && contacts.List.toggleICEGroup(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a contact id, saves it internally. Also restores the contact
|
||||
* list default handler.
|
||||
* In case of not valid contact it will display a message on the screen
|
||||
* indicating the cause of the error.
|
||||
* @param id (string) contact id
|
||||
*/
|
||||
function selectICEHandler(id) {
|
||||
checkContact(id).then(function() {
|
||||
setICEContact(id, currentICETarget, true, goBack);
|
||||
}, function error(l10nId) {
|
||||
var dismiss = {
|
||||
title: 'ok',
|
||||
callback: function() {
|
||||
ConfirmDialog.hide();
|
||||
}
|
||||
};
|
||||
ConfirmDialog.show(null, l10nId || 'ICEUnknownError', dismiss);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Will perform a series of checks to validate the selected
|
||||
* contact as a valid ICE contact
|
||||
* @param id (string) contact id
|
||||
* @return (Promise) fulfilled if contact is valid
|
||||
*/
|
||||
function checkContact(id) {
|
||||
return ICEData.load().then(function() {
|
||||
return contactNotICE(id).then(contactNotAllowed);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a contacts is already set as ICE
|
||||
* @param id (string) contact id
|
||||
* @return (Promise) fulfilled if contact is not repeated,
|
||||
* rejected otherwise
|
||||
*/
|
||||
function contactNotICE(id) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var isICE = ICEData.iceContacts.some(function(x) {
|
||||
return x.id === id;
|
||||
});
|
||||
|
||||
if (isICE) {
|
||||
reject('ICERepeatedContact');
|
||||
} else {
|
||||
resolve(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter to avoid selecting contacts as ICE if they don't have a phone number
|
||||
* or they are a Facebook contact
|
||||
* @param id (String) contact id
|
||||
* @returns (Promise) Fulfilled if contact has phone
|
||||
*/
|
||||
function contactNotAllowed(id) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
ContactsService.get(id, function(contact) {
|
||||
if(Array.isArray(contact.tel) && contact.tel[0] &&
|
||||
contact.tel[0].value && contact.tel[0].value.trim()) {
|
||||
resolve(id);
|
||||
} else {
|
||||
reject('ICEContactNoNumber');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* We are using the contact list to choose a contact as ICE. For doing
|
||||
* this, we need to setup our own click handler.
|
||||
* @para target (HTMLButton) Button click to select an ICE contact
|
||||
*/
|
||||
function showSelectList(target) {
|
||||
contacts.List.toggleICEGroup(false);
|
||||
HeaderUI.setCancelableHeader(goBack, 'selectContact');
|
||||
contacts.Settings.navigation.go('view-contacts-list', 'right-left');
|
||||
currentICETarget = target === 'select-ice-contact-1' ? 0 : 1;
|
||||
contacts.List.clearClickHandlers();
|
||||
contacts.List.handleClick(selectICEHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the values for ICE contacts, both in local and in the
|
||||
* datastore
|
||||
* @param id (string) contact id
|
||||
* @param pos (int) current position (0,1)
|
||||
* @param active (boolean) ice contact is active or not
|
||||
* @param cb (function) callback when ready
|
||||
*/
|
||||
function setICEContact(id, pos, active, cb) {
|
||||
ICEData.setICEContact(id, pos, active).then(function() {
|
||||
// Only reload contact info in case there is a change in the contact
|
||||
if (id === iceContactButtons[pos].dataset.contactId) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContactsService.get(id, function(contact) {
|
||||
var theContact = {
|
||||
active: active,
|
||||
mozContact: contact
|
||||
};
|
||||
var iceContactData = [];
|
||||
if (pos === 0) {
|
||||
iceContactData[1] = null;
|
||||
}
|
||||
else {
|
||||
iceContactData[0] = null;
|
||||
}
|
||||
iceContactData[pos] = theContact;
|
||||
|
||||
setButtonsState(iceContactData);
|
||||
|
||||
typeof cb === 'function' && cb();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function reset() {
|
||||
iceScreenInitialized = false;
|
||||
iceContactItems = [];
|
||||
iceContactCheckboxes = [];
|
||||
iceContactButtons = [];
|
||||
currentICETarget = null;
|
||||
}
|
||||
|
||||
exports.ICE = {
|
||||
init: init,
|
||||
refresh: refresh,
|
||||
reset: reset,
|
||||
get initialized() { return iceScreenInitialized; }
|
||||
};
|
||||
})(window);
|
||||
2443
gaia/apps/communications/contacts/js/views/list.js
Executable file
2443
gaia/apps/communications/contacts/js/views/list.js
Executable file
File diff suppressed because it is too large
Load diff
148
gaia/apps/communications/contacts/js/views/multiple_select.js
Executable file
148
gaia/apps/communications/contacts/js/views/multiple_select.js
Executable file
|
|
@ -0,0 +1,148 @@
|
|||
/* global Contacts, contacts, utils, LazyLoader */
|
||||
/* global ContactsService */
|
||||
/* global Matcher */
|
||||
|
||||
'use strict';
|
||||
|
||||
window.Contacts = window.Contacts || {};
|
||||
|
||||
Contacts.MultipleSelect = (function() {
|
||||
const STATUS_TIMEOUT = 3000; // ms before closing view which shows status msg
|
||||
var contactsToImport = [];
|
||||
var header, saveButton, container, template, title;
|
||||
|
||||
/**
|
||||
* Initializes references to DOM elements. This is needed before calling
|
||||
* render.
|
||||
*/
|
||||
function init() {
|
||||
header = document.getElementById('multiple-select-view-header');
|
||||
saveButton = document.getElementById('save-button');
|
||||
container = document.getElementById('multiple-select-container');
|
||||
template = document.getElementById('contactToImportTemplate');
|
||||
title = document.getElementById('multiple-select-view-title');
|
||||
|
||||
saveButton.addEventListener('click', importAll);
|
||||
header.addEventListener('action', cancelHandler);
|
||||
}
|
||||
|
||||
function cancelHandler() {
|
||||
header.removeEventListener('action', cancelHandler);
|
||||
saveButton.removeEventListener('click', importAll);
|
||||
Contacts.cancel();
|
||||
}
|
||||
|
||||
function importAll() {
|
||||
var numDupsMerged = 0,
|
||||
importedContacts = 0,
|
||||
parsedContacts = 0;
|
||||
const DEPENDENCIES = [
|
||||
'/shared/js/contacts/import/utilities/status.js',
|
||||
'/shared/js/simple_phone_matcher.js',
|
||||
'/shared/js/contacts/contacts_matcher.js',
|
||||
'/shared/js/contacts/contacts_merger.js',
|
||||
'/shared/js/contacts/merger_adapter.js'
|
||||
];
|
||||
LazyLoader.load(DEPENDENCIES, function() {
|
||||
contactsToImport.forEach((contact, index) => {
|
||||
Matcher.match(contact, 'passive', {
|
||||
onmatch: (matches) => {
|
||||
var callbacks = {
|
||||
success: () => {
|
||||
numDupsMerged++;
|
||||
doContinue(true);
|
||||
},
|
||||
error: doContinue
|
||||
};
|
||||
contacts.adaptAndMerge(contact, matches, callbacks);
|
||||
},
|
||||
onmismatch: () => {
|
||||
|
||||
ContactsService.save(
|
||||
contact,
|
||||
function(e) {
|
||||
if (e) {
|
||||
console.error(e);
|
||||
doContinue();
|
||||
return;
|
||||
}
|
||||
doContinue(true);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function doContinue(isContactImported) {
|
||||
parsedContacts++;
|
||||
if (isContactImported) {
|
||||
importedContacts++;
|
||||
}
|
||||
|
||||
if (contactsToImport.length <= parsedContacts) {
|
||||
utils.status.show({
|
||||
id: 'vCardContacts-imported',
|
||||
args: {
|
||||
n: importedContacts
|
||||
}
|
||||
}, {
|
||||
id: 'contactsMerged',
|
||||
args: {
|
||||
numDups: numDupsMerged
|
||||
}
|
||||
});
|
||||
|
||||
window.setTimeout(cancelHandler, STATUS_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to preview which contacts will be imported. Requires to call init
|
||||
* first when DOM is ready.
|
||||
*
|
||||
* @param {mozContact[]} contacts - Every contact already read from vCard.
|
||||
* @param cursor - Reader object to continue reading from vCard.
|
||||
* @param {string} filename - Name of the vcf file we are reading from.
|
||||
*/
|
||||
var render = function(contacts, cursor, filename) {
|
||||
container.innerHTML = ''; // Avoids rendering the same content twice.
|
||||
title.textContent = filename;
|
||||
contacts.forEach(doRenderContact);
|
||||
|
||||
cursor.onsuccess = function(event) {
|
||||
var contact = event.target.result;
|
||||
if (contact) {
|
||||
doRenderContact(contact);
|
||||
cursor.continue();
|
||||
}
|
||||
};
|
||||
|
||||
function doRenderContact(contact) {
|
||||
var clone = document.importNode(template.content, true);
|
||||
|
||||
var contactData = clone.querySelectorAll('p');
|
||||
contactData[0].textContent =
|
||||
Array.isArray(contact.name) && contact.name[0];
|
||||
var org = (Array.isArray(contact.org) && contact.org[0]) ?
|
||||
contact.org[0] : '';
|
||||
contactData[1].textContent = org;
|
||||
|
||||
if (Array.isArray(contact.photo) && contact.photo[0] instanceof Blob) {
|
||||
var picture = clone.querySelector('aside span');
|
||||
picture.style.backgroundImage = 'url(' +
|
||||
window.URL.createObjectURL(contact.photo[0]) +
|
||||
')';
|
||||
}
|
||||
|
||||
contactsToImport.push(contact);
|
||||
container.appendChild(clone);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
render: render,
|
||||
init: init
|
||||
};
|
||||
})();
|
||||
856
gaia/apps/communications/contacts/js/views/settings.js
Executable file
856
gaia/apps/communications/contacts/js/views/settings.js
Executable file
|
|
@ -0,0 +1,856 @@
|
|||
'use strict';
|
||||
/* global _ */
|
||||
/* global Cache */
|
||||
/* global ConfirmDialog */
|
||||
/* global Contacts */
|
||||
/* global ContactsBTExport */
|
||||
/* global ContactsExporter */
|
||||
/* global ContactsSDExport */
|
||||
/* global ContactsSIMExport */
|
||||
/* global IccHandler */
|
||||
/* global LazyLoader */
|
||||
/* global navigationStack */
|
||||
/* global Rest */
|
||||
/* global SimContactsImporter */
|
||||
/* global SimDomGenerator */
|
||||
/* global utils */
|
||||
/* global VCFReader */
|
||||
/* global ContactsService */
|
||||
/* global ExtServices */
|
||||
/* global Loader */
|
||||
/* global BulkDelete */
|
||||
/* global ICE */
|
||||
/* global Telemetry */
|
||||
|
||||
var contacts = window.contacts || {};
|
||||
|
||||
/***
|
||||
This class handles all the activity regarding
|
||||
the settings screen for contacts
|
||||
**/
|
||||
contacts.Settings = (function() {
|
||||
|
||||
var navigationHandler,
|
||||
importSettingsHeader,
|
||||
orderCheckBox,
|
||||
orderItem,
|
||||
orderByLastName,
|
||||
setICEButton,
|
||||
importSettingsPanel,
|
||||
importSettingsTitle,
|
||||
importContacts,
|
||||
exportContacts,
|
||||
importOptions,
|
||||
exportOptions,
|
||||
importLiveOption,
|
||||
importGmailOption,
|
||||
importSDOption,
|
||||
exportSDOption,
|
||||
newOrderByLastName = null,
|
||||
PENDING_LOGOUT_KEY = 'pendingLogout',
|
||||
bulkDeleteButton;
|
||||
|
||||
var EXPORT_TRANSITION_LEVEL = 2, DELETE_TRANSITION_LEVEL = 1;
|
||||
|
||||
// Initialise the settings screen (components, listeners ...)
|
||||
var init = function initialize() {
|
||||
// Create the DOM for our SIM cards and listen to any changes
|
||||
IccHandler.init(new SimDomGenerator(), contacts.Settings.cardStateChanged);
|
||||
|
||||
initContainers();
|
||||
// To avoid any race condition we listen for online events once
|
||||
// containers have been initialized
|
||||
window.addEventListener('online', checkOnline);
|
||||
window.addEventListener('offline', checkOnline);
|
||||
|
||||
// Subscribe to events related to change state in the sd card
|
||||
utils.sdcard.subscribeToChanges('check_sdcard', function(value) {
|
||||
updateStorageOptions(utils.sdcard.checkStorageCard());
|
||||
});
|
||||
|
||||
window.addEventListener('timeformatchange', updateTimestamps);
|
||||
};
|
||||
|
||||
var hideSettings = function hideSettings() {
|
||||
contacts.Settings.close();
|
||||
};
|
||||
|
||||
// Get the different values that we will show in the app
|
||||
var getData = function getData() {
|
||||
var config = utils.cookie.load();
|
||||
var order = config ? config.order : false;
|
||||
orderByLastName = order;
|
||||
newOrderByLastName = null;
|
||||
updateOrderingUI();
|
||||
};
|
||||
|
||||
var updateOrderingUI = function updateOrderingUI() {
|
||||
var value = newOrderByLastName === null ? orderByLastName :
|
||||
newOrderByLastName;
|
||||
orderCheckBox.checked = value;
|
||||
orderCheckBox.setAttribute('aria-checked', value);
|
||||
};
|
||||
|
||||
var updateImportTitle = function updateImportTitle(l10nString) {
|
||||
importSettingsTitle.setAttribute('data-l10n-id', l10nString);
|
||||
};
|
||||
|
||||
// Initialises variables and listener for the UI
|
||||
var initContainers = function initContainers() {
|
||||
orderItem = document.getElementById('settingsOrder');
|
||||
orderCheckBox = orderItem.querySelector('[name="order.lastname"]');
|
||||
orderCheckBox.addEventListener('change', onOrderingChange.bind(this));
|
||||
// Creating a navigation handler from this view
|
||||
navigationHandler = new navigationStack('view-settings');
|
||||
|
||||
// Init panel & elements for caching them
|
||||
importSettingsPanel = document.getElementById('import-settings');
|
||||
importSDOption = document.getElementById('import-sd-option');
|
||||
exportSDOption = document.getElementById('export-sd-option');
|
||||
importSettingsTitle = document.getElementById('import-settings-title');
|
||||
importLiveOption = document.getElementById('import-live-option');
|
||||
importGmailOption = document.getElementById('import-gmail-option');
|
||||
|
||||
// ICE view
|
||||
setICEButton = document.getElementById('set-ice');
|
||||
|
||||
/*
|
||||
* Adding listeners
|
||||
*/
|
||||
|
||||
document.getElementById('settings-close').addEventListener(
|
||||
'click',
|
||||
hideSettings
|
||||
);
|
||||
// Listener for updating the timestamp based on extServices
|
||||
window.addEventListener('message', function updateList(e) {
|
||||
if (e.data.type === 'import_updated') {
|
||||
updateTimestamps();
|
||||
checkNoContacts();
|
||||
}
|
||||
});
|
||||
|
||||
// Navigation back
|
||||
importSettingsHeader = document.getElementById('import-settings-header');
|
||||
importSettingsHeader.addEventListener('action', importSettingsBackHandler);
|
||||
|
||||
// Handlers for the navigation through the panels
|
||||
importContacts = document.getElementById('importContacts');
|
||||
importContacts.firstElementChild.
|
||||
addEventListener('click', importContactsHandler);
|
||||
|
||||
exportContacts = document.getElementById('exportContacts');
|
||||
exportContacts.firstElementChild.
|
||||
addEventListener('click', exportContactsHandler);
|
||||
|
||||
// Handlers for the actions related with EXPORT/IMPORT
|
||||
importOptions = document.getElementById('import-options');
|
||||
importOptions.addEventListener('click', importOptionsHandler);
|
||||
|
||||
exportOptions = document.getElementById('export-options');
|
||||
exportOptions.addEventListener('click', exportOptionsHandler);
|
||||
|
||||
// ICE view
|
||||
setICEButton.addEventListener('click', showICEScreen);
|
||||
|
||||
// Bulk delete
|
||||
bulkDeleteButton = document.getElementById('bulkDelete');
|
||||
bulkDeleteButton.addEventListener('click', bulkDeleteHandler);
|
||||
};
|
||||
|
||||
// UI event handlers
|
||||
function importSettingsBackHandler() {
|
||||
navigationHandler.back(function navigateBackHandler() {
|
||||
// Removing the previous assigned style for having
|
||||
// a clean view
|
||||
importSettingsPanel.classList.remove('export');
|
||||
importSettingsPanel.classList.remove('import');
|
||||
});
|
||||
}
|
||||
|
||||
function importContactsHandler() {
|
||||
// Hide elements for export and transition
|
||||
LazyLoader.load(['/contacts/js/utilities/telemetry.js'], () => {
|
||||
importSettingsPanel.classList.remove('export');
|
||||
importSettingsPanel.classList.add('import');
|
||||
updateImportTitle('importContactsTitle');
|
||||
navigationHandler.go('import-settings', 'right-left');
|
||||
});
|
||||
}
|
||||
|
||||
function exportContactsHandler() {
|
||||
// Hide elements for import and transition
|
||||
LazyLoader.load(['/contacts/js/export/contacts_exporter.js'], loadSearch);
|
||||
|
||||
function loadSearch() {
|
||||
Loader.view('search', function() {
|
||||
importSettingsPanel.classList.remove('import');
|
||||
importSettingsPanel.classList.add('export');
|
||||
updateImportTitle('exportContactsTitle');
|
||||
navigationHandler.go('import-settings', 'right-left');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showICEScreen(cb) {
|
||||
LazyLoader.load([
|
||||
'/contacts/js/utilities/ice_data.js',
|
||||
'/contacts/js/views/ice_settings.js',
|
||||
'/shared/js/contacts/utilities/ice_store.js'], function(){
|
||||
ICE.refresh();
|
||||
navigationHandler.go('ice-settings', 'right-left');
|
||||
if (typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Given an event, select wich should be the targeted
|
||||
// import/export source
|
||||
function getSource(e) {
|
||||
var source = e.target.parentNode.dataset.source;
|
||||
// Check special cases
|
||||
if (source && source.indexOf('-') != -1) {
|
||||
source = source.substr(0, source.indexOf('-'));
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
function logImportUsage(name) {
|
||||
return Telemetry.logImportUsage(name);
|
||||
}
|
||||
|
||||
function importOptionsHandler(e) {
|
||||
/* jshint validthis:true */
|
||||
|
||||
var source = getSource(e);
|
||||
switch (source) {
|
||||
case 'sim':
|
||||
var iccId = e.target.parentNode.dataset.iccid;
|
||||
window.setTimeout(requireSimImport.bind(this,
|
||||
onSimImport.bind(this, iccId)), 0);
|
||||
break;
|
||||
case 'sd':
|
||||
window.setTimeout(requireOverlay.bind(this, onSdImport), 0);
|
||||
break;
|
||||
case 'gmail':
|
||||
ExtServices.onContactsImported = logImportUsage.bind(null, 'gmail');
|
||||
ExtServices.importGmail();
|
||||
break;
|
||||
case 'live':
|
||||
ExtServices.onContactsImported = logImportUsage.bind(null, 'live');
|
||||
ExtServices.importLive();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var bulkDeleteHandler = function bulkDeleteHandler() {
|
||||
LazyLoader.load(
|
||||
[
|
||||
'/contacts/js/contacts_bulk_delete.js',
|
||||
'/contacts/js/contacts_remover.js'
|
||||
],
|
||||
function() {
|
||||
Loader.view('search', function() {
|
||||
contacts.List.selectFromList(_('DeleteTitle'),
|
||||
function onSelectedContacts(promise, done) {
|
||||
BulkDelete.performDelete(promise, done);
|
||||
},
|
||||
null,
|
||||
navigationHandler,
|
||||
{
|
||||
transitionLevel: DELETE_TRANSITION_LEVEL
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
function exportOptionsHandler(e) {
|
||||
var source = getSource(e);
|
||||
switch (source) {
|
||||
case 'sim':
|
||||
var iccId = e.target.parentNode.dataset.iccid;
|
||||
LazyLoader.load(['/contacts/js/export/sim.js'],
|
||||
function() {
|
||||
doExport(new ContactsSIMExport(IccHandler.getIccById(iccId)));
|
||||
}
|
||||
);
|
||||
break;
|
||||
case 'sd':
|
||||
LazyLoader.load(
|
||||
[
|
||||
'/shared/js/device_storage/get_storage_if_available.js',
|
||||
'/shared/js/device_storage/get_unused_filename.js',
|
||||
'/shared/js/contact2vcard.js',
|
||||
'/shared/js/setImmediate.js',
|
||||
'/contacts/js/export/sd.js'
|
||||
],
|
||||
function() {
|
||||
doExport(new ContactsSDExport());
|
||||
}
|
||||
);
|
||||
break;
|
||||
case 'bluetooth':
|
||||
LazyLoader.load(
|
||||
[
|
||||
'/shared/js/device_storage/get_storage_if_available.js',
|
||||
'/shared/js/device_storage/get_unused_filename.js',
|
||||
'/shared/js/contact2vcard.js',
|
||||
'/shared/js/setImmediate.js',
|
||||
'/contacts/js/export/bt.js'
|
||||
],
|
||||
function() {
|
||||
doExport(new ContactsBTExport());
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function doExport(strategy) {
|
||||
// Launch the selection mode in the list, and then invoke
|
||||
// the export with the selected strategy.
|
||||
|
||||
contacts.List.selectFromList(_('exportContactsAction'),
|
||||
function onSelectedContacts(promise) {
|
||||
// Resolve the promise, meanwhile show an overlay to
|
||||
// warn the user of the ongoin operation, dismiss it
|
||||
// once we have the result
|
||||
requireOverlay(function _loaded() {
|
||||
utils.overlay.show('preparing-contacts', null, 'spinner');
|
||||
promise.onsuccess = function onSuccess(ids) {
|
||||
// Once we start the export process we can exit from select mode
|
||||
// This will have to evolve once export errors can be captured
|
||||
contacts.List.exitSelectMode();
|
||||
var exporter = new ContactsExporter(strategy);
|
||||
exporter.init(ids, function onExporterReady() {
|
||||
// Leave the contact exporter to deal with the overlay
|
||||
exporter.start();
|
||||
});
|
||||
};
|
||||
promise.onerror = function onError() {
|
||||
contacts.List.exitSelectMode();
|
||||
utils.overlay.hide();
|
||||
};
|
||||
});
|
||||
},
|
||||
null,
|
||||
navigationHandler,
|
||||
{
|
||||
isDanger: false,
|
||||
transitionLevel: EXPORT_TRANSITION_LEVEL
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Options checking & updating
|
||||
|
||||
var checkSIMCard = function checkSIMCard() {
|
||||
var statuses = IccHandler.getStatus();
|
||||
statuses.forEach(function onStatus(status) {
|
||||
enableSIMOptions(status.iccId, status.cardState);
|
||||
});
|
||||
};
|
||||
|
||||
// Disables/Enables an option and show the error if needed
|
||||
var updateOptionStatus =
|
||||
function updateOptionStatus(domOption, disabled, error) {
|
||||
if (domOption === null) {
|
||||
return;
|
||||
}
|
||||
var optionButton = domOption.firstElementChild;
|
||||
if (disabled) {
|
||||
optionButton.setAttribute('disabled', 'disabled');
|
||||
if (error) {
|
||||
domOption.classList.add('error');
|
||||
} else {
|
||||
domOption.classList.remove('error');
|
||||
}
|
||||
} else {
|
||||
optionButton.removeAttribute('disabled');
|
||||
domOption.classList.remove('error');
|
||||
}
|
||||
};
|
||||
|
||||
// Disables/Enables the actions over the sim import functionality
|
||||
var enableSIMOptions = function enableSIMOptions(iccId, cardState) {
|
||||
var importSimOption = document.getElementById('import-sim-option-' + iccId);
|
||||
var exportSimOption = document.getElementById('export-sim-option-' + iccId);
|
||||
var disabled = (cardState !== 'ready' && cardState !== 'illegal');
|
||||
updateOptionStatus(importSimOption, disabled, true);
|
||||
updateOptionStatus(exportSimOption, disabled, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Disables/Enables the actions over the sdcard import/export functionality
|
||||
* @param {Boolean} cardAvailable Whether functions should be enabled or not.
|
||||
*/
|
||||
var updateStorageOptions = function updateStorageOptions(cardAvailable) {
|
||||
// Enable/Disable button and shows/hides error message
|
||||
updateOptionStatus(importSDOption, !cardAvailable, true);
|
||||
updateOptionStatus(exportSDOption, !cardAvailable, true);
|
||||
|
||||
var importSDErrorL10nId = null;
|
||||
var exportSDErrorL10nId = null;
|
||||
|
||||
var cardShared = utils.sdcard.status === utils.sdcard.SHARED;
|
||||
if (!cardAvailable) {
|
||||
importSDErrorL10nId = 'noMemoryCardMsg';
|
||||
exportSDErrorL10nId = 'noMemoryCardMsgExport';
|
||||
|
||||
if (cardShared) {
|
||||
importSDErrorL10nId = exportSDErrorL10nId = 'memoryCardUMSEnabled';
|
||||
}
|
||||
}
|
||||
|
||||
// update the message
|
||||
var importSDErrorNode = importSDOption.querySelector('p.error-message');
|
||||
if (importSDErrorL10nId) {
|
||||
importSDErrorNode.setAttribute('data-l10n-id', importSDErrorL10nId);
|
||||
} else {
|
||||
importSDErrorNode.removeAttribute('data-l10n-id');
|
||||
importSDErrorNode.textContent = '';
|
||||
}
|
||||
|
||||
var exportSDErrorNode = exportSDOption.querySelector('p');
|
||||
if (exportSDErrorL10nId) {
|
||||
exportSDErrorNode.setAttribute('data-l10n-id', exportSDErrorL10nId);
|
||||
} else {
|
||||
exportSDErrorNode.removeAttribute('data-l10n-id');
|
||||
exportSDErrorNode.textContent = '';
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads the overlay class before showing
|
||||
*/
|
||||
function requireOverlay(callback) {
|
||||
Loader.utility('Overlay', callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads required libraries for sim import
|
||||
*/
|
||||
function requireSimImport(callback) {
|
||||
var libraries = ['Overlay', 'Import_sim_contacts'];
|
||||
var pending = libraries.length;
|
||||
|
||||
libraries.forEach(function onPending(library) {
|
||||
Loader.utility(library, next);
|
||||
});
|
||||
|
||||
function next() {
|
||||
if (!(--pending)) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetWait(wakeLock) {
|
||||
Contacts.hideOverlay();
|
||||
if (wakeLock) {
|
||||
wakeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// Listens for any change in the ordering preferences
|
||||
var onOrderingChange = function onOrderingChange(evt) {
|
||||
newOrderByLastName = orderCheckBox.checked;
|
||||
updateOrderingUI();
|
||||
};
|
||||
|
||||
// Import contacts from SIM card and updates ui
|
||||
var onSimImport = function onSimImport(iccId, done) {
|
||||
var icc = IccHandler.getIccById(iccId);
|
||||
if (icc === null) {
|
||||
return;
|
||||
}
|
||||
var progress = Contacts.showOverlay('simContacts-reading',
|
||||
'activityBar');
|
||||
|
||||
var wakeLock = navigator.requestWakeLock('cpu');
|
||||
|
||||
var cancelled = false, contactsRead = false;
|
||||
var importer = new SimContactsImporter(icc);
|
||||
utils.overlay.showMenu();
|
||||
utils.overlay.oncancel = function oncancel() {
|
||||
cancelled = true;
|
||||
importer.finish();
|
||||
if (contactsRead) {
|
||||
// A message about canceling will be displayed while the current chunk
|
||||
// is being cooked
|
||||
progress.setClass('activityBar');
|
||||
utils.overlay.hideMenu();
|
||||
progress.setHeaderMsg('messageCanceling');
|
||||
} else {
|
||||
importer.onfinish(); // Early return while reading contacts
|
||||
}
|
||||
};
|
||||
var totalContactsToImport;
|
||||
var importedContacts = 0;
|
||||
// Delay for showing feedback to the user after importing
|
||||
var DELAY_FEEDBACK = 200;
|
||||
|
||||
importer.onread = function import_read(n) {
|
||||
contactsRead = true;
|
||||
totalContactsToImport = n;
|
||||
if (totalContactsToImport > 0) {
|
||||
progress.setClass('progressBar');
|
||||
progress.setHeaderMsg('simContacts-importing');
|
||||
progress.setTotal(totalContactsToImport);
|
||||
}
|
||||
};
|
||||
|
||||
importer.onfinish = function import_finish(numDupsMerged) {
|
||||
window.setTimeout(function onfinish_import() {
|
||||
resetWait(wakeLock);
|
||||
if (importedContacts > 0) {
|
||||
var source = 'sim-' + iccId;
|
||||
utils.misc.setTimestamp(source, function() {
|
||||
// Once the timestamp is saved, update the list
|
||||
updateTimestamps();
|
||||
checkNoContacts();
|
||||
});
|
||||
}
|
||||
if (!cancelled) {
|
||||
utils.status.show({
|
||||
id: 'simContacts-imported3',
|
||||
args: {
|
||||
n: importedContacts
|
||||
}
|
||||
},
|
||||
!numDupsMerged ? null : {
|
||||
id: 'contactsMerged',
|
||||
args: {
|
||||
numDups: numDupsMerged
|
||||
}
|
||||
});
|
||||
} else {
|
||||
logImportUsage('sim');
|
||||
}
|
||||
|
||||
typeof done === 'function' && done();
|
||||
|
||||
}, DELAY_FEEDBACK);
|
||||
|
||||
importer.onfinish = null;
|
||||
};
|
||||
|
||||
importer.onimported = function imported_contact() {
|
||||
importedContacts++;
|
||||
if (!cancelled) {
|
||||
progress.update();
|
||||
}
|
||||
};
|
||||
|
||||
importer.onerror = function import_error() {
|
||||
var cancel = {
|
||||
title: 'cancel',
|
||||
callback: function() {
|
||||
ConfirmDialog.hide();
|
||||
}
|
||||
};
|
||||
var retry = {
|
||||
title: 'retry',
|
||||
isRecommend: true,
|
||||
callback: function() {
|
||||
ConfirmDialog.hide();
|
||||
// And now the action is reproduced one more time
|
||||
window.setTimeout(requireSimImport.bind(this,
|
||||
onSimImport.bind(this, iccId)), 0);
|
||||
}
|
||||
};
|
||||
ConfirmDialog.show(null, 'simContacts-error', cancel, retry);
|
||||
resetWait(wakeLock);
|
||||
};
|
||||
|
||||
importer.start();
|
||||
};
|
||||
|
||||
var onSdImport = function onSdImport(cb) {
|
||||
var cancelled = false;
|
||||
var importer = null;
|
||||
var progress = Contacts.showOverlay(
|
||||
'memoryCardContacts-importing',
|
||||
'activityBar',
|
||||
'infiniteProgress'
|
||||
);
|
||||
utils.overlay.showMenu();
|
||||
utils.overlay.oncancel = function() {
|
||||
cancelled = true;
|
||||
importer ? importer.finish() : Contacts.hideOverlay();
|
||||
};
|
||||
var wakeLock = navigator.requestWakeLock('cpu');
|
||||
|
||||
var importedContacts = 0;
|
||||
// Delay for showing feedback to the user after importing
|
||||
var DELAY_FEEDBACK = 200;
|
||||
|
||||
utils.sdcard.retrieveFiles([
|
||||
'text/vcard',
|
||||
'text/x-vcard',
|
||||
'text/directory;profile=vCard',
|
||||
'text/directory'
|
||||
], ['vcf', 'vcard'], function(err, fileArray) {
|
||||
if (err) {
|
||||
return import_error(err, cb);
|
||||
}
|
||||
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileArray.length) {
|
||||
var promises = [];
|
||||
fileArray.forEach(file => {
|
||||
promises.push(utils.sdcard.getTextFromFile(file, onContacts));
|
||||
});
|
||||
Promise.all(promises).then(results => {
|
||||
var numDupsMerged = results.reduce((sum, current) => {
|
||||
return sum + current;
|
||||
});
|
||||
window.setTimeout(() => {
|
||||
utils.misc.setTimestamp('sd', () => {
|
||||
// Once the timestamp is saved, update the list
|
||||
updateTimestamps();
|
||||
checkNoContacts();
|
||||
resetWait(wakeLock);
|
||||
|
||||
if (!cancelled) {
|
||||
var msg1 = {
|
||||
id: 'memoryCardContacts-imported3',
|
||||
args: {
|
||||
n: importedContacts
|
||||
}
|
||||
};
|
||||
var msg2 = !numDupsMerged ? null : {
|
||||
id: 'contactsMerged',
|
||||
args: {
|
||||
numDups: numDupsMerged
|
||||
}
|
||||
};
|
||||
|
||||
utils.status.show(msg1, msg2);
|
||||
|
||||
logImportUsage('sd');
|
||||
|
||||
if (typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
});
|
||||
}, DELAY_FEEDBACK);
|
||||
}).catch(error => {
|
||||
import_error(error);
|
||||
});
|
||||
} else {
|
||||
import_error('No contacts were found.', cb);
|
||||
}
|
||||
});
|
||||
|
||||
function onContacts(text) {
|
||||
if (cancelled) {
|
||||
return Promise.reject();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
importer = new VCFReader(text);
|
||||
if (!text || !importer) {
|
||||
var error = 'No contacts were found';
|
||||
import_error(error);
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
importer.onimported = imported_contact;
|
||||
importer.onerror = error => {
|
||||
import_error(error);
|
||||
reject(error);
|
||||
};
|
||||
|
||||
importer.process((unused, numDupsMerged) => {
|
||||
if (cancelled) {
|
||||
reject('Cancelled');
|
||||
Contacts.hideOverlay();
|
||||
return;
|
||||
}
|
||||
resolve(numDupsMerged);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function imported_contact() {
|
||||
importedContacts++;
|
||||
progress.update();
|
||||
}
|
||||
|
||||
function import_error(e, cb) {
|
||||
var cancel = {
|
||||
title: 'cancel',
|
||||
callback: function() {
|
||||
ConfirmDialog.hide();
|
||||
}
|
||||
};
|
||||
|
||||
var retry = {
|
||||
title: 'retry',
|
||||
isRecommend: true,
|
||||
callback: function() {
|
||||
ConfirmDialog.hide();
|
||||
// And now the action is reproduced one more time
|
||||
window.setTimeout(requireOverlay.bind(this, onSdImport), 0);
|
||||
}
|
||||
};
|
||||
ConfirmDialog.show(null, 'memoryCardContacts-error', cancel,
|
||||
retry);
|
||||
resetWait(wakeLock);
|
||||
if (typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Dismiss settings window and execute operations if values got modified
|
||||
var close = function close() {
|
||||
if (newOrderByLastName != null &&
|
||||
newOrderByLastName != orderByLastName && contacts.List) {
|
||||
contacts.List.setOrderByLastName(newOrderByLastName);
|
||||
utils.cookie.update({order: newOrderByLastName});
|
||||
Cache.evict();
|
||||
// Force the reset of the dom, we know that we changed the order
|
||||
contacts.List.load(null, true);
|
||||
orderByLastName = newOrderByLastName;
|
||||
}
|
||||
|
||||
Contacts.goBack();
|
||||
};
|
||||
|
||||
var checkOnline = function() {
|
||||
// Perform pending automatic logouts
|
||||
window.setTimeout(automaticLogout, 0);
|
||||
|
||||
// Other import services settings
|
||||
updateOptionStatus(importGmailOption, !navigator.onLine, true);
|
||||
updateOptionStatus(importLiveOption, !navigator.onLine, true);
|
||||
};
|
||||
|
||||
var checkNoContacts = function checkNoContacts() {
|
||||
var exportButton = exportContacts.firstElementChild;
|
||||
|
||||
ContactsService.isEmpty(function(error, isEmpty) {
|
||||
if (error) {
|
||||
window.console.warn(
|
||||
'Error while trying to know the contact number',
|
||||
error
|
||||
);
|
||||
// In case of error is safer to leave enabled
|
||||
exportButton.removeAttribute('disabled');
|
||||
bulkDeleteButton.removeAttribute('disabled');
|
||||
return;
|
||||
}
|
||||
if (isEmpty) {
|
||||
exportButton.setAttribute('disabled', 'disabled');
|
||||
bulkDeleteButton.setAttribute('disabled', 'disabled');
|
||||
setICEButton.setAttribute('disabled', 'disabled');
|
||||
} else {
|
||||
exportButton.removeAttribute('disabled');
|
||||
bulkDeleteButton.removeAttribute('disabled');
|
||||
setICEButton.removeAttribute('disabled');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function saveStatus(data) {
|
||||
window.asyncStorage.setItem(PENDING_LOGOUT_KEY, data);
|
||||
}
|
||||
|
||||
function automaticLogout() {
|
||||
if (navigator.offLine === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
LazyLoader.load(['/shared/js/contacts/utilities/http_rest.js'],
|
||||
function() {
|
||||
window.asyncStorage.getItem(PENDING_LOGOUT_KEY, function(data) {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
var services = Object.keys(data);
|
||||
var numResponses = 0;
|
||||
|
||||
services.forEach(function(service) {
|
||||
var url = data[service];
|
||||
|
||||
var callbacks = {
|
||||
success: function logout_success() {
|
||||
numResponses++;
|
||||
window.console.log('Successfully logged out: ', service);
|
||||
delete data[service];
|
||||
if (numResponses === services.length) {
|
||||
saveStatus(data);
|
||||
}
|
||||
},
|
||||
error: function logout_error() {
|
||||
numResponses++;
|
||||
if (numResponses === services.length) {
|
||||
saveStatus(data);
|
||||
}
|
||||
},
|
||||
timeout: function logout_timeout() {
|
||||
numResponses++;
|
||||
if (numResponses === services.length) {
|
||||
saveStatus(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
Rest.get(url, callbacks);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var updateTimestamps = function updateTimestamps() {
|
||||
// TODO Add the same functionality to 'EXPORT' methods when ready.
|
||||
var importSources =
|
||||
document.querySelectorAll('#import-options li[data-source]');
|
||||
Array.prototype.forEach.call(importSources, function(node) {
|
||||
utils.misc.getTimestamp(node.dataset.source,
|
||||
function(time) {
|
||||
var spanID = 'notImported';
|
||||
if (time) {
|
||||
spanID = 'imported';
|
||||
var timeElement = node.querySelector('p > time');
|
||||
timeElement.setAttribute('datetime',
|
||||
(new Date(time)).toLocaleString());
|
||||
timeElement.textContent = utils.time.pretty(time);
|
||||
}
|
||||
node.querySelector('p > span').setAttribute('data-l10n-id', spanID);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var refresh = function refresh() {
|
||||
getData();
|
||||
checkOnline();
|
||||
checkSIMCard();
|
||||
utils.sdcard.getStatus(function statusUpdated() {
|
||||
updateStorageOptions(utils.sdcard.checkStorageCard());
|
||||
});
|
||||
updateTimestamps();
|
||||
checkNoContacts();
|
||||
};
|
||||
|
||||
return {
|
||||
'init': init,
|
||||
'close': close,
|
||||
'refresh': refresh,
|
||||
'cardStateChanged': checkSIMCard,
|
||||
'updateTimestamps': updateTimestamps,
|
||||
'showICEScreen' : showICEScreen,
|
||||
get navigation() { return navigationHandler; },
|
||||
'importFromSDCard': onSdImport,
|
||||
'importFromSIMCard': onSimImport
|
||||
};
|
||||
})();
|
||||
Loading…
Reference in a new issue