blob: 09a4bd2a5e66fc7da2a92def77ed193b2b0f7c81 [file] [log] [blame]
/*
* Copyright 2013 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var pimContacts,
contactUtils = require("./contactUtils"),
contactConsts = require("./contactConsts"),
ContactError = require("./ContactError"),
ContactName = require("./ContactName"),
ContactFindOptions = require("./ContactFindOptions"),
noop = function () {};
function getAccountFilters(options) {
if (options.includeAccounts) {
options.includeAccounts = options.includeAccounts.map(function (acct) {
return acct.id.toString();
});
}
if (options.excludeAccounts) {
options.excludeAccounts = options.excludeAccounts.map(function (acct) {
return acct.id.toString();
});
}
}
function populateSearchFields(fields) {
var i,
l,
key,
searchFieldsObject = {},
searchFields = [];
for (i = 0, l = fields.length; i < l; i++) {
if (fields[i] === "*") {
searchFieldsObject[ContactFindOptions.SEARCH_FIELD_GIVEN_NAME] = true;
searchFieldsObject[ContactFindOptions.SEARCH_FIELD_FAMILY_NAME] = true;
searchFieldsObject[ContactFindOptions.SEARCH_FIELD_PHONE] = true;
searchFieldsObject[ContactFindOptions.SEARCH_FIELD_EMAIL] = true;
searchFieldsObject[ContactFindOptions.SEARCH_FIELD_ORGANIZATION_NAME] = true;
} else if (fields[i] === "displayName" || fields[i] === "name") {
searchFieldsObject[ContactFindOptions.SEARCH_FIELD_GIVEN_NAME] = true;
searchFieldsObject[ContactFindOptions.SEARCH_FIELD_FAMILY_NAME] = true;
} else if (fields[i] === "nickname") {
// not supported by Cascades
} else if (fields[i] === "phoneNumbers") {
searchFieldsObject[ContactFindOptions.SEARCH_FIELD_PHONE] = true;
} else if (fields[i] === "emails") {
searchFieldsObject[ContactFindOptions.SEARCH_FIELD_EMAIL] = true;
} else if (field === "addresses") {
// not supported by Cascades
} else if (field === "ims") {
// not supported by Cascades
} else if (field === "organizations") {
searchFieldsObject[ContactFindOptions.SEARCH_FIELD_ORGANIZATION_NAME] = true;
} else if (field === "birthday") {
// not supported by Cascades
} else if (field === "note") {
// not supported by Cascades
} else if (field === "photos") {
// not supported by Cascades
} else if (field === "categories") {
// not supported by Cascades
} else if (field === "urls") {
// not supported by Cascades
}
}
for (key in searchFieldsObject) {
if (searchFieldsObject.hasOwnProperty(key)) {
searchFields.push(window.parseInt(key));
}
}
return searchFields;
}
function convertBirthday(birthday) {
//Convert date string from native to milliseconds since epoch for cordova-js
var birthdayInfo;
if (birthday) {
birthdayInfo = birthday.split("-");
return new Date(birthdayInfo[0], birthdayInfo[1] - 1, birthdayInfo[2]).getTime();
} else {
return null;
}
}
function processJnextSaveData(result, JnextData) {
var data = JnextData,
birthdayInfo;
if (data._success === true) {
data.birthday = convertBirthday(data.birthday);
result.callbackOk(data, false);
} else {
result.callbackError(data.code, false);
}
}
function processJnextRemoveData(result, JnextData) {
var data = JnextData;
if (data._success === true) {
result.callbackOk(data);
} else {
result.callbackError(ContactError.UNKNOWN_ERROR, false);
}
}
function processJnextFindData(eventId, eventHandler, JnextData) {
var data = JnextData,
i,
l,
more = false,
resultsObject = {},
birthdayInfo;
if (data.contacts) {
for (i = 0, l = data.contacts.length; i < l; i++) {
data.contacts[i].birthday = convertBirthday(data.contacts[i].birthday);
data.contacts[i].name = new ContactName(data.contacts[i].name);
}
} else {
data.contacts = []; // if JnextData.contacts return null, return an empty array
}
if (data._success === true) {
eventHandler.error = false;
}
if (eventHandler.multiple) {
// Concatenate results; do not add the same contacts
for (i = 0, l = eventHandler.searchResult.length; i < l; i++) {
resultsObject[eventHandler.searchResult[i].id] = true;
}
for (i = 0, l = data.contacts.length; i < l; i++) {
if (resultsObject[data.contacts[i].id]) {
// Already existing
} else {
eventHandler.searchResult.push(data.contacts[i]);
}
}
// check if more search is required
eventHandler.searchFieldIndex++;
if (eventHandler.searchFieldIndex < eventHandler.searchFields.length) {
more = true;
}
} else {
eventHandler.searchResult = data.contacts;
}
if (more) {
pimContacts.getInstance().invokeJnextSearch(eventId);
} else {
if (eventHandler.error) {
eventHandler.result.callbackError(data.code, false);
} else {
eventHandler.result.callbackOk(eventHandler.searchResult, false);
}
}
}
module.exports = {
search: function (successCb, failCb, args, env) {
var cordovaFindOptions = {},
result = new PluginResult(args, env),
key;
for (key in args) {
if (args.hasOwnProperty(key)) {
cordovaFindOptions[key] = JSON.parse(decodeURIComponent(args[key]));
}
}
pimContacts.getInstance().find(cordovaFindOptions, result, processJnextFindData);
result.noResult(true);
},
save: function (successCb, failCb, args, env) {
var attributes = {},
result = new PluginResult(args, env),
key,
nativeEmails = [];
attributes = JSON.parse(decodeURIComponent(args[0]));
//convert birthday format for our native .so file
if (attributes.birthday) {
attributes.birthday = new Date(attributes.birthday).toDateString();
}
if (attributes.emails) {
attributes.emails.forEach(function (email) {
if (email.value) {
if (email.type) {
nativeEmails.push({ "type" : email.type, "value" : email.value });
} else {
nativeEmails.push({ "type" : "home", "value" : email.value });
}
}
});
attributes.emails = nativeEmails;
}
if (attributes.id !== null) {
attributes.id = window.parseInt(attributes.id);
}
attributes._eventId = result.callbackId;
pimContacts.getInstance().save(attributes, result, processJnextSaveData);
result.noResult(true);
},
remove: function (successCb, failCb, args, env) {
var result = new PluginResult(args, env),
attributes = {
"contactId": window.parseInt(JSON.parse(decodeURIComponent(args[0]))),
"_eventId": result.callbackId
};
if (!window.isNaN(attributes.contactId)) {
pimContacts.getInstance().remove(attributes, result, processJnextRemoveData);
result.noResult(true);
} else {
result.error(ContactError.UNKNOWN_ERROR);
result.noResult(false);
}
}
};
///////////////////////////////////////////////////////////////////
// JavaScript wrapper for JNEXT plugin
///////////////////////////////////////////////////////////////////
JNEXT.PimContacts = function ()
{
var self = this,
hasInstance = false;
self.find = function (cordovaFindOptions, pluginResult, handler) {
//register find eventHandler for when JNEXT onEvent fires
self.eventHandlers[cordovaFindOptions.callbackId] = {
"result" : pluginResult,
"action" : "find",
"multiple" : cordovaFindOptions[1].filter ? true : false,
"fields" : cordovaFindOptions[0],
"searchFilter" : cordovaFindOptions[1].filter,
"searchFields" : cordovaFindOptions[1].filter ? populateSearchFields(cordovaFindOptions[0]) : null,
"searchFieldIndex" : 0,
"searchResult" : [],
"handler" : handler,
"error" : true
};
self.invokeJnextSearch(cordovaFindOptions.callbackId);
return "";
};
self.invokeJnextSearch = function(eventId) {
var jnextArgs = {},
findHandler = self.eventHandlers[eventId];
jnextArgs._eventId = eventId;
jnextArgs.fields = findHandler.fields;
jnextArgs.options = {};
jnextArgs.options.filter = [];
if (findHandler.multiple) {
jnextArgs.options.filter.push({
"fieldName" : findHandler.searchFields[findHandler.searchFieldIndex],
"fieldValue" : findHandler.searchFilter
});
//findHandler.searchFieldIndex++;
}
JNEXT.invoke(self.m_id, "find " + JSON.stringify(jnextArgs));
}
self.getContact = function (args) {
return JSON.parse(JNEXT.invoke(self.m_id, "getContact " + JSON.stringify(args)));
};
self.save = function (args, pluginResult, handler) {
//register save eventHandler for when JNEXT onEvent fires
self.eventHandlers[args._eventId] = {
"result" : pluginResult,
"action" : "save",
"handler" : handler
};
JNEXT.invoke(self.m_id, "save " + JSON.stringify(args));
return "";
};
self.remove = function (args, pluginResult, handler) {
//register remove eventHandler for when JNEXT onEvent fires
self.eventHandlers[args._eventId] = {
"result" : pluginResult,
"action" : "remove",
"handler" : handler
};
JNEXT.invoke(self.m_id, "remove " + JSON.stringify(args));
return "";
};
self.getId = function () {
return self.m_id;
};
self.getContactAccounts = function () {
var value = JNEXT.invoke(self.m_id, "getContactAccounts");
return JSON.parse(value);
};
self.init = function () {
if (!JNEXT.require("libpimcontacts")) {
return false;
}
self.m_id = JNEXT.createObject("libpimcontacts.PimContacts");
if (self.m_id === "") {
return false;
}
JNEXT.registerEvents(self);
};
// Handle data coming back from JNEXT native layer. Each async function registers a handler and a PluginResult object.
// When JNEXT fires onEvent we parse the result string back into JSON and trigger the appropriate handler (eventHandlers map
// uses callbackId as key), along with the actual data coming back from the native layer. Each function may have its own way of
// processing native data so we do not do any processing here.
self.onEvent = function (strData) {
var arData = strData.split(" "),
strEventDesc = arData[0],
eventHandler,
args = {};
if (strEventDesc === "result") {
args.result = escape(strData.split(" ").slice(2).join(" "));
eventHandler = self.eventHandlers[arData[1]];
if (eventHandler.action === "save" || eventHandler.action === "remove") {
eventHandler.handler(eventHandler.result, JSON.parse(decodeURIComponent(args.result)));
} else if (eventHandler.action === "find") {
eventHandler.handler(arData[1], eventHandler, JSON.parse(decodeURIComponent(args.result)));
}
}
};
self.m_id = "";
self.eventHandlers = {};
self.getInstance = function () {
if (!hasInstance) {
self.init();
hasInstance = true;
}
return self;
};
};
pimContacts = new JNEXT.PimContacts();