/**
* These javascript library is for NBT vehicles. It depends on the jquery library.
*
* @author Thomas Stadtlander, NTT DATA 2011-2012
* @version 2.18.2-1352714843134
*/
var Config = {
appIdentifier : 'Main',
setupFunction : function() {
}, // initial function for an application
startPanelID : 'Start',// defines the default panel id of this app
startPanelUrl : 'start', // defines the default panel url of this app
startPanelOptions : {}, // defines the default panel options of this appP
defaultLoadDelay : 600, // delay time in s for loadWithDelay calls
geocoderEnabled : true, // if true, the Geocoder.init() starts a timer to refresh the position
geocoderSupportedCountries : [ 'AT', 'BE', 'CH', 'DE', 'ES', 'FR', 'GB', 'IT', 'NL' ], // empty list: a custom
// country name can be used,. one item, then only the city can be inserted.
geocoderUrl : 'geocoder',// url for geocoder requests
geocoderUpdateInterval : 15000,// in milliseconds
geocoderUpdateDistance : 500, // in meter
imageURL : 'image',
i18nURL : 'commoni18n', // path to the common i18n resource json with the current translations of the backend locale
ajaxTimeout : 30000, // wait only for 60s until server response
viewportHeight : 420, // height of visible area
viewportTop : 60, // top of the viewport
scrollHeight : 60, // default scroll height
scrollPageRowsCount : 6, // # of rows to scroll by page down/up button after scrolling
firefoxMode : false, // true, for tests in firefox
speedlockPanelSetting : {
"lockedScrolling" : [], // ["AT", "BE", "DE", "DK", "ES", "FR", "IT", "NL", "RU", "SE", "UK", "CN"]
"lockedContent" : [], // ["JP"]
"lockedText" : []
},// ["US", "TW", "HK", "MO"]
homemarket : undefined,
};
var Error = {
Unexpected : 'errorUnexpected',
WrongURL : 'errorWrongURL',
NoConnection : 'errorNoConnection',
LoginFailed : 'errorLoginFailed',
ParsingException : 'errorParsingException',
SetDestinationFailed : 'errorSetDestinationFailed',
MakeVoiceCallFailed : 'errorMakeVoiceCallFailed',
BINCouldNotStarted : 'errorBINCouldNotStarted',
NoPosition : 'errorNoPosition',
NoDestination : 'errorNoDestination',
Moving : 'errorMoving',
MovingShort : 'errorMovingShort',
};
/**
* This is for all timers. If a timer was started, it should be stored here, so it can be canceled later, if needed.
*/
var Timers = {};
$(document).ready(function() {
initApp();
});
var initApp = function() {
EFIHelper.init();
addNBTEventListener();
I18N.init();
PM.init();
Geocoder.init();
LOG.info('all components initialized');
// for tests in firefox
if (navigator.userAgent.indexOf('Firefox') > -1) {
Config.firefoxMode = true;
}
};
var addNBTEventListener = function() {
$(document).on("keydown", document, generalKeydownHandler);
/**
* QC2456: If headunit speller returns, the next input field will be selected. If the input field is not in the
* visible area the browser scrolls native. This is not good and must be prevented. FocusIn is special for input
* fields, because of the embedded input tag
*/
$(document).on("focus", "li.input", function(event) {
$('#Main').animate({
scrollTop : 0
}, 1);
var element = $(this).find('input, textarea');
if (!element.parents('li').first().is('.selected')) {
element.blur();
}
PM.visiblePanel.find('.input.selected').find('input, textarea').get(0).focus();
});
$(document).on("blur", "li.input", function(event) {
event.stopPropagation();
$(this).find('input, textarea').get(0).blur();
});
};
var generalKeydownHandler = function(evt) {
var k = evt.keyCode;
switch (k) {
case 13: // enter
case 39: // right arrow
if (!PM.blockUI) {
PM.execute();
}
break;
case 38: // up arrow
if (!PM.blockUI) {
PM.scrollUp();
}
break;
case 40: // down arrow
if (!PM.blockUI) {
PM.scrollDown();
}
break;
case 37: // left arrow
if (PM.lastMovingStatus && PM.lastLockedPanel) {
// if CAB or Main Module
if (PM.isStartPage) {
PM.exitBrowser();
return;
}
// reset history if moving and a panel is is locked, so app will be closed with backbutton
PM.resetHistory();
}
PM.back();
break;
}
};
var timeBoxKeydownHandler = function(evt) {
switch (evt.keyCode) {
case 13: // enter
case 39: // right arrow
PM.blockUI = false;
break;
case 38: // up arrow
PM.countDownTime(evt.data);
evt.stopPropagation();
break;
case 40: // down arrow
PM.countUpTime(evt.data);
evt.stopPropagation();
break;
case 37: // left arrow
PM.releaseTimeFocus(evt.data);
evt.stopPropagation();
break;
}
};
/**
* PanelManager for showing, scrolling, loading and managing the history of Panels.
*/
var PM = {
isStartPage : false,
isLoadPageCalled : false,
lastMovingStatus : false, // false = staying, true = moving
lastLockedPanel : undefined, // this is the panel, which is locked during
// driving
isUpdating : false,
startedWithHash : false,
stack : new Array(), // history stack
holder : null, // for performance issue, use PM.holder to find elements.
visiblePanel : null, // for performance issue
blockUI : false, // if this is true, the keylistener will not work
idrivePlugin : null,
getUserAgent : function() {
return navigator.userAgent;
},
locale : 'de_DE', // TODO
showScroller : true, // will be set to true, if PM.show will be called. a panel can call PM.disableScroller after
// rendering.
getDefaultOptions : function() {
return {
indicator : true,
background : false,
sessionStorage : false,
localStorage : false,
refreshStorage : false,
async : true,
};
},
/**
* The PanelManager will be initialized. If there is a hashMark in the url, so the panel must be loaded with the
* given hashMark value, else the configured first panel with the configured url will be loaded. If the app wants to
* use the geocoder, first the coordinates and geocode search modus will be retrieved. If there are params added to
* the app call request, this params will be added to the start panel.
This function will be called
* automatically, if the DOM was loaded.
*/
init : function() {
LOG.info('initializing PanelManager');
if (window.history.length == 1) {
LOG.info('isStartPage set to true');
PM.isStartPage = true;
}
$('#Main').append(
'
');
this.idrivePlugin = document.getElementById('idrivePlugin');
this.holder = $('#PanelHolder');
Config.setupFunction();
// if no hash is set so load the defined default panel
var hashValue = this.getHash();
if (hashValue.length == 0) {
var url = Config.startPanelUrl;
// if the app was called with url params, so read it and give it to the first panel
url = this.getUrlWithCurrentParams(url);
PM.show(Config.startPanelID, url, Config.startPanelOptions);
return;
}
// check the hash of the url, maybe new panel must be loaded.
if (hashValue) {
LOG.info("App was called with hash: " + hashValue);
PM.startedWithHash = true;
var panelsCounter = hashValue.split('||').length;
var lastPanelHash = undefined;
$.each(hashValue.split('||'), function(index) {
var hashmark = this.toString();
for ( var i = hashmark.split('::').length; i < 3; i++) {
hashmark += '::';
}
if (index < panelsCounter - 1) {
PM.stack.push(decodeURIComponent(hashmark));
} else {
lastPanelHash = decodeURIComponent(hashmark);
}
});
if (lastPanelHash) {
this.loadPanelWithHash(lastPanelHash);
}
}
if (hashValue != undefined && hashValue.split('||').length <= 1) {
LOG.info('startPageDisplayed set to true');
PM.setStartPageDisplayed(true);
}
},
loadPanelWithHash : function(lastPanelHash) {
LOG.info('load panel with hash: ' + lastPanelHash);
hash = lastPanelHash.split('::');
if (hash.length > 0) {
if ($('#' + hash[0]).length) {
// panel already exists, so show it only
PM.show(hash[0]);
return;
}
}
if (hash.length == 3) {
if (hash[2] == 'session') {
PM.load(hash[0], hash[1], {
sessionStorage : true
});
} else if (hash[2] == 'local') {
PM.load(hash[0], hash[1], {
localStorage : true
});
} else if (hash[2] == 'cur') {
PM.loadWithPosition(hash[0], hash[1]);
} else if (hash[2] == 'dest') {
PM.loadWithDestination(hash[0], hash[1]);
} else if (hash[2] == 'other') {
PM.loadWithOtherLocation(hash[0], hash[1]);
} else {
PM.show(hash[0], hash[1]);
}
} else if (hash.length == 2) {
PM.show(hash[0], hash[1]);
} else {
this.show(hash[0]);
}
},
/**
* The idrive-plugin will be used to set the loading indicator of the browser.
*
* @param enabled:boolean
* A boolean for indicating the loader.
*/
setLoadIndicator : function(enabled) {
LOG.info('show load indicator of browser: ' + enabled);
try {
this.idrivePlugin.setBrowserActivity(enabled);
} catch (e) {
LOG.error('Could not set load indicator. Problem with idrive-plugin: ' + e);
}
},
/**
* The idrive-plugin will be used to set the start page of the browser.
*
* @param enabled:boolean
* A boolean for displaying start page.
*/
setStartPageDisplayed : function(enabled) {
if (!PM.isStartPage) {
enabled = false;
}
try {
this.idrivePlugin.setStartPageDisplayed(enabled);
} catch (e) {
LOG.error('Could not set startPageDisplay(' + enabled + ').');
}
},
/**
* call EFI-plugin to exit the current browser.
*/
exitBrowser : function() {
try {
LOG.info('Closing Browser...');
EFIHelper.exitBrowser(null);
} catch (e) {
LOG.error('Could not close Browser.');
}
},
/**
* Loads the page with the given url synchronisly without AJAX. A new DOM will be created.
This function
* should be used only for loading new applications.
*
* @param url:string
* The relative or absolute URL for the new panel.
* @param doReplace:boolean
* if it set to true, so replace the current location (no history)
*/
loadPage : function(url, doReplace) {
PM.isLoadPageCalled = true;
if (doReplace) {
window.location.replace(url);
} else {
window.location.href = url;
}
},
/**
* @param panelId
* @param url
* @param [options:map}
* {useNewestCoordinate:true|false}
*/
loadWithPosition : function(panelId, url, options) {
options = $.extend(PM.getDefaultOptions(), options);
options = $.extend(options, {
geocoder : 'cur'
});
PM.load(panelId, url, options);
},
/**
* @param panelId
* @param url
* @param [options:map}
* {useNewestCoordinate:true|false}
*/
loadWithDestination : function(panelId, url, options) {
options = $.extend(PM.getDefaultOptions(), options);
options = $.extend(options, {
geocoder : 'dest'
});
PM.load(panelId, url, options);
},
/**
* @param panelId
* @param url
* @param [options:map}
* {useNewestCoordinate:true|false}
*/
loadWithOtherLocation : function(panelId, url, options) {
options = $.extend(PM.getDefaultOptions(), options);
options = $.extend(options, {
geocoder : 'other'
});
PM.load(panelId, url, options);
},
/**
* Loads a panel from the given relative or absolute url. Panel will be added to the DOM.
*
* @param panelId:string
* The id for the new panel. It does not matter what id the panel returns. Always this id will be used
* for it.
* @param url:string
* The relative or absolute URL for the new panel.
* @param [options:map]
* A set of key/value pairs, which configure the loading.
* {
* indicator : true, // the load indicator will be shown.
* domExpiryTime : 600, // if not set, no caching will be used. Time is in seconds. For this time, the DOM content of the panel will not be refreshed.
* background : true, // no load indicator will be shown and if the result was loaded. The result will not be displayed.
* callback : function(){ }, // this function will be called after successfully loading the result.
* errorCallback : function(){ }, // this function will be called, if there are problems during the loading
* geocoder : 'mode'|'cur'|'dest'|'navi', // use the Geocoder and add the coordinates depending on the option.
* sessionStorage : true, // looks at sessionStorage, if not there, it will be added after loading
* localStorage : true, // looks at localStorage, if not there, it will be added after loading
* refreshStorage: false // force to refresh the storage
* resetHistory: false // resets the history stack before the new panel will be loaded.
* geoData: GeoData
* }
*
*/
load : function(panelId, url, options) {
options = $.extend(PM.getDefaultOptions(), options);
LOG.info('load() with options: ' + JSON.stringify(options));
if (options.geocoder) {
Geocoder.loadPanelWithCoordinates(panelId, url, options);
return;
}
if (options.sessionStorage && !options.refreshStorage) {
if (SM.loadPanel(panelId, options)) {
return;
}
}
if (options.localStorage && !options.refreshStorage) {
if (SM.loadPanel(panelId, options)) {
return;
}
}
if (options.resetHistory) {
PM.resetHistory();
}
if (options.refreshStorage) {
SM.clearPanel(panelId);
}
if (options.domExpiryTime) {
LOG.info('cache page for ' + options.domExpiryTime + "s.");
var panel = $('#' + panelId);
if (panel.length) {
if (this.isNotExpired(panel.attr('cdpLastLoaded'), options.domExpiryTime)) {
PM.show(panelId);
return;
}
}
}
LOG.info("Loading panel from url=" + url + " with id=" + panelId);
var method = "GET";
if (options.postData) {
method = "POST";
}
var postData = options.postData;
// force reload, to prevent loading from browser-cache
if (options.localStorage || options.sessionStorage) {
if (!postData || postData.length == 0) {
postData = '_t=' + PM.now();
} else {
postData += '&_t=' + PM.now();
}
}
$.ajax({
url : url,
type : method,
dataType : 'xml',
data : postData,
async : options.async,
timeout : Config.ajaxTimeout,
beforeSend : function(jqXHR) {
this.startTime = PM.now();
if (options.indicator) {
PM.showLoadIndicator(true);
}
PM.setLoadIndicator(true);
},
complete : function(jqXHR) {
LOG.info('ajax load complete after ' + (PM.now() - this.startTime) + 'ms.');
LOG.error('cancelCompleteCallback: ' + jqXHR.cancelCompleteCallback);
if (!jqXHR.cancelCompleteCallback) {
LOG.error('disable load indicator. cancelCompleteCallback: ' + jqXHR.cancelCompleteCallback);
PM.showLoadIndicator(false);
PM.setLoadIndicator(false);
}
},
error : function(jqXHR) {
LOG.info('ajax error');
if (options.errorCallback) {
if (jqXHR.status == 404) {
options.errorCallback(Error.WrongURL);
} else {
options.errorCallback(Error.NoConnection);
}
return;
}
if (!PM.isLoadPageCalled) {
// show not if PM.loadPage was called
LOG.info('ajax load error');
LOG.error('Panel could not be loaded from Server.');
PM.showError(Error.NoConnection);
}
},
/**
* @param xml:string
* the response (panel-xml or other data)
*/
success : function(xml, textStatus, jqXHR) {
LOG.info('-> ajax success');
var response = $(xml).find("response");
if (response.attr('locale') !== undefined) {
PM.locale = response.attr('locale');
I18N.update(PM.locale);
}
try {
this.status = parseInt(response.attr('status'));
LOG.info('nbt response: code=' + this.status + '; locale=' + PM.locale);
switch (this.status) {
case 100:
// nothing to do
break;
case 200: // a panel was returned
// add to temp and set the panelId to the first element
var tempDiv = $(document.createElement("div"));
tempDiv.append(response.text());
tempDiv.find('div:first').attr('id', panelId);
// remove all panels with the same IDs from DOM
tempDiv.children().each(function() {
var id = $(this).attr('id');
LOG.info('Panel with id=' + id + ' returned.');
if (id != null && id.length > 0) {
LOG.info("returned panelId: [" + id + "]");
PM.holder.find('#' + id).remove();
if (PM.visiblePanel != null && PM.visiblePanel.attr('id') == id) {
PM.visiblePanel = null;
}
}
});
// add all panels and show the first panel
PM.holder.append(tempDiv.children());
// test if url gets coordinates attached
if (options.geoData) {
$('#' + panelId).attr('cdpGeoData', escape(JSON.stringify(options.geoData)));
}
$('#' + panelId).attr('locale', response.attr('locale'));
$('#' + panelId).attr('cdpLastLoaded', PM.now());
if (url !== undefined) {
$('#' + panelId).attr('cdpURL', url);
}
if (options.originalUrl) {
$('#' + panelId).attr('cdpURL', options.originalUrl);
}
if (options.sessionStorage) {
$('#' + panelId).attr('cdpMode', 'session');
SM.storePanel(panelId, options);
}
if (options.localStorage) {
$('#' + panelId).attr('cdpMode', 'local');
SM.storePanel(panelId, options);
}
if (!options.background) {
PM.show(panelId, url);
}
if (options.callback) {
options.callback();
}
break;
case 300:// a url for redirect was returned
LOG.info('redirect: ' + response.text());
jqXHR.cancelCompleteCallback = true;
if (response.text().indexOf('http') == 0) {
PM.loadPage(response.text());
} else {
PM.load(panelId, response.text(), options);
}
break;
case 401:
LOG.info('authentication failed: ' + response.text());
EFIHelper.doUSSOauth(function(efiData) {
LOG.info('doUssoAuth -> ACK : ' + efiData.ACK);
if (efiData.ACK) {
PM.load(panelId, url, options);
} else {
PM.showError(Error.LoginFailed);
}
}, parseInt(response.text()));
break;
case 600:
var callbackFunction = response.attr('callback');
var geoData = JSON.stringify(options.geoData);
var locale = response.attr('locale');
LOG.info("custom response -> callback = " + callbackFunction);
jqXHR.cancelCompleteCallback = eval(callbackFunction + "('"
+ response.text().replace(/\'/g, '\\\'') + "', '" + panelId + "', '" + geoData + "', '"
+ locale + "');");
}
} catch (e) {
LOG.error(e);
if (options.errorCallback) {
options.errorCallback(Error.NoConnection);
} else {
PM.showError(Error.ParsingException);
}
}
}
});
},
/**
* Call EFIHelper to go back to the predefined home page.
*/
goHome : function() {
EFIHelper.goHome(function(efiData) {
});
},
/**
* Show an error panel accordig to the given error code.
*
* @param errorCode:string
* One of the error codes defined in the map Error
*/
showError : function(errorCode) {
if (!errorCode) {
errorCode = Error.Unexpected;
}
LOG.error('An error occured: ' + errorCode);
var errorPanel = $('#GenericPanelError');
if (!errorPanel.length) {
var content = '';
content += '
';
PM.holder.append(content);
errorPanel = $('#GenericPanelError');
}
errorPanel.find('.title').text(I18N.get('errorTitle'));
errorPanel.find('.text div').text(I18N.get(errorCode));
PM.show('GenericPanelError');
},
/**
* show the panel, if panelId could not be loaded and an url is given, so load the panel with the given relative or
* absolute url before showing
*
* @param panelId:string
* The id for the new panel. It does not matter what id the panel returns. Always this id will be used
* for it.
* @param [url:string]
* The relative or absolute URL for the new panel.
*/
showLoadIndicator : function(enable) {
if (enable) {
$('#GenericPanelProgress').addClass('show');
this.blockUI = true;
} else {
$('#GenericPanelProgress').removeClass('show');
this.blockUI = false;
}
},
/**
* close toolbar menu
*/
closeToolbarMenu : function() {
var toolbarMenu = PM.visiblePanel.find('.submenu:visible');
if (toolbarMenu.length) {
var menuLink = toolbarMenu.closest('li');
toolbarMenu.find('.selected').switchSelected(menuLink);
toolbarMenu.parent().toggle();
menuLink.removeClass('inactive');
}
},
/**
* show toolbar menu
*
* @param [toolbarEntry :
* HTML element] current toolbar entry (usually a 'li' element), its action will open a toolbar menu
*/
showToolbarMenu : function(toolbarEntry) {
var menu = $(toolbarEntry).find('.toolbar.submenu');
var toolbarHeight = $(toolbarEntry).parent().height();
var toolbarTop = $(toolbarEntry).offset().top;
if ((menu.height() + toolbarTop) > toolbarHeight) {
toolbarTop = toolbarHeight - menu.height();
}
menu.css('top', toolbarTop);
menu.parent().toggle();
$(toolbarEntry).switchSelected(menu.find('li').first());
$(toolbarEntry).addClass('inactive');
menu.parent().css('opacity', 1);
},
/**
* select submenu
*
* @param [event :
* javascript event] event triggered by selecting submenu
* @param [submenu :
* HTML element] current submenu element
*/
selectSubmenu : function(event, submenu) {
var selectedEntry = $(submenu).find('li.selected');
var menuLink = $(submenu).closest('div').parent();
// update the link icon
menuLink.find('img').first().attr('src', selectedEntry.find('img').attr('src'));
// switch selection
selectedEntry.switchSelected(menuLink);
selectedEntry.closest('div').toggle();
menuLink.removeClass('inactive');
// resort the menu entries
var selEntry = selectedEntry.clone();
var otherEntries = selectedEntry.siblings().clone();
var menu_ul = selectedEntry.parent();
menu_ul.empty();
menu_ul.append(selEntry);
menu_ul.append(otherEntries);
event.stopPropagation();
},
/**
* called by time input element to set time
*
* @param [timebox :
* HTML element] current time input element.
*/
setTime : function(timebox) {
PM.blockUI = true;
$(document).off("keydown", '*');
$(document).on("keydown", '*', {
timebox : $(timebox)
}, timeBoxKeydownHandler);
var hour = $(timebox).find('span.hour');
var minute = $(timebox).find('span.minute');
var suffix = $(timebox).find('span.suffix');
// init timebox
if (isNaN(parseInt(hour.text(), 10))) {
if ($(timebox).attr('cdptimemode') == '24h') {
hour.text('00');
} else {
hour.text('12');
}
}
if (isNaN(parseInt(minute.text(), 10))) {
minute.text('00');
}
// end init
if ((!hour.hasClass('adjustment')) && (!minute.hasClass('adjustment'))) {
hour.addClass('adjustment');
} else {
if (hour.hasClass('adjustment')) {
hour.removeClass('adjustment');
minute.addClass('adjustment');
} else {
$(timebox).find('input').val(hour.text() + ':' + minute.text() + suffix.text());
minute.removeClass('adjustment');
PM.blockUI = false;
$(document).off("keydown", '*');
}
}
},
/**
* called by the timeBoxKeydownHandler to count up the time
*
* @param [data :
* event data] contains current time input JQUERY element
*/
countUpTime : function(data) {
var adjustment = data.timebox.find('.adjustment');
var currentTime = parseInt(adjustment.text(), 10);
var timeMode = data.timebox.attr('cdptimemode');
if (isNaN(currentTime)) {
currentTime = 0;
} else {
if (adjustment.hasClass('hour')) {
if (timeMode == '24h') {
if (currentTime < 23) {
currentTime++;
} else {
currentTime = 0;
}
} else {
if (currentTime < 12) {
currentTime++;
if (currentTime == 12) {
if (data.timebox.find('.suffix').text() == 'am') {
data.timebox.find('.suffix').text('pm');
} else {
data.timebox.find('.suffix').text('am');
}
}
} else {
currentTime = 1;
}
}
} else {
if (currentTime < 59) {
currentTime++;
} else {
currentTime = 0;
}
}
}
if (currentTime < 10) {
currentTime = '0' + currentTime;
}
adjustment.text(currentTime);
},
/**
* called by the timeBoxKeydownHandler to count down the time
*
* @param [data :
* event data] contains current time input JQUERY element
*/
countDownTime : function(data) {
var adjustment = data.timebox.find('.adjustment');
var currentTime = parseInt(adjustment.text(), 10);
var timeMode = data.timebox.attr('cdptimemode');
if (isNaN(currentTime)) {
currentTime = 0;
} else {
if (adjustment.hasClass('hour')) {
if (timeMode == '24h') {
if (currentTime <= 0) {
currentTime = 23;
} else {
currentTime--;
}
} else {
if (currentTime <= 1) {
currentTime = 12;
} else {
currentTime--;
if (currentTime == 11) {
if (data.timebox.find('.suffix').text() == 'am') {
data.timebox.find('.suffix').text('pm');
} else {
data.timebox.find('.suffix').text('am');
}
}
}
}
} else {
if (currentTime <= 0) {
currentTime = 59;
} else {
currentTime--;
}
}
}
if (currentTime < 10) {
currentTime = '0' + currentTime;
}
adjustment.text(currentTime);
},
/**
* called to release focus during time setting
*
* @param [timebox :
* HTML element] current time input element.
*/
releaseTimeFocus : function(data) {
var hour = data.timebox.find('.hour');
var minute = data.timebox.find('.minute');
var suffix = data.timebox.find('.suffix');
data.timebox.find('input').val(hour.text() + ':' + minute.text() + suffix.text());
data.timebox.find('span').removeClass('adjustment');
PM.blockUI = false;
$(document).off("keydown", '*');
},
/**
* Show an existing panel. If the panel with the given id could not be found in the current DOM, the paramter url
* and options will be used to load a new one.
*
* @param [url:string]
* The relative or absolute URL for the new panel.
* @param [options:map]
* A set of key/value pairs, which configure the loading.
*/
show : function(panelId, url, options) {
PM.showScroller = true; // must be set every time, maybe last panel has
// changed the value
if ("GenericPanelProgress" == panelId) {
this.showLoadIndicator(true);
return;
} else {
this.showLoadIndicator(false);
}
if (this.visiblePanel && this.visiblePanel.attr('id') == panelId) {
// currentPanel has same id
return;
}
// close the toolbat menu if it has been opened
if (this.visiblePanel && this.visiblePanel.find('.submenu:visible')) {
LOG.info('show() -> closing toolbar menu');
PM.closeToolbarMenu();
}
var newPanel = this.holder.find('#' + panelId);
if (!newPanel.length && url != undefined && url != null) {
// panel not found, maybe it is dynamic and must be loaded.
this.load(panelId, url, options);
return;
} else {
// for detail panels set the scroll buttons
if (newPanel.is('.detailPanel')) {
// add textToSpeech button if there are divs with class tts, not for RSE or NBT_ASN
var ua = PM.getUserAgent();
if (ua != undefined
&& (ua.indexOf(';tts;') > -1 || ua.indexOf('Firefox') > -1 || ua.indexOf('Chrome') > -1)) {
if (newPanel.find('div.tts').length != 0 && !newPanel.find('li.textToSpeech').length) {
newPanel
.find('.toolbar')
.append(
'
');
}
});
}
if (Config.homemarket !== undefined) {
PM.setSpeedlockClass(newPanel, Config.homemarket);
}
}
// first make visible, then set scrollButtons inactive, if the content fits into the viewport
this.changeVisiblePanel(newPanel);
if (newPanel.find('li.scrollUp').length) {
if (newPanel.outerHeight() <= newPanel.getViewportHeight()) {
newPanel.find('li.scrollUp').addClass('inactive');
newPanel.find('li.scrollDown').addClass('inactive');
}
}
if (!newPanel.attr('isCutted')) {
this.cutPoiListText();
this.cutTitleText();
newPanel.attr('isCutted', true);
}
}
},
startDrivingLockedTimer : function() {
if (!(PM.getUserAgent().indexOf('NBT_RSE;') > -1) && !Timers['checkMovingInterval']) {
// start drivingLock mechanismus for all user-agents, except NBT RSE, check every 2s
Timers['checkMovingInterval'] = window.setInterval(function() {
PM.checkMoving();
}, 2000);
}
},
stopDrivingLockedTimer : function() {
window.clearInterval(Timers['checkMovingInterval']);
Timers['checkMovingInterval'] = undefined;
},
/**
* Cuts the texts of poilist items dynamically according to the size of the distance String on the right.
*/
cutPoiListText : function() {
$('.visible .poiListItem').each(function() {
var limitedText = $(this).find('.limited');
var rightText = $(this).find('.right');
if (rightText.length) {
var rightWidth = rightText.outerWidth();
limitedText.width(limitedText.width() - rightWidth);
}
PM.cutTextForElement(limitedText);
});
},
/**
* Cuts the text of the header title according to the size of an existing providerlogo and/or toolbar icons.
*/
cutTitleText : function() {
var title = $('.visible.detailPanel .header .title, .visible.panel > .header .title');
var providerLogo = $('.visible.detailPanel .header .providerlogo, .visible.panel > .header .providerlogo');
var toolbar = $('.visible.detailPanel .header .toolbar, .visible.panel > .header .toolbar');
var icon = $('.visible.detailPanel .header .icon, .visible.panel > .header .icon');
var offset = 0;
if ($('.visible .header').parents('.detailPanel').length) {
offset = 71;
}
var usedWidth = 0;
if (providerLogo.length) {
usedWidth = providerLogo.outerWidth();
}
if (toolbar.length) {
usedWidth += toolbar.outerWidth();
}
if (icon.length) {
usedWidth += icon.outerWidth() + 10;
}
title.width(title.width() - usedWidth - offset);
PM.cutTextForElement(title);
},
cutTextForElement : function(element) {
try {
if (!$('#tempText').length) {
$('body').append('');
}
var tempDiv = $('#tempText');
var text = element.text();
tempDiv.text(text);
var elewidth = element.width();
var testwidth = tempDiv.width();
if (testwidth > elewidth) {
do {
var textlen = text.length;
var newlen = textlen;
text = text.slice(0, newlen - 1);
tempDiv.text(text);
elewidth = element.width();
testwidth = tempDiv.width() + 30;
} while (testwidth > elewidth);
element.text(text + '…');
}
} catch (e) {
LOG.error(e);
}
},
/**
* A EFIHelper.js function for setting a destination in the navigation system will be called.
*
* @param lat:long
* The latitude in WGS84.
* @param lon:long
* The longitude in WGS84.
* @param descr:string
* The description of the destination, which will be displayed in the navigation system.
*/
startNavigation : function(lat, lon, descr) {
EFIHelper.setDestWGS84(function(efiData) {
if (efiData.ACK) {
LOG.info('navigation destination was set ' + lat + ', ' + lon);
} else {
PM.showError(Error.SetDestinationFailed);
}
}, lat, lon, descr);
},
/**
* A EFIHelper.js function for starting a phone call will be called.
*
* @param number:string
* The phone number.
*/
makeVoiceCall : function(number) {
EFIHelper.makeVoiceCall(function(efiData) {
if (efiData.ACK) {
LOG.info('number was called.');
} else {
PM.showError(Error.MakeVoiceCallFailed);
}
}, number);
},
/**
* start vehicle's internet browser by calling the EFIHepler.
*
* @param url:string
* Url of the page to be loaded in the browser.
*/
loadInternet : function(url) {
url = encodeURIComponent(url);
EFIHelper.startBIN(function(efiData) {
if (efiData.ACK) {
LOG.info('BIN was started.');
} else {
PM.showError(Error.BINCouldNotStarted);
}
}, url);
},
/**
* execute the click action of the current li element, if available. If the element has the class inactive, the
* action will not be called.
*/
execute : function() {
var selected = this.visiblePanel.find('li.selected');
if (selected.length && selected.click && !selected.is('.inactive')
&& (selected.isTopVisible() || selected.isBottomVisible())) {
if (PM.visiblePanel.is('.restorePosition')) {
SM.setSession('LastUsedElement', selected.index());
}
selected.click();
}
},
/**
* Show the last previous panel in the panel history (see PM.show). If the last element of the panel
* history has been reached, the previous URL in the browser's history list will be called.
*/
back : function() {
// close the toolbar menu if it exists
if (PM.visiblePanel != null && PM.visiblePanel.find('.submenu:visible').length) {
LOG.info('back() -> closing toolbar menu');
PM.closeToolbarMenu();
return;
}
LOG.info('back() -> stack = ' + PM.stack.length);
if (PM.stack.length < 1) {
window.history.back();
return;
}
var panelId = PM.visiblePanel.attr('id');
if (PM.stack.length == 1 && panelId == PM.stack[0].split('::')[0]) {
// errors without showing a warning panel is needed, for catching ajax call
PM.isLoadPageCalled = true;
// first panel, so do history back
window.history.back();
return;
}
if (PM.stack.length >= 1 && panelId != PM.stack[PM.stack.length - 1].split('::')[0]) {
LOG.info("Current panel is not the same as the last panel of the stack.");
this.loadPanelWithHash(PM.stack[PM.stack.length - 1]);
} else if (PM.stack.length > 1) {
// remove last inserted
PM.stack.pop();
this.loadPanelWithHash(PM.stack[PM.stack.length - 1]);
}
if (PM.stack.length == 1) {
PM.setStartPageDisplayed(true);
}
PM.showHistoryHashmark();
},
scrollUpPage : function() {
if (this.visiblePanel.length) {
for ( var i = 0; i < Config.scrollPageRowsCount; i++) {
this.visiblePanel.scrollUp();
}
}
},
scrollDownPage : function() {
if (this.visiblePanel.length) {
for ( var i = 0; i < Config.scrollPageRowsCount; i++) {
this.visiblePanel.scrollDown();
}
}
},
scrollUp : function() {
if (this.visiblePanel.length) {
this.visiblePanel.scrollUp();
}
},
scrollDown : function() {
if (this.visiblePanel.length) {
this.visiblePanel.scrollDown();
}
},
/**
* With the function the current visible panel will be scanned for div elements with the css class tts
* and the header with the css class header if there div elements with class tts, the
* content of them will be used to call the TTS.read(...) function.
*/
readPage : function() {
var header = this.visiblePanel.find('.content div.ttsheader');
if (!header.length) {
header = this.visiblePanel.find('.content div.header');
}
header = header.text();
var text = "";
this.visiblePanel.find('.content div.tts').each(function() {
text += $(this).text() + " \r\n\r\n";
});
LOG.info('start reading');
TTS.read('', header, text);
},
/**
* If nothing is selected already, the first interaction element (e.g. link, thumbnail or smartcursor) of the
* current visible panel will be selected and focused.
If there are no interaction elements in the
* content area, the first toolbar element will be selected.
*/
setVisibleSelectedElement : function() {
var lastUsedElement = -1;
var visibleNode = PM.visiblePanel.find('li.selected');
if (!visibleNode.length) {
if (PM.visiblePanel.is('.detailPanel')) {
visibleNode = PM.visiblePanel.find('.toolbar li:visible').first();
} else {
lastUsedElement = SM.getSession('LastUsedElement');
if (lastUsedElement != null && PM.visiblePanel.is('.restorePosition')
&& $(PM.visiblePanel.find('.content li')[lastUsedElement]).is(':actionElement')) {
visibleNode = $(PM.visiblePanel.find('.content li')[lastUsedElement]);
} else {
lastUsedElement = -1;
visibleNode = PM.visiblePanel.find('.content li:actionElement:first');
if (!visibleNode.length) {
visibleNode = PM.visiblePanel.find('li:actionElement:first');
if (!visibleNode.length) {
visibleNode = PM.visiblePanel.find('li:noActionElement:first');
}
}
}
}
}
if (visibleNode.length) {
visibleNode.addClass('selected');
if (lastUsedElement > -1) {
PM.visiblePanel.setScrollHeight(visibleNode.position().top - 120);
}
visibleNode.focus();
}
},
changeVisiblePanel : function(newPanel) {
LOG.info('new visible panel: ' + newPanel.attr('id'));
Geocoder.updateSelectPlaceLink();
if (!newPanel.is('.nohistory')) {
this.addHistory(newPanel);
}
if (this.visiblePanel != null) {
// onfocus input fields
this.visiblePanel.find('.input').blur();
// remove tooltips
$('[id^="Tooltip_"]').remove();
this.visiblePanel.removeClass('visible');
// do not close browser, if back button will be pressed
PM.setStartPageDisplayed(false);
}
newPanel.addClass('visible');
this.visiblePanel = newPanel;
this.setVisibleSelectedElement();
if (this.visiblePanel.is('[action]')) {
// panel has a action, so call it
eval(this.visiblePanel.attr('action'));
}
// set the speechcontrol for new visible panel.
SpeechControl.init();
newPanel.setScroller();
if (newPanel.is('#GenericPanelMoving, .drivingLocked, .scrollingLocked, .contentLocked, .textLocked')) {
PM.startDrivingLockedTimer();
} else {
PM.stopDrivingLockedTimer();
}
},
toggleRadioButton : function(element, group) {
element = $(element);
var parent = element.parent();
if (!element.is('.checked')) {
if (parent.find('.checked.' + group).length) {
parent.find('.checked.' + group).removeClass('checked');
}
element.addClass('checked');
// save value in input field
$('#' + group).val(element.attr('cdpValue'));
}
},
toggleCheckbox : function(element, group) {
element = $(element);
element.toggleClass('checked');
// save value in input field
var values = "";
$('.checked.' + group).each(function(key, value) {
value = $(value);
LOG.info(value.attr('cdpValue'));
if (values.length > 0) {
values += ',';
}
values += value.attr('cdpValue');
});
$('#' + group).val(values);
},
toggleSmartcursor : function(element, smartCursorClass) {
element = $(element);
var parent = element.parent();
if (element.is('.activated')) {
parent.find('li.SC.' + smartCursorClass).addClass('hidden');
element.removeClass('activated');
// add the bottom class, if there was set one before toggling
if (element.is('.no_bottom')) {
element.removeClass('no_bottom');
element.addClass('bottom');
}
} else {
parent.find('li.SC').addClass('hidden');
parent.find('li.SC.' + smartCursorClass).removeClass('hidden');
parent.find('li.activated').removeClass('activated');
element.addClass('activated');
// if bottom separator exists, so add it to the last element of the smartcursor content and remove it from
// itself.
if (element.is('.bottom')) {
parent.find('li.SC.' + smartCursorClass).last().addClass('bottom');
element.removeClass('bottom');
element.addClass('no_bottom'); // for restoring
}
}
// if height of panel is now smaller then viewport, so scroll it to zero. maybe some of the top content could be
// cut off.
if (this.visiblePanel.outerHeight() <= this.visiblePanel.getViewportHeight()) {
this.visiblePanel.setScrollHeight(0);
}
// scroll to the selected smartCursor
this.visiblePanel.setScrollHeight(element.offset().top + this.visiblePanel.getScrollHeight()
- Config.scrollHeight * 2);
},
toggleDropdown : function(element) {
element = $(element);
$('#GenericTemp').html(element.find('.options').html());
$('#GenericTemp').attr('cdpReturnPanel', element.parents('.panel').attr('id'));
this.show("GenericTemp");
},
changeDropdownValue : function(element, inputID) {
element = $(element);
$('#' + inputID).val(element.attr('cdpValue'));
$('#' + inputID).prev().html(element.text());
PM.show($('#GenericTemp').attr('cdpReturnPanel'));
},
toggleDetailLink : function(element) {
// FIXME: Falsches Verhalten wenn selektiertund dann das Panel verlassen und wieder geoeffnet wird.
element = $(element);
element.find('div.itemDetailContent').toggle(0);
},
disableScroller : function() {
PM.showScroller = false;
$('#ScrollerNotVisible').hide();
$('#ScrollerVisible').hide();
$('#Scroller').hide();
},
/**
* @param id:string
* @param url:string
*/
addHistory : function(panelObject) {
// if last panel is the same, regenerate the hash. Maybe the location mode has changed.
if(PM.stack.length > 0 && PM.stack[PM.stack.length - 1].split('::')[0] == panelObject.attr('id')){
PM.stack[PM.stack.length - 1] = this.generateHashMark(panelObject);
}
if (PM.stack.length == 0 || PM.stack[PM.stack.length - 1].split('::')[0] != panelObject.attr('id')) {
PM.stack.push(this.generateHashMark(panelObject));
}
PM.showHistoryHashmark();
},
generateHashMark : function(panelObject) {
var id = panelObject.attr('id');
var url = panelObject.attr('cdpURL');
var mode = panelObject.attr('cdpMode');
if (!url) {
url = '';
}
if (!mode) {
mode = '';
if (Geocoder.locationType()) {
mode = Geocoder.locationType();
}
}
return id + '::' + encodeURI(url) + '::' + mode;
},
resetHistory : function() {
PM.stack = new Array();
PM.showHistoryHashmark();
},
showHistoryHashmark : function() {
var hashmark = '';
$.each(PM.stack, function(index) {
// only add if url is defined.
var hashmarkBlock = this.toString();
if (hashmarkBlock.split('::').length > 0 && hashmarkBlock.split('::')[1].length > 0) {
hashmark += hashmarkBlock;
hashmark += '||';
}
});
hashmark = hashmark.slice(0, hashmark.length - 2);
window.location.replace('#' + hashmark);
},
getHash : function() {
var hash = window.location.hash;
if (hash) {
hash = hash.substring(1);
}
return hash;
},
getUrlWithCurrentParams : function(url) {
var params = document.location.search;
if (params.indexOf('?') == 0) {
if (url.indexOf('?') > -1) {
url += "&" + params.substring(1);
} else {
url += params;
}
}
return url;
},
isNotExpired : function(lastTimestamp, maxAgeInSeconds) {
return (this.now() - lastTimestamp) < (maxAgeInSeconds * 1000);
},
now : function() {
return (new Date()).getTime();
},
/**
* Submits the given formular to the given targetUrl. The resulting panel will have the given panelId.
*/
submit : function(panelId, targetUrl, formular, options) {
var data = $(formular).find('input,textarea')
.filter('[cdpTransportMethod = "GET"], :not([cdpTransportMethod])').serialize();
var postData = $(formular).find('input,textarea').filter('[cdpTransportMethod = "POST"]').serialize();
if (postData.length > 0) {
options = $.extend({
'postData' : postData
}, options);
}
if (targetUrl.indexOf('?') > -1) {
targetUrl = targetUrl + "&" + data;
} else {
targetUrl = targetUrl + "?" + data;
}
PM.load(panelId, targetUrl, options);
return false;
},
/**
* test if current locale has been changed
*/
isLocaleChanged : function(locale) {
var currentLocale = PM.getUserAgent().split(';', 7)[6];
return (locale != currentLocale);
},
checkMoving : function() {
EFIHelper
.getCarStatus(function(efiData) {
if (efiData.data.status) {
// car is now moving
if (PM.visiblePanel.is('.drivingLocked')) {
PM.lastLockedPanel = PM.visiblePanel;
var content = '';
if (!$('#GenericPanelMoving').length) {
content += '
'));
}
if (firstText.height() > 132) {// more than three lines
firstText.css('height', '131px');// set height of three lines
firstText.css('overflow', 'hidden');
}
if (PM.visiblePanel.find('.right').length) {
firstText.css('width', '480px');
}
// disabling scrolling
PM.visiblePanel.find('.scrollUp, .scrollDown').addClass('inactive').attr('title',
I18N.get('errorMoving'));
}
} else if (efiData.data.status != PM.lastMovingStatus) {
// car is now staying and last status was moving.
if (PM.lastLockedPanel) {
// hide
PM.back();
PM.lastLockedPanel = undefined;
}
if (PM.visiblePanel.is('.scrollingLocked') || PM.visiblePanel.is('.contentLocked')
|| PM.visiblePanel.is('.textLocked')) {
// enable scrolling
if (PM.visiblePanel.find('li.scrollUp').length) {
if (PM.visiblePanel.outerHeight() > PM.visiblePanel.getViewportHeight()) {
PM.visiblePanel.find('.scrollUp, .scrollDown').removeClass('inactive');
}
PM.visiblePanel.find('.scrollUp, .scrollDown').attr('title', null);
}
PM.visiblePanel.setScroller();
}
if (PM.visiblePanel.is('.contentLocked')) {
PM.visiblePanel.find('.content div.lockMsg').remove();
PM.visiblePanel.find('.content div.text.hidden,.right.hidden').removeClass('hidden');
$('#Scroller').show();
PM.visiblePanel.setScroller();
}
if (PM.visiblePanel.is('.textLocked')) {
PM.visiblePanel.find('.content div.abbr').removeClass('abbr').css('overflow', '').css(
'height', '');
PM.visiblePanel.find('.content div.ellipsis').remove();
PM.visiblePanel.find('.content div.text.hidden').removeClass('hidden');
$('#Scroller').show();
PM.visiblePanel.setScroller();
}
}
// store current status
PM.lastMovingStatus = efiData.data.status;
});
},
/**
* Set speedlock class to the detailPanel
*
* @param [panel :
* object] [homemarket : String] current home market according to this the css class will be added to the
* panel
*/
setSpeedlockClass : function(panel, homemarket) {
if (Config.speedlockPanelSetting.lockedScrolling.indexOf(homemarket) != -1) {
panel.addClass('scrollingLocked');
} else if (Config.speedlockPanelSetting.lockedContent.indexOf(homemarket) != -1) {
panel.addClass('contentLocked');
} else if (Config.speedlockPanelSetting.lockedText.indexOf(homemarket) != -1) {
panel.addClass('textLocked');
}
}
};
$.extend($.expr[':'], {
actionElement : function(element) {
element = $(element);
if (!element.is(':visible')) {
return false;
}
if (!element.is('[onclick], .input, .thumbnail')) {
return false;
}
return true;
},
noActionElement : function(element) {
element = $(element);
if (!element.is(':visible')) {
return false;
}
if (element.is(':not([onclick], .input, .thumbnail)')) {
return true;
}
return false;
},
topVisible : function(element) {
element = $(element);
return element.isTopVisible();
},
bottomVisible : function(element) {
element = $(element);
return element.isBottomVisible();
},
});
(function($) {
/**
* Scroll up a list panel or detailPanel. detailPanel
*/
$.fn.scrollUp = function() {
if (this.is('.detailPanel')) {
var button = this.find('li.selected');
if (button.length) {
if (button.is('.scrollUp')) {
if (this.is('.scrollingLocked') && PM.lastMovingStatus) {
// exit, if car is moving
return this;
}
this.removeScrollHeight();
} else {
var prev = button.prevAll("li").first();
button.switchSelected(prev);
}
}
}
if (this.is('.panel')) {
var selected = this.find('li.selected');
if (!selected.length) {
var toolbar = this.find('.toolbar');
if (toolbar) {
selected.switchSelected(toolbar.find('li').last());
}
// no element, but scroll nevertheless
this.removeScrollHeight();
} else {
// first visible action element
var prev = selected.prevVisibleActionElement();
if (prev.length) {
selected.switchSelected(prev);
// scrolling if bottom of view is reached, plus offset
if (!prev.isTopVisible(-Config.scrollHeight)) {
this.removeScrollHeight();
}
} else {
if (this.getScrollHeight() == 0 && !selected.parents('.toolbar').length) {
var toolbar = selected.parents('.visible').find('.toolbar');
if (toolbar.length) {
selected.switchSelected(toolbar.find('li:visible:last'));
}
}
this.removeScrollHeight();
if (!(selected.is(':actionElement') && selected.isBottomVisible(-Config.scrollHeight * 2))) {
var prevActionElement = selected.prevAll('li:actionElement:first');
if (prevActionElement.length && prevActionElement.isTopVisible(Config.scrollHeight)) {
prev = prevActionElement;
} else {
// last visible no action Element if scrolling is possible
if (PM.visiblePanel.getScrollHeight() > 0) {
prev = selected.prevAll('li:noActionElement:bottomVisible:last');
}
}
if (prev.length) {
selected.switchSelected(prev);
}
}
}
}
}
return this;
};
/**
* scroll down a panel or detailPanel
*/
$.fn.scrollDown = function() {
if (this.is('.detailPanel')) {
var button = this.find('li.selected');
if (button.length && button.is('.scrollDown')) {
if (this.is('.scrollingLocked') && PM.lastMovingStatus) {
// exit, if car is moving
return this;
}
this.addScrollHeight();
}
var next = button.nextAll("li").first();
button.switchSelected(next);
}
if (this.is('.panel')) {
var selected = this.find('li.selected');
if (!selected.length) {
// no element, but scroll nevertheless
this.addScrollHeight();
} else {
// if the selected element is the last element in the toolbar, so select the first element in the
// content block
if (selected.parent().is('.toolbar')) {
if (selected.next().length) {
selected.switchSelected(selected.next());
} else {
var contentBlock = selected.parents('.panel').find('ul.content');
if (contentBlock.find('li').is('[onclick]')
|| contentBlock.outerHeight() > this.getViewportHeight()) {
var newItem = contentBlock.find('li:first');
selected.switchSelected(newItem);
// call method again, if the element has no click action and there is a further element
if (!newItem.is('[onclick]') && newItem.next().length) {
this.scrollDown();
}
}
}
return this;
}
// first visible action element
var next = selected.nextVisibleActionElement();
if (next.length) {
selected.switchSelected(next);
// scrolling if bottom of view is reached, plus offset
if (!next.isBottomVisible(-Config.scrollHeight)) {
this.addScrollHeight();
}
} else {
this.addScrollHeight();
if (!(selected.is(':actionElement') && selected.isTopVisible(-Config.scrollHeight))) {
var nextActionElement = selected.nextAll('li:actionElement:first');
if (nextActionElement.length && nextActionElement.isBottomVisible(Config.scrollHeight)) {
next = nextActionElement;
} else {
// last visible no action Element
next = selected.nextAll('li:noActionElement:topVisible:last');
}
if (next.length) {
selected.switchSelected(next);
}
}
}
}
}
return this;
};
$.fn.nextVisibleActionElement = function() {
var next = this.next();
if (next.is(':not(:visible)')) {
return next.nextVisibleActionElement();
}
if (next.is(':topVisible') && next.is(':bottomVisible')) {
if (next.is(':actionElement')) {
return next;
} else {
return next.nextVisibleActionElement();
}
}
return [];
};
$.fn.prevVisibleActionElement = function() {
var prev = this.prev();
if (prev.is(':not(:visible)')) {
return prev.prevVisibleActionElement();
}
if (prev.is(':topVisible') && prev.is(':bottomVisible')) {
if (prev.is(':actionElement')) {
return prev;
} else {
return prev.prevVisibleActionElement();
}
}
return [];
};
/**
* @return the value of the attribute scrollHeight of the current element. if not found or not parseable zero will
* be returned.
*/
$.fn.getScrollHeight = function() {
var content = this.find('.content');
var scrollHeight = content.attr('scrollHeight');
return scrollHeight ? parseInt(scrollHeight) : 0;
};
$.fn.addScrollHeight = function() {
this.setScrollHeight(this.getScrollHeight() + Config.scrollHeight);
return this;
};
$.fn.removeScrollHeight = function() {
this.setScrollHeight(this.getScrollHeight() - Config.scrollHeight);
return this;
};
/**
* @param scrollHeight:int
* positive int value of new absolute scrollHeight
*/
$.fn.setScrollHeight = function(scrollHeight) {
if (scrollHeight != this.getScrollHeight()) {
var content = this.find('.content');
if (scrollHeight <= 0) {
// if it was scrolled up to much, then limit the top margin
scrollHeight = 0;
} else {
// if it was scrolled down to much, then limit the scrollHeight
var outerHeight = content.outerHeight();
if (outerHeight - scrollHeight < PM.visiblePanel.getViewportHeight()) {
scrollHeight = outerHeight - PM.visiblePanel.getViewportHeight();
}
}
// store the new scrollHeight and scroll
content.attr('scrollHeight', scrollHeight);
if (Config.firefoxMode) {
content.css('-moz-transform', 'translate(0, -' + scrollHeight + 'px)');
} else {
content.css('-webkit-transform', 'translate(0, -' + scrollHeight + 'px)');
}
}
this.setScroller();
return this;
};
/**
* Sets the right scroller to the correct position. height of scroll graphic: 416px. top-offset for graphic: 0px.
* height of screen: 420px; when the page is 4 times the screen height, scroller should have 100px => divide by
* 16800.
*/
$.fn.setScroller = function() {
// show page position in the browser
try {
idrivePlugin.setPagingPosition(0, 0);
} catch (e) {
}
if (PM.showScroller) {
var percentage = 0; // percentage value of the scroller position
var panel = PM.visiblePanel;
var contentheight = panel.outerHeight();
var viewportHeight = panel.getViewportHeight();
var topUnvisible = panel.getScrollHeight();
var bottomUnvisible = contentheight - (viewportHeight + topUnvisible);
if (panel.is('.detailPanel')) {
bottomUnvisible += Config.viewportTop;
}
if (topUnvisible == 0) {
precentage = 0;
} else if ((bottomUnvisible - Config.viewportTop) == 0) {
percentage = 100;
} else {
percentage = Math.round(topUnvisible / (topUnvisible + bottomUnvisible) * 100);
}
if (contentheight <= 420) {
$('#ScrollerNotVisible').show();
$('#ScrollerVisible').hide();
$('#Scroller').hide();
} else {
$('#ScrollerNotVisible').hide();
$('#ScrollerVisible').show();
$('#Scroller').show();
}
if (percentage < 0) {
percentage = 0;
}
if (percentage > 100) {
percentage = 100;
}
if (panel.is('.detailPanel') && contentheight > viewportHeight) {
if (percentage == 0) {
panel.find('li.scrollUp').addClass('inactive');
panel.find('li.scrollDown').removeClass('inactive');
} else if (percentage < 100) {
panel.find('li.scrollUp').removeClass('inactive');
panel.find('li.scrollDown').removeClass('inactive');
} else if (percentage == 100) {
panel.find('li.scrollUp').removeClass('inactive');
panel.find('li.scrollDown').addClass('inactive');
}
}
scrollerheight = Math.round(168000 / contentheight);
if (percentage < 100) {
percentage = Math.round(percentage * (416 - scrollerheight) / 100.0) + 7 /* offset */;
} else {
percentage = Math.round(percentage * (416 - scrollerheight) / 100.0);
}
if (scrollerheight + percentage > 416) { /* height+offset */
scrollerheight = 416 - percentage;
}
$("#Scroller").css('top', percentage + 'px');
$("#Scroller").css('background-position', '0px -' + percentage + 'px');
$("#Scroller").css('height', scrollerheight);
}
return this;
};
/**
* get the viewport height of a panel. if header is set, so reduce the viewport height
*/
$.fn.getViewportHeight = function() {
if (this.is('.panel') && this.children('div.header').length) {
return Config.viewportHeight - Config.viewportTop;
}
return Config.viewportHeight;
};
/**
* get the viewport top of a panel.
*
* @returns 0, if no header is set, else the configured viewportTop
*/
$.fn.getViewportTop = function() {
if (this.is('.panel') && this.children('div.header').length) {
return Config.viewportTop;
}
return 0;
};
/**
* This method is only for UI list elements of a panel. Retunrs true, if the top of the element can be seen.
*
* @param offset:int
* this is optional, use this, if you want to know the position moving the element up for the amount of
* given offset pixels.
*/
$.fn.isTopVisible = function(offset) {
var isVisible = false;
if (this.is('li')) {
if (this.parents('.toolbar').length) {
return true;
} else {
if (offset === undefined) {
offset = 0;
}
if (Config.firefoxMode && navigator.userAgent.indexOf('Firefox/8') > -1) {
offset -= PM.visiblePanel.getScrollHeight();
}
var item = this;
var top = item.offset().top + offset;
var panel = PM.visiblePanel;
var viewportTop = panel.getViewportTop();
var viewportHeight = panel.getViewportHeight() + viewportTop;
isVisible = top >= viewportTop && top <= viewportHeight;
}
}
return isVisible;
};
/**
* This method is only for UI list elements of a panel. Retunrs true, if the bottom of the element can be seen.
*
* @param offset:int
* this is optional, use this, if you want to know the position moving the element down for the amount of
* given offset pixels.
*/
$.fn.isBottomVisible = function(offset) {
var isVisible = false;
if (this.is('li')) {
if (this.parents('.toolbar').length) {
return true;
} else {
if (offset === undefined) {
offset = 0;
}
if (Config.firefoxMode && navigator.userAgent.indexOf('Firefox/8') > -1) {
offset += PM.visiblePanel.getScrollHeight();
}
var item = this;
var bottom = item.offset().top + item.outerHeight() - offset;
var panel = PM.visiblePanel;
var viewportTop = panel.getViewportTop();
var viewportHeight = panel.getViewportHeight() + viewportTop;
isVisible = bottom >= viewportTop && bottom <= viewportHeight;
}
}
return isVisible;
};
/**
* removes the class selected of the current element and calls the blur-event, if an element is given. To the given
* element the class selected will be added and the focus-event will be called.
*
* @param element:JQUERY
* the new selected element
*/
$.fn.switchSelected = function(element) {
if (element.length) {
// blur all visible input/textarea fields
PM.visiblePanel.find('input, textarea').blur();
var current = this;
current.removeClass('selected');
element.addClass('selected');
current.blur();
element.focus();
// remove tooltips and timer function
if (element.parent().is('.toolbar')) {
$('[id^="Tooltip_"]').remove();
if (Timers['TooltipOn']) {
window.clearTimeout(Timers['TooltipOn']);
Timers['Tooltip'] = undefined;
}
if (Timers['TooltipOff']) {
window.clearTimeout(Timers['TooltipOff']);
Timers['TooltipOff'] = undefined;
}
}
// show tooltips
if ((element.is('.scrollUp, .scrollDown') || element.not('.inactive').parent().is('.toolbar'))
&& element.attr('title') != undefined) {
var pos = element.position();
var id = 'Tooltip_' + PM.visiblePanel.attr('id') + parseInt(pos.top) + 'x' + parseInt(pos.left);
var tooltip = '
' + element.attr('title') + '
';
$('#Main').append(tooltip);
Timers['TooltipOn'] = window.setTimeout("$('#" + id + "').toggle(0);", 500);
Timers['TooltipOff'] = window.setTimeout("$('#" + id + "').toggle(0);", 3000);
}
}
return this;
};
})(jQuery);
/**
* For the current visible panel all element with class speech will be used to initialize the
* speechcontrol plugin.
*/
var SpeechControl = {
actions : new Array(),
init : function() {
LOG.info("SpeechControl.init()");
if (PM.visiblePanel != null) {
SpeechControl.actions = new Array();
var actionLinks = PM.visiblePanel.find('.speech');
var text = "";
var locales = "";
var phonemTypes = "";
var functions = "";
if (actionLinks.length) {
try {
$.each(actionLinks, function(index, element) {
element = $(element);
SpeechControl.actions[index] = element.attr('onclick');
text += element.text() + ';';
functions += 'speechAction_' + index + ';';
locales += PM.locale + ";";
phonemTypes += "NONE;";
});
text = text.slice(0, text.length - 1);
functions = functions.slice(0, functions.length - 1);
locales = locales.slice(0, locales.length - 1);
phonemTypes = phonemTypes.slice(0, phonemTypes.length - 1);
var object = '';
var parent = $('body');
var plugin = document.getElementById("pl_speechcontrol");
if (plugin != null) {
parent.get(0).removeChild(plugin);
}
parent.append(object); // add plugin
LOG.info('speechcontrol-plugin added');
} catch (error) {
LOG.error('speechcontrol-plugin could not be initialized.');
}
}
}
}
};
var TTS = {
read : function(language, headline, textToSpeechText) {
LOG.info("TTS.read(): language=" + language);
var plugin = document.getElementById("pl_tts");
var parent = $('body');
if (plugin != null) {
parent.get(0).removeChild(plugin);
}
try {
var object = '';
parent.append(object); // add plugin
plugin = document.getElementById("pl_tts");
plugin.readout();
} catch (error) {
LOG.error('TTS-Plugin did not worked.');
}
}
};
/**
* Default GeoData Object
*/
var GeoData = function() {
this.lat = 0;
this.lon = 0;
this.city = '';
this.country = '';
this.locationType = 'cur';
this.isEmpty = function() {
return this.lat == 0 && this.lon == 0 && this.city == '' && this.country == '';
};
};
var GeocoderLastUsedPlaces = {
add : function(location) {
var data = GeocoderLastUsedPlaces.load();
$.each(data, function(index) {
if (this.city == location.city && this.country == location.country) {
data.splice(index, 1);
return false;
}
});
data.unshift(location);
if (data.length > 10) {
data.pop();
}
GeocoderLastUsedPlaces.store(data);
},
load : function() {
var data = null;
try {
data = localStorage.getItem('GeocoderLastuSedPlaces');
data = JSON.parse(data);
} catch (e) {
}
if (data == null) {
data = new Array();
}
return data;
},
store : function(arrayList) {
localStorage.setItem('GeocoderLastuSedPlaces', JSON.stringify(arrayList));
},
};
/**
* TODO comment Use Geocoder.loadPanel(panelId, url), if you want to load a panel with current and destination
* coordinates. The geocoder servlet will be called and the response has a redirect with the correct coordinates or a
* panel with the found results.
*/
var Geocoder = {
currentPanelId : undefined,// PanelId, which has open the selectPlace dialog
targetAfterUpdate : undefined, // json for storing the target panel. will be used if the position of the mode is
// not stored and must be retrieved before loading the panel.
updateTimer : undefined,
init : function() {
// first time refresh.
if (Config.geocoderEnabled) {
Geocoder.refreshCurrentOrDestination();
}
},
startUpdateTimer : function() {
if (Config.geocoderEnabled && Geocoder.updateTimer == undefined) {
LOG.info('start geocoder update timer');
Geocoder.updateTimer = window.setInterval(function() {
Geocoder.refreshCurrentOrDestination();
}, Config.geocoderUpdateInterval);
}
},
stopUpdateTimer : function() {
if (Geocoder.updateTimer) {
LOG.info('stop geocoder update timer');
window.clearInterval(Geocoder.updateTimer);
Geocoder.updateTimer = undefined;
}
},
refreshCurrentOrDestination : function() {
Geocoder.stopUpdateTimer();
var type = Geocoder.locationType();
if (type == 'cur') {
Geocoder.loadPos({
indicator : false,
doNotShowNoPositionError : true,
errorCallback : $.noop(),
maxResults : 1
});
} else if (type == 'dest') {
Geocoder.loadDest({
indicator : false,
doNotShowNoPositionError : true,
errorCallback : $.noop(),
maxResults : 1
});
}
},
/**
* The select place overview panel will be shown. All the other panels for other place selection will be generated.
* No backend call is necessary. The list for the available countries in the other place panel can be configured
* with Config.geocoderSupportedCountries.
*/
showGeocoder : function() {
// stop timer
Geocoder.stopUpdateTimer();
Geocoder.currentPanelId = PM.visiblePanel.attr('id');
// cleanup
$('#GeocoderOverview').remove();
$('#GeocoderSelectPlace').remove();
var ua = PM.getUserAgent();
var geocoderPanel = '
';
// ----- Other Place Input Panel ----
var lastUsedCountry = Geocoder.position().country;
var lastUsedCountryName = Geocoder.position().country;
var otherPlacePanel = '
'
+ I18N.get('geocoderOtherLocation')
+ '
';
PM.holder.append(geocoderPanel);
PM.holder.append(otherPlacePanel);
PM.show('GeocoderOverview');
},
/**
* get(or set) location type from (into) session storage
*
* @param [newtype]
* new location type, if null then read it from session storage
*/
locationType : function(newType) {
if (!newType) {
newType = sessionStorage.getItem('GeocoderLocationType');
if (!newType) {
newType = 'cur';
}
return newType;
} else {
sessionStorage.setItem('GeocoderLocationType', newType);
}
},
/**
* get(or set) geo data from (into) html5 storage
*
* @param [geoData]
* object contains some geo data, if null then read it from session storage
*/
position : function(geoData) {
if (!geoData) {
// load data with stored locationType
return Geocoder.positionByLocationType(Geocoder.locationType());
} else {
// parse data
var geoDataString = geoData;
if (typeof geoData == 'object') {
geoDataString = JSON.stringify(geoData);
} else {
geoData = $.parseJSON(geoDataString);
}
// store locationType, if no targetAfterUpdate is defined
if (!Geocoder.targetAfterUpdate) {
Geocoder.locationType(geoData.locationType);
}
// store data for locationType
localStorage.setItem('StoredGeoData_' + geoData.locationType, geoDataString);
// store history entry
if (geoData.locationType == 'other') {
GeocoderLastUsedPlaces.add(geoData);
}
}
},
positionByLocationType : function(locationType) {
try {
geoData = JSON.parse(localStorage.getItem('StoredGeoData_' + locationType));
} catch (e) {
}
geoData = $.extend(new GeoData, geoData);
if (!geoData) {
return new GeoData();
}
return geoData;
},
/**
* The new location will be stored in the localStorage and the locationType will be set.
*
* @param geoData
* @returns {Boolean}
*/
update : function(geoData) {
try {
if (typeof geoData != 'object') {
geoData = $.parseJSON(geoData);
}
// store data
Geocoder.position(geoData);
// panel was load with specific mode
if (Geocoder.targetAfterUpdate) {
var target = Geocoder.targetAfterUpdate;
Geocoder.targetAfterUpdate = undefined;
PM.load(target.id, target.url, target.options);
return true;
}
if (Geocoder.currentPanelId) {
// show lastPanel
PM.show(Geocoder.currentPanelId);
Geocoder.currentPanelId = undefined;
if (PM.visiblePanel && PM.visiblePanel.is('.updateByGeocoder')) {
PM.load(PM.visiblePanel.attr('id'), PM.visiblePanel.attr('cdpURL'), {
geocoder : 'modus'
});
}
} else {
// resfresh selectPlace Link
Geocoder.updateSelectPlaceLink();
}
} catch (e) {
LOG.error(e.message);
}
if ($('.visible#GeocoderResult').length) {
PM.back();
}
// start timer again
Geocoder.startUpdateTimer();
return false;
},
/**
* this will be called, if the panel will be made visible.
*
* @param panel:JQUERY
*/
updateSelectPlaceLink : function() {
var type = Geocoder.locationType();
var geoData = Geocoder.position();
var iconClass = 'location_current';
if (type == 'other') {
iconClass = 'location_other';
} else if (type == 'dest') {
iconClass = 'location_destination';
}
var selectPlace = $('.panel').find('.selectPlace');
if (selectPlace.length) {
if (!geoData.city) {
geoData.city = I18N.get('geocoderSelectPlace');
}
selectPlace.attr('onclick', 'Geocoder.showGeocoder();');
selectPlace.attr('onfocus', 'Geocoder.focusSelectPlace(this)');
selectPlace.attr('onblur', 'Geocoder.blurSelectPlace(this)');
selectPlace.each(function() {
var item = $(this);
if (item.is('.update') || item.text().length == 0) {
$(this).html('
' + geoData.city + '
');
}
});
$('.selectPlace.selected').focus();
}
var selectPlace = $('.detailPanel').find('.selectPlace');
if (selectPlace.length) {
selectPlace.html('');
selectPlace.attr('onclick', 'Geocoder.showGeocoder();');
selectPlace.attr('title', I18N.get('geocoderSelectPlace'));
}
},
focusSelectPlace : function(element) {
element = $(element).find('div div:not(.icon)');
var text = $.trim(element.text());
if (text.slice(text.length - 2) != ' ?') {
element.text($.trim(text) + ' ?');
}
},
blurSelectPlace : function(element) {
element = $(element).find('div div:not(.icon)');
var text = $.trim(element.text());
if (text.slice(text.length - 2) == ' ?') {
element.text(text.slice(0, text.length - 2));
}
},
/**
* This is the submit function for the search other place formular. The city and country value will be retrieved and
* the geocoder servlet will be called.
*/
submitOtherPlace : function() {
var geoData = new GeoData();
geoData.city = $('#GeocoderCity').val();
geoData.country = $('#GeocoderCountry').val();
geoData.locationType = 'other';
Geocoder.loadPanel('GeocoderResult', Config.geocoderUrl, {}, geoData);
return false;
},
/**
* if no geoData is given, the geoData will be loaded from the localStorage depnending on the current location mode.
* The URL will be extended with the geoData values.
*
* @param panelId
* @param url
* @param options
* @param [geoData]
*/
loadPanel : function(panelId, url, options, geoData) {
options = $.extend({}, options);
options.originalUrl = url;
if (!geoData) {
geoData = Geocoder.position();
}
if (url.indexOf('?') > -1) {
url += '&';
} else {
url += '?';
}
url += 'lat=' + geoData.lat;
url += '&lon=' + geoData.lon;
if (geoData.city) {
url += '&city=' + encodeURIComponent(geoData.city);
}
if (geoData.country) {
url += '&country=' + encodeURIComponent(geoData.country);
}
url += '&locationType=' + encodeURIComponent(geoData.locationType);
options.geoData = geoData;
PM.load(panelId, url, options);
},
/**
* This will be called from the PanelManager to add the correct coordinates to the request URL.
*
* @see PM.load()
* @param panelId
* @param url
* @param options
*/
loadPanelWithCoordinates : function(panelId, url, options) {
options = $.extend({}, options);
// for compatibility: geocoder = true will be changed to 'mode'
if (options.geocoder == true) {
options.geocoder = 'modus';
}
var geoOpt = options.geocoder;
options.geocoder = false;
var geoData = undefined;
LOG.info('loadPanel with coordinates [' + geoOpt + ']');
switch (geoOpt) {
case 'modus':
geoData = Geocoder.position();
break;
case 'navi':
Geocoder.loadPosAndDest(panelId, url, options);
return;
default:
// pos, dest or other
geoData = Geocoder.positionByLocationType(geoOpt);
}
if (geoData.isEmpty() || options.useNewestCoordinate) {
if (geoData.isEmpty()) {
if (options.useNewestCoordinate) {
geoOpt = 'dest';
} else {
geoOpt = 'cur';
}
}
var tempOptions = {};
if (options.doNotShowNoPositionError) {
tempOptions = $.extend(tempOptions, {
doNotShowNoPositionError : true
});
}
var targetOptions = options;
targetOptions.geocoder = geoOpt;
targetOptions.useNewestCoordinate = false;
Geocoder.targetAfterUpdate = {
id : panelId,
url : url,
options : targetOptions
};
switch (geoOpt) {
case 'cur':
Geocoder.loadPos(tempOptions);
break;
case 'dest':
Geocoder.loadDest(tempOptions);
break;
case 'other':
Geocoder.showGeocoder();
PM.show('GeocoderSelectPlace');
break;
}
return;
}
Geocoder.loadPanel(panelId, url, options, geoData);
},
/**
* Call EFI and load the current position. The backend geocoder will be called to get the city and country value.
*/
loadPos : function(options) {
Geocoder.stopUpdateTimer();
options = $.extend({}, options);
EFIHelper
.getPosWGS84(function(efiData) {
if (Geocoder.responseHasCoordinates(efiData)) {
var geoData = new GeoData();
geoData.locationType = 'cur';
geoData.lat = Geocoder.convertWGS84ToDegree(efiData.data.lat);
geoData.lon = Geocoder.convertWGS84ToDegree(efiData.data.lon);
if (Geocoder.getDistance(Geocoder.positionByLocationType('cur'), geoData) > Config.geocoderUpdateDistance) {
var url = Config.geocoderUrl;
if (options.maxResults) {
url += '?maxResults=1';
}
Geocoder.loadPanel('GeocoderResult', url, options, geoData);
} else {
Geocoder.update(Geocoder.positionByLocationType('cur'));
}
} else {
if (!options.doNotShowNoPositionError) {
PM.showError(Error.NoPosition);
}
}
});
},
/**
* Call EFI and load the current destination. The backend geocoder will be called to get the city and country value.
*/
loadDest : function(options) {
Geocoder.stopUpdateTimer();
options = $.extend({}, options);
EFIHelper.getDestWGS84(function(efiData) {
if (Geocoder.responseHasCoordinates(efiData)) {
var geoData = new GeoData();
geoData.locationType = 'dest';
geoData.lat = Geocoder.convertWGS84ToDegree(efiData.data.lat);
geoData.lon = Geocoder.convertWGS84ToDegree(efiData.data.lon);
if (Geocoder.getDistance(Geocoder.positionByLocationType('dest'), geoData) > 500) {
var url = Config.geocoderUrl;
if (options.maxResults) {
url += '?maxResults=1';
}
Geocoder.loadPanel('GeocoderResult', url, options, geoData);
} else {
Geocoder.update(Geocoder.positionByLocationType('dest'));
}
} else {
if (!options.doNotShowNoPositionError) {
PM.showError(Error.NoDestination);
}
}
});
},
/**
* TODO The current and the destination coordinates will be added to the request.
*
* @param panelId:string
* @param url:string
* @param [options:map]
* A set of key/value pairs that configure the loading.
* @see PM.load(...)
*/
loadPosAndDest : function(panelId, url, options) {
EFIHelper.getPosWGS84(function(efiData) {
var curLat = Geocoder.convertWGS84ToDegree(efiData.data.lat);
var curLon = Geocoder.convertWGS84ToDegree(efiData.data.lon);
EFIHelper.getDestWGS84(function(efiData) {
var destLat = Geocoder.convertWGS84ToDegree(efiData.data.lat);
var destLon = Geocoder.convertWGS84ToDegree(efiData.data.lon);
if (url.indexOf('?') > -1) {
url += '&';
} else {
url += '?';
}
url += 'clat=' + curLat + '&clon=' + curLon + '&dlat=' + destLat + '&dlon=' + destLon;
PM.load(panelId, url, options);
});
});
},
responseHasCoordinates : function(efiData) {
return (efiData.data.lat > 0 || efiData.data.lon > 0);
},
/**
* calculates the distance between the start and end position in meters
*
* @param startPos:GeoData
* @param endPos:GeoData
*/
getDistance : function(startPos, endPos) {
var dLat = (endPos.lat - startPos.lat) / 180.0 * Math.PI;
var dLon = (endPos.lon - startPos.lon) / 180.0 * Math.PI;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos((startPos.lat) / 180.0 * Math.PI)
* Math.cos((endPos.lat) / 180.0 * Math.PI) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var distance = 6371000 * c;
if (distance >= Config.geocoderUpdateDistance) {
LOG.info('distance of locations is ' + distance + 'm.');
}
return distance;
},
/**
* Convert geo data from WGS84 representation into decimal representation. *
*
* @param value
* long value that represents the WGS84 Format to convert
* @return value in Degree
*/
convertWGS84ToDegree : function(value) {
if (isNaN(value)) {
return 0;
}
value = (value / (Math.pow(2, 32))) * 360;
value = value * 1000000;
value = Math.round(value);
value = value / 1000000;
return value;
},
/**
* @Convert geo data from decimal representation into WGS84 representation. *
* @param value
* double value that represents the degree to convert
* @return the value in WGS84
*
*/
convertDegreeToWGS84 : function(value) {
if (isNaN(value)) {
return 0;
}
return Math.round((value / (360)) * Math.pow(2, 32));
}
};
/**
* I18N - Translations
*/
var I18N = {
data : {},
/**
* This function search for the given key and returns the translation for the current locale.
*
* @param key
* @returns
*/
get : function(key) {
try {
return I18N.data[key];
} catch (e) {
return "";
}
},
/**
* This function will be called automatically, if the DOM was loaded.
*/
init : function() {
try {
I18N.data = i18nFallback;
} catch (e) {
}
var i18nJSON = localStorage.getItem('I18N');
if (i18nJSON != null && i18nJSON != '') {
I18N.postInit(i18nJSON);
try {
// check for current user-agent locale
I18N.update(PM.getUserAgent().split(';')[6]);
} catch (e) {
}
} else {
I18N.load(false);
}
},
load : function(async) {
$.ajax({
url : Config['i18nURL'],
type : 'GET',
async : async,
timeout : 30000,
success : function(i18nJSON) {
I18N.postInit(i18nJSON);
},
error : function() {
window.setTimeout(function() {
I18N.load(async);
}, 2000);
}
});
},
postInit : function(i18nJSON) {
try {
I18N.data = JSON.parse(i18nJSON);
localStorage.setItem('I18N', i18nJSON);
} catch (e) {
LOG.error('I18N json could not be parsed.');
}
$('title').text(I18N.get('pageTitle'));
},
/**
* This function will be called automatically, if a panel was loaded. If the locale differs from the stored locale,
* the i18n json will be refreshed from the backend.
*
* @param locale
*/
update : function(locale) {
if (I18N.get('locale') != locale) {
I18N.load(true);
}
}
};
/**
* This Object will be used to manage the last used Apps and to start them.
*/
var Favorites = {
startApp : function(element, targetUrl, appID) {
PM.loadPage(Favorites.addToListReturnTargetUrl(element, targetUrl, appID));
},
startExternalApp : function(element, targetUrl, appID) {
PM.load('ExternalApp', Favorites.addToListReturnTargetUrl(element, targetUrl, appID));
},
addToListReturnTargetUrl : function(element, targetUrl, appID) {
element = $(element);
Favorites.add($(element).find('div div').last().text(), $(element).find('img').attr('src'), targetUrl, appID);
if (Config['appIdentifier'] != 'Main') {
targetUrl = '../' + targetUrl;
}
return targetUrl;
},
show : function(element) {
var panel = '
'
+ $(element).find('div div').last().text()
+ '
';
var data = Favorites.load();
if (data && data.length > 0) {
for ( var i = 0; i < data.length; i++) {
panel += '
'
+ data[i]['name'] + '
';
}
}
panel += '
';
$('#Favorites').remove();
PM.holder.append(panel);
PM.show('Favorites');
},
remove : function(appID) {
var data = Favorites.load();
$.each(data, function(index) {
if (this.appID == appID) {
data.splice(index, 1);
return false;
}
});
Favorites.store(data);
},
add : function(name, iconUrl, targetUrl, appID) {
var data = Favorites.load();
$.each(data, function(index) {
if (this.targetUrl == targetUrl) {
data.splice(index, 1);
return false;
}
});
data.unshift({
name : name,
iconUrl : iconUrl,
targetUrl : targetUrl,
appID : appID
});
if (data.length > 6) {
data.pop();
}
Favorites.store(data);
},
load : function() {
var data = null;
try {
data = localStorage.getItem('FavoritesData');
data = JSON.parse(data);
} catch (e) {
}
if (data == null) {
data = new Array();
}
return data;
},
store : function(arrayList) {
localStorage.setItem('FavoritesData', JSON.stringify(arrayList));
},
};
/**
* Storage Manager
*/
var SM = {
getKey : function(key) {
return Config.appIdentifier + '::' + key;
},
loadPanel : function(panelId, options) {
LOG.info('Try to load panel from storage: ' + panelId);
var content = null;
if (options && options.localStorage) {
content = this.get(panelId);
} else {
content = this.getSession(panelId);
}
if (content != null
&& $(document.createElement('div')).append(content).children().first().attr('locale') == I18N
.get('locale')) {
// if not in background so remove first
if (!(options && options.background)) {
$('#' + panelId).remove();
}
PM.holder.append(content);
PM.show(panelId);
LOG.info('Panel \'' + panelId + '\'loaded from storage');
return true;
}
return false;
},
storePanel : function(panelId, options) {
var panel = $('#' + panelId);
var html = $(document.createElement("div")).append(panel.clone()).html();
if (options && options.localStorage) {
this.set(panelId, html);
} else {
this.setSession(panelId, html);
}
},
clearPanel : function(panelId) {
this.clear(panelId);
this.clearSession(panelId);
},
get : function(key) {
return localStorage.getItem(this.getKey(key));
},
set : function(key, value) {
return localStorage.setItem(this.getKey(key), value);
},
clear : function(key) {
LOG.info('SM.clear(\'' + key + '\');');
if (key == undefined) {
localStorage.clear();
} else {
localStorage.removeItem(this.getKey(key));
}
},
getSession : function(key) {
return sessionStorage.getItem(this.getKey(key));
},
setSession : function(key, value) {
return sessionStorage.setItem(this.getKey(key), value);
},
clearSession : function(key) {
if (key == undefined) {
sessionStorage.clear();
} else {
sessionStorage.removeItem(this.getKey(key));
}
},
/**
*
* @param [element]
*/
clearAll : function(element) {
if (element) {
element = $(element);
element.html('
' + element.text() + '
');
}
localStorage.clear();
sessionStorage.clear();
},
};
var MAP = {
Config : {
'width' : 420,
'height' : 360,
'GoogleOffset' : 268435456,
'zIndexInactive' : 260,// The z-Index of an inactive Pin/Marker;
'zIndexActive' : 261, // The z-Index of an active Pin/Marker
'maxZoomLevel' : 18,
'minZoomLevel' : 1
},
// the array of POIs which gets filled with lat, lon values
markers : new Array(),
// The array which contains the calculated coordinates of all POIs in pixels
generatedMarkers : new Array(),
zoom : 0, // gets calculated dynamically
pin_width : 47, // the width of a single pin in the sprite
pin_height : 75, // the height of a single pin in the sprite
page_offset_left : 0, // the left side of the screen is for text
page_offset_top : 0, // some space for the toolbar on top
initDetailMap : function() {
$('.visible .content').append(
'');
},
init : function(lat, lon) {
this.markers = new Array();
this.generatedMarkers = new Array();
this.zoom = 0;
if (!$('.visible .rightContent').length) {
$('.visible .contentContainer').before('');
$('.visible li.link').each(function(index) {
var element = $(this);
if (element.is('[cdplat]') && element.is('[cdplon]')) {
// number of all links without coordinates
// before the first link with coordinates
var noCoordLinks = $('.visible li[cdpLon].link:first').prev().length;
index -= noCoordLinks;
MAP.markers.push([ element.attr('cdplat'), element.attr('cdplon') ]);
element.on("focus", function() {
var marker = $('.visible .marker_' + index);
var height = -(index + 1) * 150 + 75;
marker.css('backgroundPosition', '0px ' + height + 'px');
marker.css('z-index', MAP.Config['zIndexActive']);
});
element.on("blur", function() {
var marker = $('.visible .marker_' + index);
var height = -(index) * 150;
marker.css('backgroundPosition', '0px ' + height + 'px');
marker.css('z-index', MAP.Config['zIndexInactive']);
});
}
});
this.generateMapOverlays(lat, lon);
$('.visible li.selected').focus();
}
},
calculateZoomLevel : function() {
var minlat = Number.MAX_VALUE;
var maxlat = 0;
var minlng = Number.MAX_VALUE;
var maxlng = 0;
var mapdisplay = Math.min(this.Config['width'], this.Config['height']);
var interval = 0;
// calculate min and max values
for ( var i = 0; i < this.markers.length; i++) {
if ((this.markers[i][0] != undefined) && (this.markers[i][0] != "")
&& (Number(this.markers[i][0]) != Number.NaN) && (this.markers[i][1] != undefined)
&& (this.markers[i][1] != "") && (Number(this.markers[i][1]) != Number.NaN)) {
// get min and max markers as absolute values otherwise negative coordinates are causing a wrong
// zoomlevel
minlat = Math.min(minlat, Math.abs(this.markers[i][0]));
maxlat = Math.max(maxlat, Math.abs(this.markers[i][0]));
minlng = Math.min(minlng, Math.abs(this.markers[i][1]));
maxlng = Math.max(maxlng, Math.abs(this.markers[i][1]));
}
var latBuffer = ((maxlat - minlat) * 0.1) / 2;
var lngBuffer = ((maxlng - minlng) * 0.1) / 2;
var minLatNew = (minlat + latBuffer);
var maxLatNew = (maxlat + latBuffer);
var minLngNew = (minlng + lngBuffer);
var maxLngNew = (maxlng + lngBuffer);
maxlat = maxLatNew;
maxlng = maxLngNew;
minlat = minLatNew;
minlng = minLngNew;
}
var ctrlat = minlat + ((maxlat - minlat) / 2);
var ctrlng = minlng + ((maxlng - minlng) / 2);
if ((maxlat - minlat) > (maxlng - minlng)) {
interval = (maxlat - minlat) / 2;
minlng = ctrlng - interval;
maxlng = ctrlng + interval;
} else {
interval = (maxlng - minlng) / 2;
minlat = ctrlat - interval;
maxlat = ctrlat + interval;
}
// if a position of a poi is exactly the same or too close to the car's position, a buffer is used to avoid a
// wrong zoom level
if (minlat == maxlat) {
maxlat += (maxlat / 1000);
}
if (minlng == maxlng) {
maxlng += (maxlng / 1000);
}
var dist = (6371 * Math.acos(Math.sin(minlat / 57.2958)
* Math.sin(maxlat / 57.2958)
+ (Math.cos(minlat / 57.2958) * Math.cos(maxlat / 57.2958) * Math.cos((maxlng / 57.2958)
- (minlng / 57.2958)))));
this.zoom = Math
.floor(8 - Math.log(1.6446 * dist * 2 / Math.sqrt(2 * (mapdisplay * mapdisplay))) / Math.log(2));
},
/**
* Here the zoom level for the Google Map gets calculated
*/
adjustZoomLevel : function(lat, lon) {
center_offset_x = Math.floor(this.Config['width'] / 2);
center_offset_y = Math.floor(this.Config['height'] / 2);
center_x = this.LonToX(lon);
center_y = this.LatToY(lat);
this.fitPinsIntoMap(center_x, center_y, center_offset_x, center_offset_y);
for ( var i = 0; i < this.generatedMarkers.length; i++) {
var zoomLevelIsOk = false;
while (!zoomLevelIsOk) {
if ((this.generatedMarkers[i][0] < (this.page_offset_left)
|| (this.generatedMarkers[i][1] < (this.page_offset_top - (this.pin_height / 2)))
|| (this.generatedMarkers[i][0] > (this.page_offset_left + (this.Config['width'] - this.pin_width))) || (this.generatedMarkers[i][1] > (this.page_offset_top
+ this.Config['height'] - this.pin_height)))) {
this.zoom -= 1;
this.fitPinsIntoMap(center_x, center_y, center_offset_x, center_offset_y);
} else {
zoomLevelIsOk = true;
}
}
}
},
fitPinsIntoMap : function(center_x, center_y, center_offset_x, center_offset_y) {
for ( var index = 0; index < this.markers.length; ++index) {
target_y = this.LatToY(this.markers[index][0]);
target_x = this.LonToX(this.markers[index][1]);
delta_x = (target_x - center_x) >> (21 - this.zoom);
delta_y = (target_y - center_y) >> (21 - this.zoom);
marker_offset_x = center_offset_x + delta_x - Math.round(this.pin_width / 2);
marker_offset_y = center_offset_y + delta_y - Math.round(this.pin_height);
this.generatedMarkers[index] = new Array(this.page_offset_left + marker_offset_x, this.page_offset_top
+ marker_offset_y);
}
},
getMapImageUrl : function(center) {
var imageUrl = "http://maps.google.com/maps/api/staticmap" + "?center=" + center + "&zoom=" + this.zoom
+ "&size=" + this.Config['width'] + "x" + this.Config['height'] + "&mobile=true" + "&maptype=mobile"
+ "&sensor=true";
if (Config['imageURL']) {
imageUrl = Config['imageURL'] + "?url=" + encodeURIComponent(imageUrl + "&client=auto-bmw");
imageUrl += "&output=jpeg&compression=5&progressive=true";
}
return imageUrl;
},
generateMapOverlays : function(lat, lon) {
// Set center coordinates as pixel coordinates in world map
center = lat + "," + lon;
center_x = this.LonToX(lon);
center_y = this.LatToY(lat);
if (this.markers.length > 0) {
this.calculateZoomLevel();
this.adjustZoomLevel(lat, lon);
} else {
// No POIs found. Setting default zoomlevel to 9.
this.zoom = 9;
}
var url = this.getMapImageUrl(center);
center_offset_x = Math.floor(this.Config['width'] / 2);
center_offset_y = Math.floor(this.Config['height'] / 2);
this.createMap("map", url, this.Config['width'], this.Config['height'], this.page_offset_left,
this.page_offset_top);
for ( var index = 0, len = this.markers.length; index < len; ++index) {
this.createMarker("marker_" + index, "0px -" + (index * (this.pin_height * 2)) + "px", this.pin_width,
this.pin_height, this.generatedMarkers[index][0], this.generatedMarkers[index][1]);
}
this.createCurrentMarker();
},
createMap : function(id, url, width, height, left, top) {
var newdiv = document.createElement('div');
newdiv.setAttribute('id', id);
newdiv.style.width = width + "px";
newdiv.style.height = height + "px";
newdiv.style.padding = 0 + "px";
newdiv.style.margin = 0 + "px";
newdiv.style.left = left + "px";
newdiv.style.top = top + "px";
newdiv.style.background = "transparent";
newdiv.innerHTML = '';
$('.visible .rightContent').append(newdiv);
},
createMarker : function(id, position, width, height, left, top) {
var newdiv = document.createElement('div');
newdiv.style.backgroundPosition = position;
newdiv.className = "mapMarker " + id;
newdiv.style.zIndex = MAP.Config['zIndexInactive'];
newdiv.style.width = width + "px";
newdiv.style.height = height + "px";
newdiv.style.position = 'absolute';
newdiv.style.padding = 0;
newdiv.style.margin = 0;
newdiv.style.left = left + "px";
newdiv.style.top = top + "px";
$('.visible .rightContent').append(newdiv);
},
createCurrentMarker : function() {
var newdiv = document.createElement('div');
newdiv.setAttribute('id', 'currentPosition');
newdiv.style.backgroundRepeat = "no-repeat";
var locationType = Geocoder.locationType();
if ('other' == locationType) {
newdiv.className = "mapMarker other";
} else if ('dest' == locationType) {
newdiv.className = "mapMarker destination";
} else {
newdiv.className = "mapMarker current";
}
newdiv.style.zIndex = MAP.Config['zIndexActive'] - 2;
newdiv.style.width = "48px";
newdiv.style.height = "48px";
newdiv.style.position = 'absolute';
newdiv.style.padding = 0;
newdiv.style.margin = 0;
newdiv.style.left = (this.Config['width'] / 2 - 24) + "px";
newdiv.style.top = (this.Config['height'] / 2 - 24) + "px";
$('.visible .rightContent').append(newdiv);
},
LonToX : function(lon) {
radius = this.Config['GoogleOffset'] / Math.PI;
return Math.floor(this.Config['GoogleOffset'] + radius * lon * Math.PI / 180);
},
LatToY : function(lat) {
radius = this.Config['GoogleOffset'] / Math.PI;
return Math.floor(this.Config['GoogleOffset'] - radius
* Math.log((1 + Math.sin(lat * Math.PI / 180)) / (1 - Math.sin(lat * Math.PI / 180))) / 2);
},
XToLon : function(x) {
radius = this.Config['GoogleOffset'] / Math.PI;
return ((Math.floor(x) - this.Config['GoogleOffset']) / radius) * 180 / Math.PI;
},
YToLat : function(y) {
radius = this.Config['GoogleOffset'] / Math.PI;
return (Math.PI / 2 - 2 * Math.atan(Math.exp((Math.floor(y) - this.Config['GoogleOffset']) / radius))) * 180
/ Math.PI;
},
adjustLonByPixels : function(lon, delta, zoom) {
return XToLon(LonToX(lon) + (delta << (21 - zoom)));
},
adjustLatByPixels : function(lat, delta, zoom) {
return YToLat(LatToY(lat) + (delta << (21 - zoom)));
},
zoomIn : function() {
var map = PM.visiblePanel.find('img#Map' + PM.visiblePanel.attr('id'));
if (map.length) {
var src = map.attr('src');
var currZoom = src.match(/zoom%3D(.*)%26size/)[1];
if (currZoom == this.Config.maxZoomLevel) {
return false;
}
var zoomInButton = PM.visiblePanel.find('li.zoomIn');
var zoomOutButton = PM.visiblePanel.find('li.zoomOut');
var newZoom = parseInt(currZoom) + 1;
var newSrc = null;
if (newZoom >= this.Config.maxZoomLevel) {
newSrc = src
.replace(/zoom%3D(.*)%26size/, 'zoom%3D'.concat(this.Config.maxZoomLevel).concat('%26size'));
zoomInButton.addClass('inactive');
zoomOutButton.removeClass('inactive');
} else {
newSrc = src.replace(/zoom%3D(.*)%26size/, 'zoom%3D'.concat(newZoom).concat('%26size'));
zoomInButton.removeClass('inactive');
zoomOutButton.removeClass('inactive');
}
PM.showLoadIndicator(true);
PM.setLoadIndicator(true);
$('.visible .content').find('img[id^="MapMapPanel"]').one('load', function() {
PM.showLoadIndicator(false);
PM.setLoadIndicator(false);
});
map.attr('src', newSrc);
}
},
zoomOut : function() {
var map = PM.visiblePanel.find('img#Map' + PM.visiblePanel.attr('id'));
if (map.length) {
var src = map.attr('src');
var currZoom = src.match(/zoom%3D(.*)%26size/)[1];
if (currZoom == this.Config.minZoomLevel) {
return;
}
var zoomInButton = PM.visiblePanel.find('li.zoomIn');
var zoomOutButton = PM.visiblePanel.find('li.zoomOut');
var newZoom = parseInt(currZoom) - 1;
var newSrc = null;
if (newZoom <= this.Config.minZoomLevel) {
newSrc = src
.replace(/zoom%3D(.*)%26size/, 'zoom%3D'.concat(this.Config.minZoomLevel).concat('%26size'));
zoomInButton.removeClass('inactive');
zoomOutButton.addClass('inactive');
} else {
newSrc = src.replace(/zoom%3D(.*)%26size/, 'zoom%3D'.concat(newZoom).concat('%26size'));
zoomInButton.removeClass('inactive');
zoomOutButton.removeClass('inactive');
}
PM.showLoadIndicator(true);
PM.setLoadIndicator(true);
$('.visible .content').find('img[id^="MapMapPanel"]').one('load', function() {
PM.showLoadIndicator(false);
PM.setLoadIndicator(false);
});
map.attr('src', newSrc);
}
}
};
/**
* Constants
*/
var EFIerrors = {
"NO_NAVIGATION" : "100_NO_NAVIGATION",
"NO_TELESERVICES" : "101_NO_TELESERVICES",
"NO_GPS" : "102_NO_GPS",
"NO_TV" : "103_NO_TV",
"NO_PHONE" : "104_NO_PHONE",
"NO_BMW_INTERNET" : "105_NO_BMW_INTERNET",
"NO_DESTINATION" : "200_NO_DESTINATION"
};
/**
* Response object of the EFIHelper, which will be given to the defined callback functions.
*/
var EFIData = function(_ack, _detail, _data) {
this.ACK = _ack;
this.DETAIL = _detail;
this.data = _data;
};
/**
* This is the Wrapper for the EFI Plugin of the vehicle Browser.use
*
* @author Edmund Hierlemann, doubleslash
* @author Thomas Stadlander, Cirquent
*/
var EFIHelper = {
plugin : null, // holder for the found plugin
testMode : false, // for test in desktop browser
callbackFunction : null, // call this function after getting efi response
retryTime : 0, // retry times of calling function getPosWGS84
init : function() {
// Check if EFIPluginSimulator is available
if (typeof EFIPluginSimulator != 'undefined') {
this.plugin = new EFIPluginSimulator();
LOG.info('EFIHelper Simulator.');
this.testMode = true;
} else {
this.plugin = document.getElementById("harmanEfiplugin");
if (this.plugin != null) {
LOG.info('EFIHelper plugin found.');
} else {
LOG.error('EFIHelper plugin not found.');
}
}
LOG.info('EFIHelper is initialized.');
},
getPosCallback : function(_responseObject) {
LOG.info('getPosCallback of EFIHelper');
var efiData = new EFIData();
efiData.ACK = _responseObject.ACK;
efiData.DETAIL = _responseObject.DETAIL;
efiData.data = {};
if (_responseObject !== undefined && _responseObject.data !== undefined && efiData.ACK == true) {
var d = _responseObject.data;
var retryDelay = Math.ceil(Math.random() * 2000);
if (d.posLong != 0 && d.posLong != 2147483647) {
efiData.data["lon"] = d.posLong;
} else {
if (EFIHelper.retryTime < 3) {
EFIHelper.retryTime++;
LOG.info('-> Retrying ' + EFIHelper.retryTime
+ ' times to call EFIHelper.getPosWGS84 with delay of ' + retryDelay);
window.setTimeout(function() {
EFIHelper.getPosWGS84(EFIHelper.posCallbackFunction);
}, retryDelay);
return;
}
}
if (d.posLat != 0 && d.posLat != 2147483647) {
efiData.data["lat"] = d.posLat;
} else {
if (EFIHelper.retryTime < 3) {
EFIHelper.retryTime++;
LOG.info('-> Retrying ' + EFIHelper.retryTime + ' times to call EFIHelper.getPosWGS84');
window.setTimeout(function() {
EFIHelper.getPosWGS84(EFIHelper.posCallbackFunction);
}, retryDelay);
return;
}
}
} else {
if (EFIHelper.retryTime < 3) {
EFIHelper.retryTime++;
LOG.info('-> Retrying ' + EFIHelper.retryTime + ' times to call EFIHelper.getPosWGS84');
EFIHelper.getPosWGS84(EFIHelper.posCallbackFunction);
return;
}
}
if (EFIHelper.retryTime >= 3) {
efiData.data["lon"] = 0;
efiData.data["lat"] = 0;
}
EFIHelper.retryTime = 0;
EFIHelper.posCallbackFunction(efiData);
Geocoder.startUpdateTimer();
},
genericCallback : function(_responseObject) {
LOG.info('genericCallback of EFIHelper');
var efiData = new EFIData();
efiData.ACK = _responseObject.ACK;
efiData.DETAIL = _responseObject.DETAIL;
efiData.data = {};
if (_responseObject !== undefined && _responseObject.data !== undefined && efiData.ACK == true) {
var d = _responseObject.data;
if (d.settings !== undefined) {
efiData.data["settings"] = d.settings;
}
if (d.tsType !== undefined) {
efiData.data["tsType"] = d.tsType;
}
if (d.destLong !== undefined) {
efiData.data["lon"] = d.destLong;
}
if (d.destLat !== undefined) {
efiData.data["lat"] = d.destLat;
}
if (d.destDescr !== undefined) {
efiData.data["desc"] = d.destDescr;
}
if (d.type !== undefined) {
efiData.data["type"] = d.type;
}
if (d.posLong !== undefined) {
efiData.data["lon"] = d.posLong;
}
if (d.posLat !== undefined) {
efiData.data["lat"] = d.posLat;
}
if (d.range !== undefined) {
efiData.data["range"] = d.range;
}
if (d.unit !== undefined) {
efiData.data["unit"] = d.unit;
}
if (d.country !== undefined) {
efiData.data["country"] = d.country;
}
if (d.town !== undefined) {
efiData.data["town"] = d.town;
}
if (d.street !== undefined) {
efiData.data["street"] = d.street;
}
if (d.number !== undefined) {
efiData.data["number"] = d.number;
}
if (d.crossing !== undefined) {
efiData.data["crossing"] = d.crossing;
}
if (d.status !== undefined) {
efiData.data["status"] = d.status;
}
}
EFIHelper.callbackFunction(efiData);
Geocoder.startUpdateTimer();
},
startTeleserviceCall : function(_callback, _tsType) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.startTeleserviceCall(this.genericCallback, _tsType);
},
setDestWGS84 : function(_callback, _destLat, _destLong, _destDescr) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.setDestWGS84(this.genericCallback, _destLong, _destLat, _destDescr);
},
getArrivalTime : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getArrivalTime(this.genericCallback);
},
getAudioSource : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getAudioSource(this.genericCallback);
},
getCarSettings : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getCarSettings(this.genericCallback);
},
getCarStatus : function(_callback) {
Geocoder.stopUpdateTimer();
this.savedCarStatusCallback = _callback;
this.plugin.getCarStatus(this.genericCallbackCarStatus);
},
savedCarStatusCallback : null,
genericCallbackCarStatus : function(_responseObject) {
LOG.info('genericCallbackCarStatus of EFIHelper');
var efiData = new EFIData();
efiData.ACK = _responseObject.ACK;
efiData.DETAIL = _responseObject.DETAIL;
efiData.data = {};
if (_responseObject !== undefined && _responseObject.data !== undefined && efiData.ACK == true) {
var d = _responseObject.data;
if (d.status !== undefined) {
efiData.data["status"] = d.status;
}
}
EFIHelper.savedCarStatusCallback(efiData);
Geocoder.startUpdateTimer();
},
getCoDriver : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getCoDriver(this.genericCallback);
},
getCruisingRange : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getCruisingRange(this.genericCallback);
},
getDestWGS84 : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getDestWGS84(this.genericCallback);
},
getDistanceToDestination : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getDistanceToDestination(this.genericCallback);
},
getDrivingDirection : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getDrivingDirection(this.genericCallback);
},
getFuelType : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getFuelType(this.genericCallback);
},
getJourneyComputerData : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getJourneyComputerData(this.genericCallback);
},
getKilometerStatus : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getKilometerStatus(this.genericCallback);
},
getPhoneStatus : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getPhoneStatus(this.genericCallback);
},
getPosAdr : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getPosAdr(this.genericCallback);
},
posCallbackFunction : null,
getPosWGS84 : function(_callback) {
Geocoder.stopUpdateTimer();
this.posCallbackFunction = _callback;
this.plugin.getPosWGS84(this.getPosCallback);
},
getRadioStation : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getRadioStation(this.genericCallback);
},
getTVStation : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getTVStation(this.genericCallback);
},
getUserAgent : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getUserAgent(this.genericCallback);
},
getVersion : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.getVersion(this.genericCallback);
},
goHome : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.goHome(this.genericCallback);
},
makeVoiceCall : function(_callback, _phoneNumber) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.makeVoiceCall(this.genericCallback, _phoneNumber);
},
sendToAddress : function(_callback) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.sendToAddress(this.genericCallback);
},
setHome : function(_callback, _homeURL) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.setHome(this.genericCallback, _homeURL);
},
setVINRN : function(_callback, _VINRN) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.setVINRN(this.genericCallback, _VINRN);
},
startBIN : function(_callback, _url) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.startBIN(this.genericCallback, _url);
},
/**
* _authLevel = 1: do authentication only if necessary _authLevel = 2: ask for password; current user will be
* displayed _authLevel = 3: ask for user and password
*/
doUSSOauth : function(_callback, _authLevel) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
var level = parseInt(_authLevel);
if (isNaN(level) || level < 1 || level > 3) {
level = 3; // default
}
this.plugin.doUSSOauth(this.genericCallback, level);
},
naviTripImport : function(_callback, _importUrl, _descr, _filesize) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.naviTripImport(this.genericCallback, _importUrl, _descr, _filesize);
},
PIAExport : function(_callback, PIAIDListStream, PIAIDListFlag, uploadProfileURL) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.piaExport(this.genericCallback, PIAIDListStream, PIAIDListFlag, uploadProfileURL);
},
PIAImport : function(_callback, downloadProfileURL) {
Geocoder.stopUpdateTimer();
this.callbackFunction = _callback;
this.plugin.piaImport(this.genericCallback, downloadProfileURL);
},
exitBrowser : function(obj) {
this.plugin.exitBrowser(obj);
},
/**
* trace-functions used to create HU-logs
*
* @param msg
* message to be logged
*/
traceMessage : function(msg) {
this.plugin.traceMessage(msg);
},
traceWarning : function(msg) {
this.plugin.traceWarning(msg);
},
traceError : function(msg) {
this.plugin.traceError(msg);
},
traceFatalError : function(msg) {
this.plugin.traceFatalError(msg);
}
};
String.prototype.hashCode = function() {
var hash = 0;
if (this.length == 0)
return hash;
for ( var i = 0; i < this.length; i++) {
c = this.charCodeAt(i);
hash = ((hash << 5) - hash) + c;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
};
/**
* Logger. Usage: LOG.error('LOG started.'); LOG.info('LOG started.');
*/
var LOG = {
error : function(text) {
var logEntry = LOG.generateLogEntry(text);
if (typeof EFIHelper != "undefined" && logEntry != undefined) {
try {
EFIHelper.traceError(logEntry);
} catch (e) {
// if the EFI-function not exists, do nothing
}
}
},
info : function(text) {
var logEntry = LOG.generateLogEntry(text);
if (typeof EFIHelper != "undefined" && logEntry != undefined) {
try {
EFIHelper.traceMessage(logEntry);
} catch (e) {
// if the EFI-function not exists, do nothing
}
}
},
warn : function(text) {
var logEntry = LOG.generateLogEntry(text);
if (typeof EFIHelper != "undefined" && logEntry != undefined) {
try {
EFIHelper.traceWarning(logEntry);
} catch (e) {
// if the EFI-function not exists, do nothing
}
}
},
fatalError : function(text) {
var logEntry = LOG.generateLogEntry(text);
if (typeof EFIHelper != "undefined" && logEntry != undefined) {
try {
EFIHelper.traceFatalError(logEntry);
} catch (e) {
// if the EFI-function not exists, do nothing
}
}
},
generateLogEntry : function(text) {
if (typeof text != 'object' && typeof Config != "undefined") {
return '[' + Config.appIdentifier + '] ' + text;
} else {
LOG.error('unable to generate the log entry!');
return null;
}
}
};
// all following functions are needed for the speechcontrol plugin.
function speechAction_0() {
eval(SpeechControl.actions[0]);
}
function speechAction_1() {
eval(SpeechControl.actions[1]);
}
function speechAction_2() {
eval(SpeechControl.actions[2]);
}
function speechAction_3() {
eval(SpeechControl.actions[3]);
}
function speechAction_4() {
eval(SpeechControl.actions[4]);
}
function speechAction_5() {
eval(SpeechControl.actions[5]);
}
function speechAction_6() {
eval(SpeechControl.actions[6]);
}
function speechAction_7() {
eval(SpeechControl.actions[7]);
}
function speechAction_8() {
eval(SpeechControl.actions[8]);
}
function speechAction_9() {
eval(SpeechControl.actions[9]);
}