Вам нужен список идентификаторов? Если да, попробуйте:
- debug: msg="{{ lookup('file','test.json') | from_json | json_query(query) }}"
vars:
query: "Foods[].{id: Id, for: (Tags[?Key=='For'].Value)[0]} | [?for=='Tigger'].id"
Сначала создайте простые объекты с необходимыми полями, а затем подключите их к фильтру.
Одно возможное решение использует JavaScript на клиенте.
Клиентский алгоритм:
Алгоритм сервера:
Исходный код клиента (JavaScript):
function getCookie( name ) {
var parts = document.cookie.split(name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
function expireCookie( cName ) {
document.cookie =
encodeURIComponent(cName) + "=deleted; expires=" + new Date( 0 ).toUTCString();
}
function setCursor( docStyle, buttonStyle ) {
document.getElementById( "doc" ).style.cursor = docStyle;
document.getElementById( "button-id" ).style.cursor = buttonStyle;
}
function setFormToken() {
var downloadToken = new Date().getTime();
document.getElementById( "downloadToken" ).value = downloadToken;
return downloadToken;
}
var downloadTimer;
var attempts = 30;
// Prevents double-submits by waiting for a cookie from the server.
function blockResubmit() {
var downloadToken = setFormToken();
setCursor( "wait", "wait" );
downloadTimer = window.setInterval( function() {
var token = getCookie( "downloadToken" );
if( (token == downloadToken) || (attempts == 0) ) {
unblockSubmit();
}
attempts--;
}, 1000 );
}
function unblockSubmit() {
setCursor( "auto", "pointer" );
window.clearInterval( downloadTimer );
expireCookie( "downloadToken" );
attempts = 30;
}
Пример кода сервера (PHP):
$TOKEN = "downloadToken";
// Sets a cookie so that when the download begins the browser can
// unblock the submit button (thus helping to prevent multiple clicks).
// The false parameter allows the cookie to be exposed to JavaScript.
$this->setCookieToken( $TOKEN, $_GET[ $TOKEN ], false );
$result = $this->sendFile();
Где:
public function setCookieToken(
$cookieName, $cookieValue, $httpOnly = true, $secure = false ) {
// See: http://stackoverflow.com/a/1459794/59087
// See: http://shiflett.org/blog/2006/mar/server-name-versus-http-host
// See: http://stackoverflow.com/a/3290474/59087
setcookie(
$cookieName,
$cookieValue,
2147483647, // expires January 1, 2038
"/", // your path
$_SERVER["HTTP_HOST"], // your domain
$secure, // Use true over HTTPS
$httpOnly // Set true for $AUTH_COOKIE_NAME
);
}
Если Xmlhttprequest с blob не является опцией, вы можете открыть файл в новом окне и проверить, не заселены ли элементы eny в этом теле окна с интервалом.
var form = document.getElementById("frmDownlaod");
form.setAttribute("action","downoad/url");
form.setAttribute("target","downlaod");
var exportwindow = window.open("", "downlaod", "width=800,height=600,resizable=yes");
form.submit();
var responseInterval = setInterval(function(){
var winBody = exportwindow.document.body
if(winBody.hasChildNodes()) // or 'downoad/url' === exportwindow.document.location.href
{
clearInterval(responseInterval);
// do your work
// if there is error page configured your application for failed requests, check for those dom elemets
}
}, 1000)
//Better if you specify maximun no of intervals
Если вы передаете файл, который вы генерируете динамически, а также имеете встроенную библиотеку обмена сообщениями между серверами, вы можете легко оповестить своего клиента.
Библиотека обмена сообщениями между клиентом, которую мне нравится и рекомендую, - Socket.io (через Node.js). После того, как ваш серверный сценарий будет создан, генерирующий файл, который будет передан для загрузки, ваша последняя строка в этом скрипте может передать сообщение Socket.io, которое отправляет уведомление клиенту. На клиенте Socket.io прослушивает входящие сообщения, исходящие от сервера, и позволяет вам действовать на них. Преимущество использования этого метода над другими заключается в том, что вы можете обнаружить «истинное» финишное событие после завершения потоковой передачи.
Например, вы можете показать индикатор занятости после нажатия ссылки загрузки, передайте свой файл, выпустите сообщение на Socket.io с сервера в последней строке вашего потокового скрипта, послушайте клиента для получения уведомления, получите уведомление и обновите свой пользовательский интерфейс, скрыв индикатор занятости.
Я понимаю, что большинство людей, которые читают ответы на этот вопрос, могут не иметь такого типа установки, но я использовал это точное решение для отличного эффекта в своих собственных проектах и прекрасно работает.
Socket.io невероятно прост в установке и использовании. Подробнее: http://socket.io/
Если вы загрузили файл, который был сохранен, в отличие от того, чтобы быть в документе, невозможно определить, когда загрузка будет завершена, поскольку она не входит в объем текущего документа, а отдельный процесс в браузера.
старый поток, я знаю ...
, но те, которые приводятся здесь google, могут быть заинтересованы в моем решении. это очень просто, но надежно. и он позволяет отображать реальные сообщения о проделанной работе (и их можно легко подключить к существующим процессам):
скрипт, который обрабатывает (моя проблема: получение файлов через http и доставка их как zip), пишет статус сессии.
статус проверяется и отображается каждую секунду. это все (хорошо, его нет, вам нужно позаботиться о большом количестве деталей (например, одновременные загрузки), но это хорошее место для начала; -)).
страница загрузки:
<a href="download.php?id=1" class="download">DOWNLOAD 1</a>
<a href="download.php?id=2" class="download">DOWNLOAD 2</a>
...
<div id="wait">
Please wait...
<div id="statusmessage"></div>
</div>
<script>
//this is jquery
$('a.download').each(function()
{
$(this).click(
function(){
$('#statusmessage').html('prepare loading...');
$('#wait').show();
setTimeout('getstatus()', 1000);
}
);
});
});
function getstatus(){
$.ajax({
url: "/getstatus.php",
type: "POST",
dataType: 'json',
success: function(data) {
$('#statusmessage').html(data.message);
if(data.status=="pending")
setTimeout('getstatus()', 1000);
else
$('#wait').hide();
}
});
}
</script>
getstatus.php
<?php
session_start();
echo json_encode($_SESSION['downloadstatus']);
?>
download.php
<?php
session_start();
$processing=true;
while($processing){
$_SESSION['downloadstatus']=array("status"=>"pending","message"=>"Processing".$someinfo);
session_write_close();
$processing=do_what_has_2Bdone();
session_start();
}
$_SESSION['downloadstatus']=array("status"=>"finished","message"=>"Done");
//and spit the generated file to the browser
?>
.each()
для регистрации событий. просто скажите $('a.download').click()
– robisrob
16 November 2015 в 23:26
Я написал простой класс JavaScript, который реализует технику, аналогичную той, которая описана в ht-файле answer . Надеюсь, это может быть полезно кому-то здесь. Проект GitHub называется response-monitor.js
По умолчанию он использует spin.js в качестве индикатора ожидания, но также предоставляет набор обратных вызовов для реализации пользовательского индикатора.
JQuery поддерживается, но не требуется.
Известные функции
Пример использования
HTML
<!-- the response monitor implementation -->
<script src="response-monitor.js"></script>
<!-- optional JQuery plug-in -->
<script src="response-monitor.jquery.js"></script>
<a class="my_anchors" href="/report?criteria1=a&criteria2=b#30">Link 1 (Timeout: 30s)</a>
<a class="my_anchors" href="/report?criteria1=b&criteria2=d#10">Link 2 (Timeout: 10s)</a>
<form id="my_form" method="POST">
<input type="text" name="criteria1">
<input type="text" name="criteria2">
<input type="submit" value="Download Report">
</form>
Клиент (обычный JavaScript)
//registering multiple anchors at once
var my_anchors = document.getElementsByClassName('my_anchors');
ResponseMonitor.register(my_anchors); //clicking on the links initiates monitoring
//registering a single form
var my_form = document.getElementById('my_form');
ResponseMonitor.register(my_form); //the submit event will be intercepted and monitored
Клиент (JQuery)
$('.my_anchors').ResponseMonitor();
$('#my_form').ResponseMonitor({timeout: 20});
Клиент с обратными вызовами (JQuery)
//when options are defined, the default spin.js integration is bypassed
var options = {
onRequest: function(token){
$('#cookie').html(token);
$('#outcome').html('');
$('#duration').html('');
},
onMonitor: function(countdown){
$('#duration').html(countdown);
},
onResponse: function(status){
$('#outcome').html(status==1?'success':'failure');
},
onTimeout: function(){
$('#outcome').html('timeout');
}
};
//monitor all anchors in the document
$('a').ResponseMonitor(options);
Сервер (PHP)
$cookiePrefix = 'response-monitor'; //must match the one set on the client options
$tokenValue = $_GET[$cookiePrefix];
$cookieName = $cookiePrefix.'_'.$tokenValue; //ex: response-monitor_1419642741528
//this value is passed to the client through the ResponseMonitor.onResponse callback
$cookieValue = 1; //for ex, "1" can interpret as success and "0" as failure
setcookie(
$cookieName,
$cookieValue,
time()+300, // expire in 5 minutes
"/",
$_SERVER["HTTP_HOST"],
true,
false
);
header('Content-Type: text/plain');
header("Content-Disposition: attachment; filename=\"Response.txt\"");
sleep(5); //simulate whatever delays the response
print_r($_REQUEST); //dump the request in the text file
Для получения дополнительных примеров проверьте папку examples в репозитории.
Очень простое (и хромое) однострочное решение - использовать событие window.onblur()
для закрытия диалогового окна загрузки. Конечно, если это займет слишком много времени, и пользователь решает сделать что-то еще (например, читать электронные письма), диалог загрузки будет закрыт.
onbeforeunload
. Спасибо.
– wf4
14 February 2014 в 18:13
Я использую следующее, чтобы загрузить blobs и аннулировать URL-адрес объекта после загрузки. он работает в chrome и firefox!
function download(blob){
var url = URL.createObjectURL(blob);
console.log('create ' + url);
window.addEventListener('focus', window_focus, false);
function window_focus(){
window.removeEventListener('focus', window_focus, false);
URL.revokeObjectURL(url);
console.log('revoke ' + url);
}
location.href = url;
}
после того, как диалоговое окно загрузки файла закрыто, окно возвращает ее фокус назад, так что событие фокусировки запускается.
Когда пользователь запускает генерацию файла, вы можете просто назначить уникальный идентификатор этой «загрузке» и отправить пользователя на страницу, которая обновляет (или проверяет с помощью AJAX) каждые несколько секунд. После того, как файл будет закончен, сохраните его под тем же уникальным идентификатором и ...
Затем вы можете пропустить весь беспорядок iframe / waiting / browserwindow, но у вас действительно элегантное решение.
У меня была такая же проблема. Мое решение заключалось в использовании временных файлов, так как я уже создавал кучу временных файлов. Форма отправляется с помощью:
var microBox = {
show : function(content) {
$(document.body).append('<div id="microBox_overlay"></div><div id="microBox_window"><div id="microBox_frame"><div id="microBox">' +
content + '</div></div></div>');
return $('#microBox_overlay');
},
close : function() {
$('#microBox_overlay').remove();
$('#microBox_window').remove();
}
};
$.fn.bgForm = function(content, callback) {
// Create an iframe as target of form submit
var id = 'bgForm' + (new Date().getTime());
var $iframe = $('<iframe id="' + id + '" name="' + id + '" style="display: none;" src="about:blank"></iframe>')
.appendTo(document.body);
var $form = this;
// Submittal to an iframe target prevents page refresh
$form.attr('target', id);
// The first load event is called when about:blank is loaded
$iframe.one('load', function() {
// Attach listener to load events that occur after successful form submittal
$iframe.load(function() {
microBox.close();
if (typeof(callback) == 'function') {
var iframe = $iframe[0];
var doc = iframe.contentWindow.document;
var data = doc.body.innerHTML;
callback(data);
}
});
});
this.submit(function() {
microBox.show(content);
});
return this;
};
$('#myForm').bgForm('Please wait...');
В конце скрипта, который генерирует файл, который у меня есть:
header('Refresh: 0;url=fetch.php?token=' . $token);
echo '<html></html>';
Это приведет к тому, что событие load на iframe будет уволена. Затем сообщение ожидания будет закрыто, и загрузка файла начнется. Протестировано на IE7 и Firefox.
Основываясь на примере Элмера, я подготовил собственное решение. После того, как элементы щелкнули с определенным классом download , он позволяет отображать на экране пользовательские сообщения. Я использовал триггер focus , чтобы скрыть сообщение.
JavaScript
$(function(){$('.download').click(function() { ShowDownloadMessage(); }); })
function ShowDownloadMessage()
{
$('#message-text').text('your report is creating, please wait...');
$('#message').show();
window.addEventListener('focus', HideDownloadMessage, false);
}
function HideDownloadMessage(){
window.removeEventListener('focus', HideDownloadMessage, false);
$('#message').hide();
}
HTML
<div id="message" style="display: none">
<div id="message-screen-mask" class="ui-widget-overlay ui-front"></div>
<div id="message-text" class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ui-draggable ui-resizable waitmessage">please wait...</div>
</div>
Теперь вы должны реализовать любой элемент для загрузки:
<a class="download" href="file://www.ocelot.com.pl/prepare-report">Download report</a>
или
<input class="download" type="submit" value="Download" name="actionType">
После каждого нажатия download вы увидите сообщение, которое создает ваш отчет, подождите. ..
Вопрос заключается в том, чтобы во время создания файла отображался индикатор ожидания, а затем возвращался к нормальному состоянию после загрузки файла. Как мне нравится делать это, используйте скрытый iFrame и подключайте событие onload к фрейму, чтобы моя страница знала, когда начнется загрузка. НО загрузка не запускается в IE для загрузки файлов (например, с токеном заголовка вложения). Опрос сервера работает, но мне не нравится дополнительная сложность. Итак, вот что я делаю:
Отказ от ответственности, не делайте этого на загруженном сайте, из-за того, что кеширование может складываться. Но на самом деле, если ваши сайты, занятые длительным запуском процесса, будут голодать в любом случае.
Вот что выглядит codebehind, что вам действительно нужно.
public partial class Download : System.Web.UI.Page
{
protected System.Web.UI.HtmlControls.HtmlControl Body;
protected void Page_Load( object sender, EventArgs e )
{
byte[ ] data;
string reportKey = Session.SessionID + "_Report";
// Check is this page request to generate the content
// or return the content (data query string defined)
if ( Request.QueryString[ "data" ] != null )
{
// Get the data and remove the cache
data = Cache[ reportKey ] as byte[ ];
Cache.Remove( reportKey );
if ( data == null )
// send the user some information
Response.Write( "Javascript to tell user there was a problem." );
else
{
Response.CacheControl = "no-cache";
Response.AppendHeader( "Pragma", "no-cache" );
Response.Buffer = true;
Response.AppendHeader( "content-disposition", "attachment; filename=Report.pdf" );
Response.AppendHeader( "content-size", data.Length.ToString( ) );
Response.BinaryWrite( data );
}
Response.End();
}
else
{
// Generate the data here. I am loading a file just for an example
using ( System.IO.FileStream stream = new System.IO.FileStream( @"C:\1.pdf", System.IO.FileMode.Open ) )
using ( System.IO.BinaryReader reader = new System.IO.BinaryReader( stream ) )
{
data = new byte[ reader.BaseStream.Length ];
reader.Read( data, 0, data.Length );
}
// Store the content for retrieval
Cache.Insert( reportKey, data, null, DateTime.Now.AddMinutes( 5 ), TimeSpan.Zero );
// This is the key bit that tells the frame to reload this page
// and start downloading the content. NOTE: Url has a query string
// value, so that the content isn't generated again.
Body.Attributes.Add("onload", "window.location = 'binary.aspx?data=t'");
}
}
Быстрое решение, если вы хотите отображать сообщение или gif загрузчика до тех пор, пока не отобразится диалоговое окно загрузки, следует поместить сообщение в скрытый контейнер, и когда вы нажимаете кнопку, которая генерирует загружаемый файл, вы делаете контейнер видимый. Затем используйте jquery или javascript, чтобы поймать событие фокуса кнопки, чтобы скрыть контейнер, содержащий сообщение
Создайте iframe при нажатии кнопки / ссылки и добавьте это в тело.
$('<iframe />')
.attr('src', url)
.attr('id','iframe_download_report')
.hide()
.appendTo('body');
Создайте iframe с задержкой и удалите его после загрузки.
var triggerDelay = 100;
var cleaningDelay = 20000;
var that = this;
setTimeout(function() {
var frame = $('<iframe style="width:1px; height:1px;" class="multi-download-frame"></iframe>');
frame.attr('src', url+"?"+ "Content-Disposition: attachment ; filename="+that.model.get('fileName'));
$(ev.target).after(frame);
setTimeout(function() {
frame.remove();
}, cleaningDelay);
}, triggerDelay);
Я очень опаздываю на вечеринку, но я расскажу об этом здесь, если кто-нибудь еще захочет узнать мое решение:
У меня была настоящая борьба с этой точной проблемой, но я нашел жизнеспособную
У меня была html-страница, которая запустила отдельный php-скрипт, который сгенерировал файл, а затем загрузил его. На html-странице я использовал следующий jquery в заголовке html (вам также нужно включить библиотеку jquery):
<script>
$(function(){
var iframe = $("<iframe>", {name: 'iframe', id: 'iframe',}).appendTo("body").hide();
$('#click').on('click', function(){
$('#iframe').attr('src', 'your_download_script.php');
});
$('iframe').load(function(){
$('#iframe').attr('src', 'your_download_script.php?download=yes'); <!--on first iframe load, run script again but download file instead-->
$('#iframe').unbind(); <!--unbinds the iframe. Helps prevent against infinite recursion if the script returns valid html (such as echoing out exceptions) -->
});
});
</script>
На вашем_download_script.php есть следующее:
function downloadFile($file_path) {
if (file_exists($file_path)) {
header('Content-Description: File Transfer');
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename=' . basename($file_path));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file_path));
ob_clean();
flush();
readfile($file_path);
exit();
}
}
$_SESSION['your_file'] = path_to_file; //this is just how I chose to store the filepath
if (isset($_REQUEST['download']) && $_REQUEST['download'] == 'yes') {
downloadFile($_SESSION['your_file']);
} else {
*execute logic to create the file*
}
Чтобы прервать это, jquery сначала запускает ваш php-скрипт в iframe. Iframe загружается после создания файла. Затем jquery снова запускает скрипт с переменной запроса, сообщающей скрипту для загрузки файла.
Причина, по которой вы не можете выполнить загрузку и создание файлов за один раз, связана с заголовком php () функция. Если вы используете header (), вы меняете скрипт на что-то другое, кроме веб-страницы, и jquery никогда не распознает сценарий загрузки как «загруженный». Я знаю, что это может не обязательно обнаруживать, когда браузер получает файл, но ваша проблема была похожа на мою.