diff --git a/js/ui/cordova/plugins/cordova-plugin-contacts/src/blackberry10/index.js b/js/ui/cordova/plugins/cordova-plugin-contacts/src/blackberry10/index.js new file mode 100644 index 0000000..09a4bd2 --- /dev/null +++ b/js/ui/cordova/plugins/cordova-plugin-contacts/src/blackberry10/index.js @@ -0,0 +1,374 @@ +/* + * 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();