Convenience function to run an AJAX call with a progress dialog

This commit is contained in:
Kovid Goyal 2015-11-17 16:04:45 +05:30
parent 81dfbd90f9
commit 56c31d8067
2 changed files with 34 additions and 6 deletions

View File

@ -4,6 +4,14 @@
from gettext import gettext as _
def ajax(path, on_complete, on_progress=None, bypass_cache=True, method='GET', query=None, timeout=30*1000, ok_code=200):
# Run an AJAX request. on_complete must be a function that accepts three
# arguments: end_type, xhr, ev where end_type is one of 'abort', 'error',
# 'load', 'timeout'. In case end_type is anything other than 'load' you can
# get a descriptive error message via `xhr.error_html`. on_progress, if
# provided must be a function accepting three arguments: loaded, total, xhr
# where loaded is the number of bytes received, total is the total size.
#
# Returns the xhr object, call xhr.send() to start the request.
query = query or {}
xhr = XMLHttpRequest()
keys = Object.keys(query)
@ -19,16 +27,16 @@ def ajax(path, on_complete, on_progress=None, bypass_cache=True, method='GET', q
path += ('&' if has_query else '?') + Date().getTime()
xhr.request_path = path
xhr.error_string = ''
xhr.error_html = ''
def set_error(event):
if event == 'timeout':
xhr.error_string = str.format(_('Failed to communicate with "{}", timed out after: {} seconds'), xhr.request_path, timeout/1000)
xhr.error_html = str.format(_('Failed to communicate with "{}", timed out after: {} seconds'), xhr.request_path, timeout/1000)
elif event == 'abort':
xhr.error_string = str.format(_('Failed to communicate with "{}", aborted'), xhr.request_path)
xhr.error_html = str.format(_('Failed to communicate with "{}", aborted'), xhr.request_path)
else:
rtext = xhr.responseText or ''
xhr.error_string = str.format(_('Failed to communicate with "{}", with status: [{}] {}<br>{}'), xhr.request_path, xhr.status, xhr.statusText, rtext[:200])
xhr.error_html = str.format(_('Failed to communicate with "{}", with status: [{}] {}<br>{}'), xhr.request_path, xhr.status, xhr.statusText, rtext[:200])
def progress_callback(ev):
if ev.lengthComputable:
@ -40,7 +48,7 @@ def ajax(path, on_complete, on_progress=None, bypass_cache=True, method='GET', q
ul = int(ul)
except Exception:
return
on_progress(ev.loaded, ul)
on_progress(ev.loaded, ul, xhr)
def complete_callback(end_type, ev):
if xhr.status != ok_code and end_type == 'load':

View File

@ -1,6 +1,7 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
from ajax import ajax
from elementmaker import E
from dom import set_css, clear, build_rule
from gettext import gettext as _
@ -162,7 +163,7 @@ def create_progress_dialog(msg, on_close):
# def test_progress():
# counter = 0
# pd = progress_dialog('Testing progress dialog', def():
# pd = progress_dialog('Testing progress dialog, please wait...', def():
# nonlocal counter
# counter = 101
# console.log('pd canceled')
@ -203,4 +204,23 @@ def warning_dialog(title, msg, details=None):
create_simple_dialog(title, msg, details, 'warning', _('Warning:'))
def progress_dialog(msg, on_close=None):
# Show a modal dialog with a progress bar and an optional close button.
# If the user clicks the close button, on_close is called and the dialog is closed.
# Returns an object with the methods: close(), update_progress(amount, total), set_msg()
# Call update_progress() to update the progress bar
# Call set_msg() to change the displayed message
# Call close() once the task being performed is finished
return create_progress_dialog(msg, on_close)
def ajax_progress_dialog(path, on_complete, msg, **kw):
pd = None
def on_complete_callback(event_type, xhr, ev):
nonlocal pd
pd.close()
pd = undefined
return on_complete(event_type, xhr, ev)
def on_progress_callback(loaded, total, xhr):
pd.update_progress(loaded, total)
xhr = ajax(path, on_complete_callback, on_progress=on_progress_callback, **kw)
pd = progress_dialog(msg, xhr.abort)
return xhr, pd