Mon 21 Jul 22:43:21 CEST 2025
This commit is contained in:
parent
85b399034d
commit
5ad001ce62
464
js/ui/cordova/plugins/cordova-plugin-contacts/src/firefoxos/ContactsProxy.js
vendored
Normal file
464
js/ui/cordova/plugins/cordova-plugin-contacts/src/firefoxos/ContactsProxy.js
vendored
Normal file
|
@ -0,0 +1,464 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Cordova contact definition:
|
||||||
|
// http://cordova.apache.org/docs/en/2.5.0/cordova_contacts_contacts.md.html#Contact
|
||||||
|
// FxOS contact definition:
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/mozContact
|
||||||
|
|
||||||
|
|
||||||
|
var Contact = require('./Contact');
|
||||||
|
var ContactField = require('./ContactField');
|
||||||
|
var ContactAddress = require('./ContactAddress');
|
||||||
|
var ContactName = require('./ContactName');
|
||||||
|
|
||||||
|
// XXX: a hack to check if id is "empty". Cordova inserts a
|
||||||
|
// string "this string is supposed to be a unique identifier that will
|
||||||
|
// never show up on a device" if id is empty
|
||||||
|
function _hasId(id) {
|
||||||
|
if (!id || id.indexOf(' ') >= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend mozContact prototype to provide update from Cordova
|
||||||
|
function updateFromCordova(contact, fromContact) {
|
||||||
|
|
||||||
|
function exportContactFieldArray(contactFieldArray, key) {
|
||||||
|
if (!key) {
|
||||||
|
key = 'value';
|
||||||
|
}
|
||||||
|
var arr = [];
|
||||||
|
for (var i=0; i < contactFieldArray.length; i++) {
|
||||||
|
arr.push(contactFieldArray[i][key]);
|
||||||
|
};
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportAddress(addresses) {
|
||||||
|
// TODO: check moz address format
|
||||||
|
var arr = [];
|
||||||
|
|
||||||
|
for (var i=0; i < addresses.length; i++) {
|
||||||
|
var addr = {};
|
||||||
|
for (var key in addresses[i]) {
|
||||||
|
if (key == 'formatted' || key == 'id') {
|
||||||
|
continue;
|
||||||
|
} else if (key == 'type') {
|
||||||
|
addr[key] = [addresses[i][key]];
|
||||||
|
} else if (key == 'country') {
|
||||||
|
addr['countryName'] = addresses[i][key];
|
||||||
|
} else {
|
||||||
|
addr[key] = addresses[i][key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr.push(addr);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportContactField(data) {
|
||||||
|
var contactFields = [];
|
||||||
|
for (var i=0; i < data.length; i++) {
|
||||||
|
var item = data[i];
|
||||||
|
if (item.value) {
|
||||||
|
var itemData = {value: item.value};
|
||||||
|
if (item.type) {
|
||||||
|
itemData.type = [item.type];
|
||||||
|
}
|
||||||
|
if (item.pref) {
|
||||||
|
itemData.pref = item.pref;
|
||||||
|
}
|
||||||
|
contactFields.push(itemData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return contactFields;
|
||||||
|
}
|
||||||
|
// adding simple fields [contactField, eventualMozContactField]
|
||||||
|
var nameFields = [['givenName'], ['familyName'],
|
||||||
|
['honorificPrefix'], ['honorificSuffix'],
|
||||||
|
['middleName', 'additionalName']];
|
||||||
|
var baseArrayFields = [['displayName', 'name'], ['nickname']];
|
||||||
|
var baseStringFields = [];
|
||||||
|
var j = 0; while(field = nameFields[j++]) {
|
||||||
|
if (fromContact.name[field[0]]) {
|
||||||
|
contact[field[1] || field[0]] = fromContact.name[field[0]].split(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j = 0; while(field = baseArrayFields[j++]) {
|
||||||
|
if (fromContact[field[0]]) {
|
||||||
|
contact[field[1] || field[0]] = fromContact[field[0]].split(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j = 0; while(field = baseStringFields[j++]) {
|
||||||
|
if (fromContact[field[0]]) {
|
||||||
|
contact[field[1] || field[0]] = fromContact[field[0]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fromContact.birthday) {
|
||||||
|
contact.bday = new Date(fromContact.birthday);
|
||||||
|
}
|
||||||
|
if (fromContact.emails) {
|
||||||
|
var emails = exportContactField(fromContact.emails)
|
||||||
|
contact.email = emails;
|
||||||
|
}
|
||||||
|
if (fromContact.categories) {
|
||||||
|
contact.category = exportContactFieldArray(fromContact.categories);
|
||||||
|
}
|
||||||
|
if (fromContact.addresses) {
|
||||||
|
contact.adr = exportAddress(fromContact.addresses);
|
||||||
|
}
|
||||||
|
if (fromContact.phoneNumbers) {
|
||||||
|
contact.tel = exportContactField(fromContact.phoneNumbers);
|
||||||
|
}
|
||||||
|
if (fromContact.organizations) {
|
||||||
|
// XXX: organizations are saved in 2 arrays - org and jobTitle
|
||||||
|
// depending on the usecase it might generate issues
|
||||||
|
// where wrong title will be added to an organization
|
||||||
|
contact.org = exportContactFieldArray(fromContact.organizations, 'name');
|
||||||
|
contact.jobTitle = exportContactFieldArray(fromContact.organizations, 'title');
|
||||||
|
}
|
||||||
|
if (fromContact.note) {
|
||||||
|
contact.note = [fromContact.note];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Extend Cordova Contact prototype to provide update from FFOS contact
|
||||||
|
Contact.prototype.updateFromMozilla = function(moz) {
|
||||||
|
function exportContactField(data) {
|
||||||
|
var contactFields = [];
|
||||||
|
for (var i=0; i < data.length; i++) {
|
||||||
|
var item = data[i];
|
||||||
|
var itemData = new ContactField(item.type, item.value, item.pref);
|
||||||
|
contactFields.push(itemData);
|
||||||
|
}
|
||||||
|
return contactFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeContactFieldFromArray(data) {
|
||||||
|
var contactFields = [];
|
||||||
|
for (var i=0; i < data.length; i++) {
|
||||||
|
var itemData = new ContactField(null, data[i]);
|
||||||
|
contactFields.push(itemData);
|
||||||
|
}
|
||||||
|
return contactFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportAddresses(addresses) {
|
||||||
|
// TODO: check moz address format
|
||||||
|
var arr = [];
|
||||||
|
|
||||||
|
for (var i=0; i < addresses.length; i++) {
|
||||||
|
var addr = {};
|
||||||
|
for (var key in addresses[i]) {
|
||||||
|
if (key == 'countryName') {
|
||||||
|
addr['country'] = addresses[i][key];
|
||||||
|
} else if (key == 'type') {
|
||||||
|
addr[key] = addresses[i][key].join(' ');
|
||||||
|
} else {
|
||||||
|
addr[key] = addresses[i][key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr.push(addr);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOrganizations(orgs, jobs) {
|
||||||
|
orgs = (orgs) ? orgs : [];
|
||||||
|
jobs = (jobs) ? jobs : [];
|
||||||
|
var max_length = Math.max(orgs.length, jobs.length);
|
||||||
|
var organizations = [];
|
||||||
|
for (var i=0; i < max_length; i++) {
|
||||||
|
organizations.push(new ContactOrganization(
|
||||||
|
null, null, orgs[i] || null, null, jobs[i] || null));
|
||||||
|
}
|
||||||
|
return organizations;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFormatted(name) {
|
||||||
|
var fields = ['honorificPrefix', 'givenName', 'middleName',
|
||||||
|
'familyName', 'honorificSuffix'];
|
||||||
|
var f = '';
|
||||||
|
for (var i = 0; i < fields.length; i++) {
|
||||||
|
if (name[fields[i]]) {
|
||||||
|
if (f) {
|
||||||
|
f += ' ';
|
||||||
|
}
|
||||||
|
f += name[fields[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (moz.id) {
|
||||||
|
this.id = moz.id;
|
||||||
|
}
|
||||||
|
var nameFields = [['givenName'], ['familyName'],
|
||||||
|
['honorificPrefix'], ['honorificSuffix'],
|
||||||
|
['additionalName', 'middleName']];
|
||||||
|
var baseArrayFields = [['name', 'displayName'], 'nickname', ['note']];
|
||||||
|
var baseStringFields = [];
|
||||||
|
var name = new ContactName();
|
||||||
|
var j = 0; while(field = nameFields[j++]) {
|
||||||
|
if (moz[field[0]]) {
|
||||||
|
name[field[1] || field[0]] = moz[field[0]].join(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.name = name;
|
||||||
|
j = 0; while(field = baseArrayFields[j++]) {
|
||||||
|
if (moz[field[0]]) {
|
||||||
|
this[field[1] || field[0]] = moz[field[0]].join(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j = 0; while(field = baseStringFields[j++]) {
|
||||||
|
if (moz[field[0]]) {
|
||||||
|
this[field[1] || field[0]] = moz[field[0]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// emails
|
||||||
|
if (moz.email) {
|
||||||
|
this.emails = exportContactField(moz.email);
|
||||||
|
}
|
||||||
|
// categories
|
||||||
|
if (moz.category) {
|
||||||
|
this.categories = makeContactFieldFromArray(moz.category);
|
||||||
|
}
|
||||||
|
|
||||||
|
// addresses
|
||||||
|
if (moz.adr) {
|
||||||
|
this.addresses = exportAddresses(moz.adr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// phoneNumbers
|
||||||
|
if (moz.tel) {
|
||||||
|
this.phoneNumbers = exportContactField(moz.tel);
|
||||||
|
}
|
||||||
|
// birthday
|
||||||
|
if (moz.bday) {
|
||||||
|
this.birthday = Date.parse(moz.bday);
|
||||||
|
}
|
||||||
|
// organizations
|
||||||
|
if (moz.org || moz.jobTitle) {
|
||||||
|
// XXX: organizations array is created from org and jobTitle
|
||||||
|
this.organizations = createOrganizations(moz.org, moz.jobTitle);
|
||||||
|
}
|
||||||
|
// construct a read-only formatted value
|
||||||
|
this.name.formatted = createFormatted(this.name);
|
||||||
|
|
||||||
|
/* Find out how to translate these parameters
|
||||||
|
// photo: Blob
|
||||||
|
// url: Array with metadata (?)
|
||||||
|
// impp: exportIM(contact.ims), TODO: find the moz impp definition
|
||||||
|
// anniversary
|
||||||
|
// sex
|
||||||
|
// genderIdentity
|
||||||
|
// key
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createMozillaFromCordova(successCB, errorCB, contact) {
|
||||||
|
var moz;
|
||||||
|
// get contact if exists
|
||||||
|
if (_hasId(contact.id)) {
|
||||||
|
var search = navigator.mozContacts.find({
|
||||||
|
filterBy: ['id'], filterValue: contact.id, filterOp: 'equals'});
|
||||||
|
search.onsuccess = function() {
|
||||||
|
moz = search.result[0];
|
||||||
|
updateFromCordova(moz, contact);
|
||||||
|
successCB(moz);
|
||||||
|
};
|
||||||
|
search.onerror = errorCB;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create empty contact
|
||||||
|
moz = new mozContact();
|
||||||
|
// if ('init' in moz) {
|
||||||
|
// 1.2 and below compatibility
|
||||||
|
// moz.init();
|
||||||
|
// }
|
||||||
|
updateFromCordova(moz, contact);
|
||||||
|
successCB(moz);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createCordovaFromMozilla(moz) {
|
||||||
|
var contact = new Contact();
|
||||||
|
contact.updateFromMozilla(moz);
|
||||||
|
return contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// However API requires the ability to save multiple contacts, it is
|
||||||
|
// used to save only one element array
|
||||||
|
function saveContacts(successCB, errorCB, contacts) {
|
||||||
|
// a closure which is holding the right moz contact
|
||||||
|
function makeSaveSuccessCB(moz) {
|
||||||
|
return function(result) {
|
||||||
|
// create contact from FXOS contact (might be different than
|
||||||
|
// the original one due to differences in API)
|
||||||
|
var contact = createCordovaFromMozilla(moz);
|
||||||
|
// call callback
|
||||||
|
successCB(contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var i=0;
|
||||||
|
var contact;
|
||||||
|
while(contact = contacts[i++]){
|
||||||
|
var moz = createMozillaFromCordova(function(moz) {
|
||||||
|
var request = navigator.mozContacts.save(moz);
|
||||||
|
// success and/or fail will be called every time a contact is saved
|
||||||
|
request.onsuccess = makeSaveSuccessCB(moz);
|
||||||
|
request.onerror = errorCB;
|
||||||
|
}, function() {}, contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// API provides a list of ids to be removed
|
||||||
|
function remove(successCB, errorCB, ids) {
|
||||||
|
var i=0;
|
||||||
|
var id;
|
||||||
|
for (var i=0; i < ids.length; i++){
|
||||||
|
// throw an error if no id provided
|
||||||
|
if (!_hasId(ids[i])) {
|
||||||
|
console.error('FFOS: Attempt to remove unsaved contact');
|
||||||
|
errorCB(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// check if provided id actually exists
|
||||||
|
var search = navigator.mozContacts.find({
|
||||||
|
filterBy: ['id'], filterValue: ids[i], filterOp: 'equals'});
|
||||||
|
search.onsuccess = function() {
|
||||||
|
if (search.result.length === 0) {
|
||||||
|
console.error('FFOS: Attempt to remove a non existing contact');
|
||||||
|
errorCB(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var moz = search.result[0];
|
||||||
|
var request = navigator.mozContacts.remove(moz);
|
||||||
|
request.onsuccess = successCB;
|
||||||
|
request.onerror = errorCB;
|
||||||
|
};
|
||||||
|
search.onerror = errorCB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var mozContactSearchFields = [['name', 'displayName'], ['givenName'],
|
||||||
|
['familyName'], ['email'], ['tel'], ['jobTitle'], ['note'],
|
||||||
|
['tel', 'phoneNumbers'], ['email', 'emails']];
|
||||||
|
// Searching by nickname and additionalName is forbidden in 1.3 and below
|
||||||
|
// Searching by name is forbidden in 1.2 and below
|
||||||
|
|
||||||
|
// finds if a key is allowed and returns FFOS name if different
|
||||||
|
function getMozSearchField(key) {
|
||||||
|
if (mozContactSearchFields.indexOf([key]) >= 0) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
for (var i=0; i < mozContactSearchFields.length; i++) {
|
||||||
|
if (mozContactSearchFields[i].length > 1) {
|
||||||
|
if (mozContactSearchFields[i][1] === key) {
|
||||||
|
return mozContactSearchFields[i][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _getAll(successCB, errorCB, params) {
|
||||||
|
// [contactField, eventualMozContactField]
|
||||||
|
var getall = navigator.mozContacts.getAll({});
|
||||||
|
var contacts = [];
|
||||||
|
|
||||||
|
getall.onsuccess = function() {
|
||||||
|
if (getall.result) {
|
||||||
|
contacts.push(createCordovaFromMozilla(getall.result));
|
||||||
|
getall.continue();
|
||||||
|
} else {
|
||||||
|
successCB(contacts);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
getall.onerror = errorCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function search(successCB, errorCB, params) {
|
||||||
|
var options = params[1] || {};
|
||||||
|
if (!options.filter) {
|
||||||
|
return _getAll(successCB, errorCB, params);
|
||||||
|
}
|
||||||
|
var filterBy = [];
|
||||||
|
// filter and translate fields
|
||||||
|
for (var i=0; i < params[0].length; i++) {
|
||||||
|
var searchField = params[0][i];
|
||||||
|
var mozField = getMozSearchField(searchField);
|
||||||
|
if (searchField === 'name') {
|
||||||
|
// Cordova uses name for search by all name fields.
|
||||||
|
filterBy.push('givenName');
|
||||||
|
filterBy.push('familyName');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (searchField === 'displayName' && 'init' in new mozContact()) {
|
||||||
|
// ``init`` in ``mozContact`` indicates FFOS version 1.2 or below
|
||||||
|
// Searching by name (in moz) is then forbidden
|
||||||
|
console.log('FFOS ContactProxy: Unable to search by displayName on FFOS 1.2');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (mozField) {
|
||||||
|
filterBy.push(mozField);
|
||||||
|
} else {
|
||||||
|
console.log('FXOS ContactProxy: inallowed field passed to search filtered out: ' + searchField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var mozOptions = {filterBy: filterBy, filterOp: 'startsWith'};
|
||||||
|
if (!options.multiple) {
|
||||||
|
mozOptions.filterLimit = 1;
|
||||||
|
}
|
||||||
|
mozOptions.filterValue = options.filter;
|
||||||
|
var request = navigator.mozContacts.find(mozOptions);
|
||||||
|
request.onsuccess = function() {
|
||||||
|
var contacts = [];
|
||||||
|
var mozContacts = request.result;
|
||||||
|
var moz = mozContacts[0];
|
||||||
|
for (var i=0; i < mozContacts.length; i++) {
|
||||||
|
contacts.push(createCordovaFromMozilla(mozContacts[i]));
|
||||||
|
}
|
||||||
|
successCB(contacts);
|
||||||
|
};
|
||||||
|
request.onerror = errorCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
save: saveContacts,
|
||||||
|
remove: remove,
|
||||||
|
search: search
|
||||||
|
};
|
||||||
|
|
||||||
|
require("cordova/exec/proxy").add("Contacts", module.exports);
|
Loading…
Reference in New Issue
Block a user