/** * 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 += '
'; content += '
'; content += '
'; content += '
'; content += '
'; content += '
'; 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( '
  • '); newPanel.find('.textToSpeech').attr('title', I18N.get('readOut')); } } // add scroll buttons if (!newPanel.is('.fix') && !newPanel.find('li.scrollUp').length) { newPanel .find('.toolbar') .each( function() { if (!$(this).hasClass('submenu')) { $(this) .prepend( ''); $(this) .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 += '
    '; content += '
    '; PM.holder.append(content); } PM.changeVisiblePanel($('#GenericPanelMoving')); } if (PM.visiblePanel.is('.scrollingLocked')) { // disabling scrolling PM.visiblePanel.find('.scrollUp, .scrollDown').addClass('inactive').attr('title', I18N.get('errorMoving')); } if (PM.visiblePanel.is('.contentLocked') && !PM.visiblePanel.find('div.lockMsg').length) { // locking content PM.scrollUpPage(); $('#Scroller').hide(); PM.visiblePanel.find('.content div.text,.right').not('.ttsheader, .bottom').addClass( 'hidden'); var content = '
    '; content += I18N.get('errorMoving'); content += '
    '; PM.visiblePanel.find('.content').append(content); // disabling scrolling PM.visiblePanel.find('.scrollUp, .scrollDown').addClass('inactive').attr('title', I18N.get('errorMoving')); } if (PM.visiblePanel.is('.textLocked') && !PM.visiblePanel.find('div.ellipsis').length) { // locking text content PM.scrollUpPage(); $('#Scroller').hide(); PM.visiblePanel.find('.content div.text').not('.ttsheader, .bottom').addClass('hidden'); var firstText = $(PM.visiblePanel.find('.content div.text.hidden').get(0)); firstText.removeClass('hidden'); firstText.addClass('abbr'); if (PM.visiblePanel.find('.content div.text.hidden').length >= 1 || firstText.height() > 132) { PM.visiblePanel.find('.content').append($('
    ...
    ')); } 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 = ''; object += ''; object += ''; object += ''; object += ''; object += ''; 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 = ''; object += ''; object += ''; object += ''; object += ''; 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 = '
    ' + I18N.get('geocoderSelectPlace') + '
      '; if (ua.indexOf('gps') > -1 || ua.indexOf('Firefox') > -1 || ua.indexOf('Chrome') > -1) { geocoderPanel += ''; } if (ua.indexOf('nav') > -1 || ua.indexOf('Firefox') > -1 || ua.indexOf('Chrome') > -1) { geocoderPanel += ''; } geocoderPanel += ''; if (GeocoderLastUsedPlaces.load().length > 0) { geocoderPanel += '
    • ' + I18N.get('geocoderLastUsed') + ' (' + GeocoderLastUsedPlaces.load().length + ')
    • '; $.each(GeocoderLastUsedPlaces.load(), function(index) { var dataString = JSON.stringify(this); LOG.error(dataString); geocoderPanel += ''; }); } geocoderPanel += '
    '; // ----- Other Place Input Panel ---- var lastUsedCountry = Geocoder.position().country; var lastUsedCountryName = Geocoder.position().country; var otherPlacePanel = '
    ' + I18N.get('geocoderOtherLocation') + '
    • '; if (Config.geocoderSupportedCountries.length > 1) { if (I18N.get('country' + lastUsedCountry)) { lastUsedCountryName = I18N.get('country' + lastUsedCountry); } otherPlacePanel += ''; } else if (Config.geocoderSupportedCountries.length == 1) { otherPlacePanel += ''; } else { otherPlacePanel += '
    • '; } otherPlacePanel += '
    '; 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 += ''; } } 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]); }