uk.co.workingedge.phonegap.plugin.launchnavigator
Version:
Cordova/Phonegap plugin to navigate to a destination using native navigation apps on Android, iOS, and Windows
864 lines (780 loc) • 27.5 kB
JavaScript
/*
* Copyright (c) 2014 Dave Alden (http://github.com/dpa99c)
* Copyright (c) 2014 Working Edge Ltd. (http://www.workingedge.co.uk)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
var ln = {};
/*********************
* Internal properties
*********************/
var DEFAULT_appSelectionDialogHeaderText = "Select app for navigation",
DEFAULT_appSelectionCancelButtonText = "Cancel",
DEFAULT_rememberChoicePromptDialogHeaderText = "Remember your choice?",
DEFAULT_rememberChoicePromptDialogBodyText = "Use the same app for navigating next time?",
DEFAULT_rememberChoicePromptDialogYesButtonText = "Yes",
DEFAULT_rememberChoicePromptDialogNoButtonText = "No";
var store;
var emptyFn = function(){};
/********************
* Internal functions
********************/
var ensureStore = function(){
store = localforage.createInstance({
name: "launchnavigator"
});
};
var setItem = function(key, value, callback){
ensureStore();
return store.setItem(key, value, callback);
};
var getItem = function(key, callback){
ensureStore();
return store.getItem(key, function(err, value){
callback(value);
});
};
var removeItem = function(key, callback){
ensureStore();
return store.removeItem(key, callback);
};
var itemExists = function(key, callback){
ensureStore();
return store.getItem(key, function(err, value){
callback(value !== null);
});
};
/******************
* Public Constants
******************/
/**
* Supported platforms
* @type {object}
*/
ln.PLATFORM = {
ANDROID: "android",
IOS: "ios",
WINDOWS: "windows"
};
/**
* string constants, used to identify apps in native code
* @type {object}
*/
ln.APP = {
USER_SELECT: "user_select",
APPLE_MAPS: "apple_maps",
GOOGLE_MAPS: "google_maps",
WAZE: "waze",
CITYMAPPER: "citymapper",
NAVIGON: "navigon",
TRANSIT_APP: "transit_app",
YANDEX: "yandex",
UBER: "uber",
TOMTOM: "tomtom",
BING_MAPS: "bing_maps",
SYGIC: "sygic",
HERE_MAPS: "here_maps",
MOOVIT: "moovit",
LYFT: "lyft",
MAPS_ME: "maps_me",
CABIFY: "cabify",
BAIDU: "baidu",
TAXIS_99: "taxis_99",
GAODE: "gaode"
};
/**
* Explicitly supported apps by platform
* @type {object}
*/
ln.APPS_BY_PLATFORM = {};
ln.APPS_BY_PLATFORM[ln.PLATFORM.ANDROID] = [
ln.APP.USER_SELECT,
ln.APP.GOOGLE_MAPS,
ln.APP.CITYMAPPER,
ln.APP.UBER,
ln.APP.WAZE,
ln.APP.YANDEX,
ln.APP.SYGIC,
ln.APP.HERE_MAPS,
ln.APP.MOOVIT,
ln.APP.LYFT,
ln.APP.MAPS_ME,
ln.APP.CABIFY,
ln.APP.BAIDU,
ln.APP.TAXIS_99,
ln.APP.GAODE
];
ln.APPS_BY_PLATFORM[ln.PLATFORM.IOS] = [
ln.APP.USER_SELECT,
ln.APP.APPLE_MAPS,
ln.APP.GOOGLE_MAPS,
ln.APP.WAZE,
ln.APP.CITYMAPPER,
ln.APP.NAVIGON,
ln.APP.TRANSIT_APP,
ln.APP.YANDEX,
ln.APP.UBER,
ln.APP.TOMTOM,
ln.APP.SYGIC,
ln.APP.HERE_MAPS,
ln.APP.MOOVIT,
ln.APP.LYFT,
ln.APP.MAPS_ME,
ln.APP.CABIFY,
ln.APP.BAIDU,
ln.APP.TAXIS_99,
ln.APP.GAODE
];
ln.APPS_BY_PLATFORM[ln.PLATFORM.WINDOWS] = [
ln.APP.BING_MAPS
];
/**
* Stock maps app that is always present on each platform
* @type {object}
*/
ln.STOCK_APP = {};
ln.STOCK_APP[ln.PLATFORM.ANDROID] = ln.APP.GOOGLE_MAPS;
ln.STOCK_APP[ln.PLATFORM.IOS] = ln.APP.APPLE_MAPS;
ln.STOCK_APP[ln.PLATFORM.WINDOWS] = ln.APP.BING_MAPS;
/**
* Display names for supported apps
* @type {object}
*/
ln.APP_NAMES = {};
ln.APP_NAMES[ln.APP.USER_SELECT] = "[User select]";
ln.APP_NAMES[ln.APP.APPLE_MAPS] = "Apple Maps";
ln.APP_NAMES[ln.APP.GOOGLE_MAPS] = "Google Maps";
ln.APP_NAMES[ln.APP.WAZE] = "Waze";
ln.APP_NAMES[ln.APP.CITYMAPPER] = "Citymapper";
ln.APP_NAMES[ln.APP.NAVIGON] = "Navigon";
ln.APP_NAMES[ln.APP.TRANSIT_APP] = "Transit App";
ln.APP_NAMES[ln.APP.YANDEX] = "Yandex Navigator";
ln.APP_NAMES[ln.APP.UBER] = "Uber";
ln.APP_NAMES[ln.APP.TOMTOM] = "Tomtom";
ln.APP_NAMES[ln.APP.BING_MAPS] = "Bing Maps";
ln.APP_NAMES[ln.APP.SYGIC] = "Sygic";
ln.APP_NAMES[ln.APP.HERE_MAPS] = "HERE Maps";
ln.APP_NAMES[ln.APP.MOOVIT] = "Moovit";
ln.APP_NAMES[ln.APP.LYFT] = "Lyft";
ln.APP_NAMES[ln.APP.MAPS_ME] = "MAPS.ME";
ln.APP_NAMES[ln.APP.CABIFY] = "Cabify";
ln.APP_NAMES[ln.APP.BAIDU] = "Baidu Maps";
ln.APP_NAMES[ln.APP.TAXIS_99] = "99 Taxi";
ln.APP_NAMES[ln.APP.GAODE] = "Gaode Maps (Amap)";
/**
* All possible transport modes
* @type {object}
*/
ln.TRANSPORT_MODE = {
DRIVING: "driving",
WALKING: "walking",
BICYCLING: "bicycling",
TRANSIT: "transit"
};
/**
* Supported transport modes by apps and platform
* @type {object}
*/
ln.TRANSPORT_MODES = {};
// Android
ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID] = {};
ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID][ln.APP.USER_SELECT] = [ // Allow all
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.BICYCLING,
ln.TRANSPORT_MODE.TRANSIT
];
ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID][ln.APP.GOOGLE_MAPS] = [ // Only launchMode=turn-by-turn
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.BICYCLING,
ln.TRANSPORT_MODE.TRANSIT
];
ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID][ln.APP.SYGIC] = [
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING
];
ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID][ln.APP.MAPS_ME] = [
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.BICYCLING,
ln.TRANSPORT_MODE.TRANSIT
];
ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID][ln.APP.BAIDU] = [
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.BICYCLING,
ln.TRANSPORT_MODE.TRANSIT
];
ln.TRANSPORT_MODES[ln.PLATFORM.ANDROID][ln.APP.GAODE] = [
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.BICYCLING,
ln.TRANSPORT_MODE.TRANSIT
];
// Windows
ln.TRANSPORT_MODES[ln.PLATFORM.WINDOWS] = {};
ln.TRANSPORT_MODES[ln.PLATFORM.WINDOWS][ln.APP.BING_MAPS] = [
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.TRANSIT
];
// iOS
ln.TRANSPORT_MODES[ln.PLATFORM.IOS] = {};
ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.USER_SELECT] = [ // Allow all
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.BICYCLING,
ln.TRANSPORT_MODE.TRANSIT
];
ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.GOOGLE_MAPS] = [
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.BICYCLING,
ln.TRANSPORT_MODE.TRANSIT
];
ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.APPLE_MAPS] = [
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.TRANSIT
];
ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.SYGIC] = [
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING
];
ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.MAPS_ME] = [
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.BICYCLING,
ln.TRANSPORT_MODE.TRANSIT
];
ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.BAIDU] = [
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.BICYCLING,
ln.TRANSPORT_MODE.TRANSIT
];
ln.TRANSPORT_MODES[ln.PLATFORM.IOS][ln.APP.GAODE] = [
ln.TRANSPORT_MODE.DRIVING,
ln.TRANSPORT_MODE.WALKING,
ln.TRANSPORT_MODE.BICYCLING,
ln.TRANSPORT_MODE.TRANSIT
];
/**
* Apps by platform that support specifying a start location
* @type {object}
*/
ln.SUPPORTS_START = {};
ln.SUPPORTS_START[ln.PLATFORM.ANDROID] = [
ln.APP.USER_SELECT,
ln.APP.GOOGLE_MAPS, // Only launchMode=maps
ln.APP.CITYMAPPER,
ln.APP.UBER,
ln.APP.YANDEX,
ln.APP.HERE_MAPS,
ln.APP.MOOVIT,
ln.APP.LYFT,
ln.APP.MAPS_ME,
ln.APP.CABIFY,
ln.APP.BAIDU,
ln.APP.TAXIS_99,
ln.APP.GAODE
];
ln.SUPPORTS_START[ln.PLATFORM.IOS] = [
ln.APP.USER_SELECT,
ln.APP.APPLE_MAPS,
ln.APP.GOOGLE_MAPS,
ln.APP.CITYMAPPER,
ln.APP.TRANSIT_APP,
ln.APP.YANDEX,
ln.APP.UBER,
ln.APP.HERE_MAPS,
ln.APP.MOOVIT,
ln.APP.LYFT,
ln.APP.MAPS_ME,
ln.APP.CABIFY,
ln.APP.BAIDU,
ln.APP.TAXIS_99,
ln.APP.GAODE
];
ln.SUPPORTS_START[ln.PLATFORM.WINDOWS] = [
ln.APP.BING_MAPS
];
/**
* Apps by platform that support specifying a start nickname
* @type {object}
*/
ln.SUPPORTS_START_NAME = {};
ln.SUPPORTS_START_NAME[ln.PLATFORM.ANDROID] = [
ln.APP.USER_SELECT,
ln.APP.CITYMAPPER,
ln.APP.UBER,
ln.APP.HERE_MAPS,
ln.APP.MOOVIT,
ln.APP.CABIFY,
ln.APP.BAIDU,
ln.APP.TAXIS_99,
ln.APP.GAODE
];
ln.SUPPORTS_START_NAME[ln.PLATFORM.IOS] = [
ln.APP.USER_SELECT,
ln.APP.APPLE_MAPS, // Only launchMode=mapkit
ln.APP.CITYMAPPER,
ln.APP.UBER,
ln.APP.HERE_MAPS,
ln.APP.MOOVIT,
ln.APP.CABIFY,
ln.APP.BAIDU,
ln.APP.TAXIS_99,
ln.APP.GAODE
];
/**
* Apps by platform that support specifying a destination nickname
* @type {object}
*/
ln.SUPPORTS_DEST_NAME = {};
ln.SUPPORTS_DEST_NAME[ln.PLATFORM.ANDROID] = [
ln.APP.USER_SELECT,
ln.APP.GOOGLE_MAPS, // only launchMode=geo
ln.APP.CITYMAPPER,
ln.APP.UBER,
ln.APP.HERE_MAPS,
ln.APP.MOOVIT,
ln.APP.CABIFY,
ln.APP.BAIDU,
ln.APP.TAXIS_99,
ln.APP.GAODE
];
ln.SUPPORTS_DEST_NAME[ln.PLATFORM.IOS] = [
ln.APP.USER_SELECT,
ln.APP.APPLE_MAPS, // Only launchMode=mapkit
ln.APP.CITYMAPPER,
ln.APP.NAVIGON,
ln.APP.UBER,
ln.APP.TOMTOM,
ln.APP.HERE_MAPS,
ln.APP.MOOVIT,
ln.APP.CABIFY,
ln.APP.BAIDU,
ln.APP.TAXIS_99,
ln.APP.GAODE
];
/**
* Apps by platform that support specifying a launch mode
* @type {object}
*/
ln.SUPPORTS_LAUNCH_MODE = {};
ln.SUPPORTS_LAUNCH_MODE[ln.PLATFORM.ANDROID] = [
ln.APP.USER_SELECT,
ln.APP.GOOGLE_MAPS
];
ln.SUPPORTS_LAUNCH_MODE[ln.PLATFORM.IOS] = [
ln.APP.USER_SELECT,
ln.APP.APPLE_MAPS
];
ln.COORDS_REGEX = /^[-\d.]+,[\s]*[-\d.]+$/;
/******************
* Public API
******************/
/**
* Returns the display name of the specified app.
* @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`.
* @return {string} - app display name. e.g. "Google Maps".
*/
ln.getAppDisplayName = function(app){
ln.util.validateApp(app);
return ln.APP_NAMES[app];
};
/**
* Returns list of supported apps on a given platform.
* @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.IOS`.
* @return {string[]} - apps supported on specified platform as a list of `launchnavigator.APP` constants.
*/
ln.getAppsForPlatform = function(platform){
ln.util.validatePlatform(platform);
return ln.APPS_BY_PLATFORM[platform];
};
/**
* Indicates if an app on a given platform supports specification of transport mode.
* @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`.
* @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.IOS`.
* @return {boolean} - true if app/platform combination supports specification of transport mode.
*/
ln.supportsTransportMode = function(app, platform){
ln.util.validateApp(app);
ln.util.validatePlatform(platform);
return !!ln.TRANSPORT_MODES[platform] && ln.util.objectContainsKey(ln.TRANSPORT_MODES[platform], app);
};
/**
* Returns the list of transport modes supported by an app on a given platform.
* @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`.
* @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.IOS`.
* @return {string[]} - list of transports modes as constants in `launchnavigator.TRANSPORT_MODE`.
* If app/platform combination doesn't support specification of transport mode, the list will be empty;
*/
ln.getTransportModes = function(app, platform){
if(ln.supportsTransportMode(app, platform)){
return ln.TRANSPORT_MODES[platform][app];
}
return [];
};
/**
* Indicates if an app on a given platform supports specification of launch mode.
* @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`.
* @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.ANDROID`.
* @return {boolean} - true if app/platform combination supports specification of transport mode.
*/
ln.supportsLaunchMode = function(app, platform) {
ln.util.validateApp(app);
ln.util.validatePlatform(platform);
return !!ln.SUPPORTS_LAUNCH_MODE[platform] && ln.util.arrayContainsValue(ln.SUPPORTS_LAUNCH_MODE[platform], app);
};
/**
* Indicates if an app on a given platform supports specification of start location.
* @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`.
* @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.IOS`.
* @return {boolean} - true if app/platform combination supports specification of start location.
*/
ln.supportsStart = function(app, platform){
ln.util.validateApp(app);
ln.util.validatePlatform(platform);
return !!ln.SUPPORTS_START[platform] && ln.util.arrayContainsValue(ln.SUPPORTS_START[platform], app);
};
/**
* Indicates if an app on a given platform supports specification of a custom nickname for start location.
* @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`.
* @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.IOS`.
* @return {boolean} - true if app/platform combination supports specification of start location.
*/
ln.supportsStartName = function(app, platform){
ln.util.validateApp(app);
ln.util.validatePlatform(platform);
return !!ln.SUPPORTS_START_NAME[platform] && ln.util.arrayContainsValue(ln.SUPPORTS_START_NAME[platform], app);
};
/**
* Indicates if an app on a given platform supports specification of a custom nickname for destination location.
* @param {string} app - specified as a constant in `launchnavigator.APP`. e.g. `launchnavigator.APP.GOOGLE_MAPS`.
* @param {string} platform - specified as a constant in `launchnavigator.PLATFORM`. e.g. `launchnavigator.PLATFORM.IOS`.
* @return {boolean} - true if app/platform combination supports specification of destination location.
*/
ln.supportsDestName = function(app, platform){
ln.util.validateApp(app);
ln.util.validatePlatform(platform);
return !!ln.SUPPORTS_DEST_NAME[platform] && ln.util.arrayContainsValue(ln.SUPPORTS_DEST_NAME[platform], app);
};
/**
*
* @param {string/number[]} destination (required) - destination location to use for navigation - see launchnavigator.navigate()
* @param {object} [options={}] - optional parameters - see launchnavigator.navigate()
* @param {function} successCallback - function executed in case of success
* @param {function} errorCallback - function executed in case of error
*/
ln.userSelect = function(destination, options, successCallback, errorCallback){
var userSelectDisplayed, app;
options = options || {};
options.errorCallback = options.errorCallback || errorCallback || emptyFn;
options.successCallback = options.successCallback || successCallback || emptyFn;
// app selection
options.appSelection = options.appSelection || {};
options.appSelection.dialogPositionX = options.appSelection.dialogPositionX || 550;
options.appSelection.dialogPositionY = options.appSelection.dialogPositionY || 500;
options.appSelection.callback = options.appSelection.callback || emptyFn;
options.appSelection.rememberChoice = options.appSelection.rememberChoice || {};
options.appSelection.rememberChoice.enabled = typeof options.appSelection.rememberChoice.enabled !== "undefined" ? options.appSelection.rememberChoice.enabled : "prompt";
options.appSelection.rememberChoice.prompt = options.appSelection.rememberChoice.prompt || {};
options.appSelection.rememberChoice.prompt.callback = options.appSelection.rememberChoice.prompt.callback || emptyFn;
var buttonList = [], buttonMap = {};
if(userSelectDisplayed) return;
var launchApp = function(){
options.app = app;
launchnavigator.navigate(destination, options);
};
var displayChooser = function(){
userSelectDisplayed = true;
window.plugins.actionsheet.show({
'androidTheme': options.appSelection.androidTheme || window.plugins.actionsheet.ANDROID_THEMES.THEME_HOLO_LIGHT,
'title': options.appSelection.dialogHeaderText || DEFAULT_appSelectionDialogHeaderText,
'buttonLabels': buttonList,
'androidEnableCancelButton' : true, // default false
//'winphoneEnableCancelButton' : true, // default false
'addCancelButtonWithLabel': options.appSelection.cancelButtonText || DEFAULT_appSelectionCancelButtonText,
'position': [options.appSelection.dialogPositionX, options.appSelection.dialogPositionY] // for iPad pass in the [x, y] position of the popover
}, onChooseApp);
};
var onChooseApp = function (btnNumber){
userSelectDisplayed = false;
var idx = btnNumber - 1;
app = buttonMap[idx];
if(app !== "cancel"){
options.appSelection.callback(app);
if(options.appSelection.rememberChoice.enabled === true || options.appSelection.rememberChoice.enabled === "true"){
rememberUserChoiceAndLaunch();
}else if(options.appSelection.rememberChoice.enabled === false || options.appSelection.rememberChoice.enabled === "false"){
// Don't remember, just launch app
launchApp();
}else{
// Default
checkIfAlreadyPrompted();
}
} else {
options.errorCallback('cancelled');
}
};
var rememberUserChoiceAndLaunch = function(){
setItem("choice", app, function(){
launchApp();
});
};
var checkForChoice = function(availableApps){
getItem("choice", function(choice){
if(choice){
if(availableApps[choice]){
app = choice;
launchApp();
}else{
// Chosen app is no longer available on device
ln.appSelection.userChoice.clear(function(){
ln.appSelection.userPrompted.clear(function(){
displayChooser();
});
})
}
}else{
displayChooser();
}
})
};
// Check if user has already been prompted whether to remember their choice
var checkIfAlreadyPrompted = function(){
getItem("prompted", function(prompted){
if(prompted){
launchApp();
}else{
promptUser();
}
});
};
// Prompt user whether to remember their choice
var promptUser = function(){
if(options.appSelection.rememberChoice.promptFn){
options.appSelection.rememberChoice.promptFn(handleUserPromptChoice);
}else{
// Show prompt using cordova dialogs
navigator.notification.confirm(
options.appSelection.rememberChoice.prompt.bodyText || DEFAULT_rememberChoicePromptDialogBodyText,
function(idx){
handleUserPromptChoice(idx === 1);
},
options.appSelection.rememberChoice.prompt.headerText || DEFAULT_rememberChoicePromptDialogHeaderText,
[
options.appSelection.rememberChoice.prompt.yesButtonText || DEFAULT_rememberChoicePromptDialogYesButtonText,
options.appSelection.rememberChoice.prompt.noButtonText || DEFAULT_rememberChoicePromptDialogNoButtonText
]
);
}
};
var handleUserPromptChoice = function(shouldRemember){
options.appSelection.rememberChoice.prompt.callback(shouldRemember);
setItem("prompted", true, function(){
if(shouldRemember){
rememberUserChoiceAndLaunch();
}else{
launchApp();
}
});
};
// Get list of available apps
launchnavigator.availableApps(function(apps){
for(var _app in apps){
var isAvailable = apps[_app];
if(!isAvailable) continue;
if(options.appSelection.list && options.appSelection.list.length > 0 && !ln.util.arrayContainsValue(options.appSelection.list, _app)) continue;
buttonList.push(ln.getAppDisplayName(_app));
buttonMap[buttonList.length-1] = _app;
}
if(buttonList.length === 0){
return options.errorCallback("No supported navigation apps are available on the device");
}
if(buttonList.length === 1){
app = buttonMap[0];
return launchApp();
}
buttonMap[buttonList.length] = "cancel"; // Add an entry for cancel button
// Check if a user choice exists
checkForChoice(apps);
}, options.errorCallback);
};
/*****************************
* App selection API functions
*****************************/
ln.appSelection = {
userChoice: {},
userPrompted: {}
};
/**
* Indicates whether a user choice exists for a preferred navigator app.
* @param {function} cb - function to pass result to: will receive a boolean argument.
*/
ln.appSelection.userChoice.exists = function(cb){
itemExists("choice", cb);
};
/**
* Returns current user choice of preferred navigator app.
* @param {function} cb - function to pass result to: will receive a string argument indicating the app, which is a constant in `launchnavigator.APP`.
* If no current choice exists, value will be null.
*/
ln.appSelection.userChoice.get = function(cb){
getItem("choice", cb);
};
/**
* Sets the current user choice of preferred navigator app.
* @param {string} app - app to set as preferred choice as a constant in `launchnavigator.APP`.
* @param {function} cb - function to call once operation is complete.
*/
ln.appSelection.userChoice.set = function(app, cb){
setItem("choice", app, cb);
};
/**
* Clears current user choice of preferred navigator app.
* @param {function} cb - function to call once operation is complete.
*/
ln.appSelection.userChoice.clear = function(cb){
removeItem("choice", cb);
};
/**
* Indicates whether user has already been prompted whether to remember their choice a preferred navigator app.
* @param {function} cb - function to pass result to: will receive a boolean argument.
*/
ln.appSelection.userPrompted.get = function(cb){
itemExists("prompted", cb);
};
/**
* Sets flag indicating user has already been prompted whether to remember their choice a preferred navigator app.
* @param {function} cb - function to call once operation is complete.
*/
ln.appSelection.userPrompted.set = function(cb){
setItem("prompted", true, cb);
};
/**
* Clears flag which indicates if user has already been prompted whether to remember their choice a preferred navigator app.
* @param {function} cb - function to call once operation is complete.
*/
ln.appSelection.userPrompted.clear = function(cb){
removeItem("prompted", cb);
};
/*******************
* Utility functions
*******************/
ln.util = {};
ln.util.arrayContainsValue = function (a, obj) {
var i = a.length;
while (i--) {
if (a[i] === obj) {
return true;
}
}
return false;
};
ln.util.objectContainsKey = function (o, key) {
for(var k in o){
if(k === key){
return true;
}
}
return false;
};
ln.util.objectContainsValue = function (o, value) {
for(var k in o){
if(o[k] === value){
return true;
}
}
return false;
};
ln.util.countKeysInObject = function (o){
var count = 0;
for(var k in o){
count++;
}
return count;
};
ln.util.isValidApp = function(app){
if(app === "none") return true; // native chooser
return ln.util.objectContainsValue(ln.APP, app);
};
ln.util.isValidPlatform = function(platform){
return ln.util.objectContainsValue(ln.PLATFORM, platform);
};
ln.util.isValidTransportMode = function(transportMode) {
return ln.util.objectContainsValue(ln.TRANSPORT_MODE, transportMode);
};
ln.util.validateApp = function(app){
if(!ln.util.isValidApp(app)){
throw new Error("'"+app+"' is not a recognised app");
}
};
ln.util.validatePlatform = function(platform){
if(!ln.util.isValidPlatform(platform)){
throw new Error("'"+platform+"' is not a recognised platform");
}
};
ln.util.validateTransportMode = function(transportMode){
if(!ln.util.isValidTransportMode(transportMode)){
throw new Error("'"+transportMode+"' is not a recognised transport mode");
}
};
ln.util.extractCoordsFromLocationString = function(location){
if(location && typeof(location) === "string" && location.match(ln.COORDS_REGEX)){
location = location.replace(/\s*/g,'');
var parts = location.split(",");
location = [parts[0], parts[1]];
}
return location;
};
ln.util.isValidLaunchMode = function(launchMode){
for(var LAUNCH_MODE in ln.LAUNCH_MODE){
if(launchMode === ln.LAUNCH_MODE[LAUNCH_MODE]) return true;
}
return false;
};
ln.util.validateLaunchMode = function(launchMode){
if(!ln.util.isValidLaunchMode(launchMode)){
throw new Error("'"+launchMode+"' is not a recognised launch mode");
}
};
ln.util.conformNavigateOptions = function(args){
var options;
if(args.length > 1 && typeof args[1] === "function"){
// assume (dest, success, error, opts)
options = (args.length > 3 && typeof args[3] === "object") ? args[3] : {};
options.successCallback = args[1];
if(args.length > 2 && typeof args[2] === "function"){
options.errorCallback = args[2];
}
}else{
// assume (dest, opts)
options = (args.length > 1 && typeof args[1] === "object") ? args[1] : {};
}
return options;
};
module.exports = ln;