Функция fail никогда не вызывается, если пользователь отказывается делиться геолокацией в firefox

Итак, у меня есть этот код javascript. В Safari и Chrome, если пользователь отказывается делиться местоположением, он переходит в функцию сбоя, как следует; однако в Firefox это не так.

Любая помощь оценивается.

function initGeolocation()
{
    if( navigator.geolocation )
    {          
          // Call getCurrentPosition with success and failure callbacks
          navigator.geolocation.getCurrentPosition( success, fail );
    }
    else
    {
          alert("Sorry, your browser does not support geolocation services.");
    }
}

 var map;
 function success(position)
 {

     var longIDText = document.getElementById('longID');
     var latIDText = document.getElementById('latID');
     longIDText.value = position.coords.longitude;
     latIDText.value = position.coords.latitude;
     document.getElementById('coordSubmitID').click();
  }

  function fail(error)
  {
          alert("FAAAAAAAAAAIIIIIIIIIL")
          var zip_code ;
          while (true){
              // Could not obtain location

              zip_code = prompt("Please enter your current address or zip code","");


              if ( zip_code == "" ) {
                  alert(zip_code +" is not a valid address. Please try again.");
              } 
              else{
                break;
              }
          }
          var zipIDText = document.getElementById('zipID');
          zipIDText.value = zip_code;
          document.getElementById('coordSubmitID').click();
  }

Ответ 1

Для Firefox он кажется, что PERMISSION_DENIED поднят только, если выбрано "Never share"; если диалог отклонен или выбран "Не сейчас", то фактически ничего не происходит - даже при демонстрации геолокации mozillas, если вы отклоняете пользовательский интерфейс разрешений, ничего не происходит.

Это означает, что getCurrentPosition может возвращаться либо потому, что пользователь закрыл пользовательский интерфейс подтверждения, либо потому, что он успешно запустил его асинхронный запрос - не существует способа различать эти два.

https://bugzilla.mozilla.org/show_bug.cgi?id=675533

Ответ 2

Это настоящая боль и определенно нежелательная функциональность.

Обходной путь, который я использую, чтобы сохранить пользователя в ожидании, - установить тайм-аут, чтобы проверить, показывается ли счетчик ожидания через 3 секунды, и если да, скройте его и покажите ввод ручного почтового индекса:

var latlng;

var waitTime = 3000;
try {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function (position) {
            success(position);
        }, showError);
    } else {
        showError("NOT-SUPPORTED");
    }
    var t = setTimeout(function () {
        if ($("#getZip div.loading").css("display") != "none") {
            $("#getZip div.loading").hide();
            $("#errorZip").show();
        }
    }, waitTime);
} catch (evt) {
    alert(evt);
}

Ответ 3

Как отметил alexleonard, единственным надежным кроссбраузерным решением, которое я нашел для этого, является наличие setTimeout() для проверки состояния вашего объекта/переменных latLng, поскольку опция timeout getCurrentPosition(), похоже, не работает надежно. Пример ниже был протестирован в IE11, Chrome33 и Firefox28.

Для более полного решения, которое использует обещание jQuery, посмотрите мой Gist здесь: https://gist.github.com/GFoley83/10092929

Пример - нажмите F12, вставьте в консоль и запустите

var latLng,
    geoOptions = {
        enableHighAccuracy: false,
        timeout: 5000, // Wait 5 seconds
        maximumAge: 300000 //  Valid for 5 minutes
    };

var userLocationFound = function(position){
    latLng = {
        lat: position.coords.latitude,
        lng: position.coords.longitude
    };
    window.console.log("User confirmed! Location found: " + latLng.lat + ", " + latLng .lng);
}

var userLocationNotFound = function(){
    latLng = {
        lat: -41.29247, // fallback lat 
        lng: 174.7732  // fallback lng
    };
    window.console.log("Fallback set: ", latLng);
}

window.navigator.geolocation.getCurrentPosition(userLocationFound, userLocationNotFound, geoOptions);

setTimeout(function () {
    if(!latLng){
        window.console.log("No confirmation from user, using fallback");
        userLocationNotFound();
    }else{
        window.console.log("Location was set");
    }
}, geoOptions.timeout + 1000); // Wait extra second

Ответ 4

Это по дизайну и, по-видимому, не является проблемой. См. https://bugzilla.mozilla.org/show_bug.cgi?id=675533

Разработчики, использующие эту функцию, оставляют за собой возможность работать с браузером для Firefox.

Следует отметить, что на основании комментариев разработчика FF о фактическом использовании геолокации конечными пользователями, по-видимому, разработчики Firefox собирают подробные данные о том, что конечные пользователи делают с их продуктами.

Ответ 5

Обратите внимание, что это также проблема в Chrome.

В Chrome появляется уведомление о том, что "сайт хочет знать ваше местоположение" - тогда он предлагает опции "Разрешить" и "Запретить" в качестве параметров. С дизайном пользовательского интерфейса пользователь с большей вероятностью будет выбирать "Разрешить или Запретить", после чего возвращает ответ на функцию navigator.geolocation.getCurrentPosition. Тем не менее, пользователь может также щелкнуть "X" справа от консультативного уведомления. Это по сути то же самое, что нажать "Не сейчас" в Firefox.

Никакой результат не возвращается функции.

Похоже, что таймер должен быть реализован для обеспечения этого возможного результата.

Ответ 6

Используйте обещание. Я использую angularjs, у которого есть собственная версия $q, чтобы решить ту же проблему, что у всех нас есть.

            $scope.ByUserPosition = function () {
                //http://www.w3.org/TR/geolocation-API/
                var deferred = $q.defer();

                deferred.promise.then(findByPosition, function (data) {
                    console.log('error', data);
                });

                var resolveBy = 1000 * 30;
                navigator.geolocation.getCurrentPosition(function (position) {
                    deferred.resolve({ latitude: position.coords.latitude, longitude: position.coords.longitude });
                }, function (err) {
                    deferred.reject(err);
                }, {
                    enableHighAccuracy: true,
                    timeout: resolveBy,
                    maximumAge: 0
                });

                $timeout(function() {
                    deferred.reject('timed out');
                }, resolveBy)
            };

Ответ 7

Изменить (после downvote) 6-11-2013

Как отмечено ниже, этот ответ не решает проблему, когда пользователь отказывает в доступе к местоположению. До нисходящего канала правильно. Я сохраняю ответ здесь, потому что тайм-аут - это все, что нужно использовать в любом случае, и я не вижу его в любом ответе.

Функция navigator.geolocation.getCurrentPosition() имеет возможность отправлять с ней таймаут:

navigator.geolocation.getCurrentPosition(
     function (position){
        //do someting with position
     },
     function (error){
        // do something with the error (like the code)
     }, 
     {timeout:10000}
);

и некоторые другие варианты, такие как возраст кэшированной позиции (maximumAge). тайм-аут и максимальное значение составляют миллисекунды, поэтому 10000 = 10 секунд.

Кстати, тайм-аут по умолчанию бесконечен... поэтому, если вы не установите таймаут, он никогда не вызовет обратный вызов для ошибок....

поэтому в варианте, как ответил Джейми, я бы сказал:

if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function (position) {
            success(position);
        }, showError, {timeout:3000});
    }

Ответ 8

Единственное решение этой проблемы:

  • Когда пользователь нажимает кнопку, чтобы автоматически определить свое местоположение, покажите счетчик и ссылку рядом с ним "ex: Отмена".
  • Если он разрешает совместное использование местоположения, то проблем нет. Если он решит отклонить всплывающее окно Firefox, счетчик все равно будет отображаться, но он может нажать ссылку "Отменить", чтобы остановить счетчик как индикатор отклонения всплывающего окна

Надеюсь, это поможет:)

Ответ 9

Вот решение моей проблемы с использованием vanilla es6 Promises. Вдохновленный ответом @LeblancMeneses.

if(navigator.geolocation) {
  let promise = new Promise((resolve, reject) => {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        resolve(position)
      },
      (error) => {
        resolve(error)
      }
    )
    window.setTimeout(() => {
      resolve({})
    }, 8000)
  })
  promise.then((result) => {
      // do something with result
  })
} else {
  console.log('no geolocation available')
}

Ответ 10

var latlng; 
if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function (position) {
         latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
    });
}
if(!latlng) {
    latlng = new google.maps.LatLng(57.718, 11.974); 
}

Удалите все мои ошибки:)

Ответ 11

watchPosition и getCurrentPosition принимают второй обратный вызов, который вызывается при возникновении ошибки. Обратный вызов ошибки предоставляет аргумент для объекта ошибки. Для отказа разрешено error.code будет error.PERMISSION_DENIED (числовое значение 1).

Подробнее здесь: https://developer.mozilla.org/en/Using_geolocation

Пример:

navigator.geolocation.watchPosition(function(position) {
  console.log("i'm tracking you!");
},
function (error) { 
  if (error.code == error.PERMISSION_DENIED)
     console.log("you denied me :-(");

});