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