Как показать диалог сохранения файла в Safari?

Мне нужна помощь. У меня есть приложение angular и с помощью DocRaptor вы хотите создать PDF файл и сохранить его как файл. Но я не могу запустить диалог для сохранения файла в Safari любым способом, который я нашел в Stack Overflow. Эти методы открывают файл на текущей вкладке браузера и заменяют сайт html или открывают файл на новой вкладке. Никто не может показать диалог. Вот примеры, которые я уже пытался использовать. Окружающая среда MacOS - EL Capitan. Safari 9.0.3

Решение # 1

var content = 'file content for example';
var blob = new Blob([ content ], { type : 'text/plain' });
$scope.url = (window.URL || window.webkitURL).createObjectURL( blob );

Пример jsfiddle. Показывает файл на текущей вкладке. Заменяет сайт. Но работает в Chrome.

Решение # 2

<a target="_self" href="mysite.com/uploads/ahlem.pdf" download="foo.pdf">

Пример jsfiddle. Не работает вообще в Safari. Работает в Chrome.

Решение # 3

<a class="btn" ng-click="saveJSON()" ng-href="{{ url }}">Export to JSON</a>

и

$scope.saveJSON = function () {
            $scope.toJSON = '';
            $scope.toJSON = angular.toJson($scope.data);
            var blob = new Blob([$scope.toJSON], { type:"application/json;charset=utf-8;" });           
            var downloadLink = angular.element('<a></a>');
                        downloadLink.attr('href',window.URL.createObjectURL(blob));
                        downloadLink.attr('download', 'fileName.json');
            downloadLink[0].click();
        };

Пример фрагмент кода. Показывает содержимое файла вместо документа html.

Решение # 4

function download(text, name, type) {
  var a = document.getElementById("a");
  var file = new Blob([text], {type: type});
  a.href = URL.createObjectURL(file);
  a.download = name;
}

Пример фрагмент кода. Замените документ содержимым файла в Safari. Работает в Chrome.

И подобное Решение # 5

function download(text, name, type) {
    var a = document.createElement("a");
    var file = new Blob([text], {type: type});
    a.href = URL.createObjectURL(file);
    a.download = name;
    a.click();
}

Пример jsfiddle. Не работает вообще в Safari. Работает в Chrome.

Также я попытался использовать библиотеки вроде: FileSaver - он открывает файл в Safari вместо документа. Поэтому вы должны нажать Cmd + S. Пример. Если мы используем тип "pplication/octet-stream", имя файла будет неизвестно или возникла ошибка "Не удалось загрузить ресурс: загрузка кадра прерывается". Issue.

Вторая библиотека Downloadify - вообще не работает в Safari. Issue.

Angular library nw-fileDialog - вместо сохранения, поскольку он показывает файл выбора. Issue.

DocRaptor имеет собственный пример с jQuery. Пример с angular в jsfiddle. Он работает в Chrome, но в примере Safari не может быть причиной ошибки с SAMEORIGIN

Отказано в отображении 'https://docraptor.com/docs' в кадре, потому что он установил 'X-Frame-Options' в 'SAMEORIGIN'.

Но если мы воспроизведем его на сервере и изменим url на 'https://docraptor.com/docs.pdf', он работает и открывает файл на новой вкладке и автоматически загружает файл, поэтому вы не можете выбрать папку, и после того, как пользователь загрузки увидит белый пустой экран в браузере. Если мы укажем форму target = "_ self", она будет работать идеально, но консоль будет иметь ошибку "Не удалось загрузить ресурс:".

Буду признателен за любую помощь в решении этой проблемы. Благодарю. С наилучшими пожеланиями.

Ответ 1

Попробуйте использовать Blob файл для этого:

// Buffer can be response from XMLHttpRequest/Ajax or your custom Int32 data
function download(buffer, filename) {
  var file = new Blob([buffer], {
    type: 'application/octet-stream' // Replace your mimeType if known
  });
  var fileReader = new FileReader();

  fileReader.onloadend = function(e) {
    var converted = e.target.result;
    converted.name = filename;
    converted.webkitRelativePath = filename;

    var iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    document.body.appendChild(iframe);
    iframe.src = converted;
  };
  fileReader.onerror = function(e) {
    throw new Error('Something is wrong with buffer data');
  };
  fileReader.file = file;
  fileReader.readAsDataURL(file);
}

В основном он использует filebuffer и загружает его как содержимое iframe. Обязательно подключите правильный тип mime, чтобы система безопасности Safari получала аналитический тип файла.

Ответ 2

В идеале решение №2 было бы ответом, но атрибут загрузки пока не поддерживает кросс-браузер.

Поэтому для создания загрузки вам необходимо использовать <form>. Как вы отметили, DocRaptor пример jQuery использует эту технику.

Ошибка SAMEORIGIN на самом деле потому, что JSFiddle запускает код в iFrame с настройками источника. Если вы запускаете это прямо из своего приложения Angular, у вас не должно быть никаких проблем.