changeset 1300:6e110baa707f

browser (photos/album): photo(s) upload and deletion
author Goffi <goffi@goffi.org>
date Fri, 19 Jun 2020 16:47:51 +0200
parents 053141849206
children ff44f822bfdd
files libervia/pages/photos/album/_browser/__init__.py
diffstat 1 files changed, 155 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libervia/pages/photos/album/_browser/__init__.py	Fri Jun 19 16:47:51 2020 +0200
@@ -0,0 +1,155 @@
+from browser import document, window, bind, html, DOMNode
+from browser import aio
+from browser import timer
+from javascript import JSON
+from interpreter import Inspector
+from bridge import Bridge
+from template import Template
+import dialog
+
+files_service = window.files_service
+files_path = window.files_path
+bridge = Bridge()
+
+
+def on_progress(ev, photo_elt):
+    if ev.lengthComputable:
+        percent = int(ev.loaded/ev.total*100)
+        update_progress(photo_elt, percent)
+
+
+def on_load(file_, photo_elt):
+    update_progress(photo_elt, 100)
+    photo_elt.classList.add("progress_finished")
+    photo_elt.classList.remove("progress_started")
+    photo_elt.select_one('.action_delete').bind("click", on_delete)
+    print(f"file {file_.name} uploaded correctly")
+
+
+def on_error(failure, file_, photo_elt):
+    # TODO: cleaner error notification
+    window.alert(f"can't upload {file_.name}: failure")
+
+
+def update_progress(photo_elt, new_value):
+    progress_elt = photo_elt.select_one("progress")
+    progress_elt.value = new_value
+    progress_elt.text = f"{new_value}%"
+
+
+def on_slot_cb(file_, upload_slot, photo_elt):
+    put_url, get_url, headers = upload_slot
+    xhr = window.XMLHttpRequest.new()
+    xhr.open("PUT", put_url, True)
+    xhr.upload.bind('progress', lambda ev: on_progress(ev, photo_elt))
+    xhr.upload.bind('load', lambda ev: on_load(file_, photo_elt))
+    xhr.upload.bind('error', lambda ev: on_error(xhr.response, file_, photo_elt))
+    xhr.setRequestHeader('Xmpp-File-Path', window.encodeURIComponent(files_path))
+    xhr.setRequestHeader('Xmpp-File-No-Http', "true")
+    xhr.send(file_)
+
+
+def on_slot_eb(file_, failure, photo_elt):
+    breakpoint()
+
+
+def upload_files(files):
+    print(f"uploading {len(files)} files")
+    photo_tpl = Template('photo/item.html')
+    album_items = document['album_items']
+    for file_ in files:
+        url = window.URL.createObjectURL(file_)
+        photo_elt = photo_tpl.get_elt({
+            "file": {
+                "name": file_.name,
+                # we don't want to open the file on click, it's not yet the
+                # uploaded URL
+                "url": url,
+                # we have no thumb yet, so we use the whole image
+                # TODO: reduce image for preview
+                "thumb_url": url,
+            },
+            "uploading": True,
+        })
+        photo_elt.classList.add("progress_started")
+        print(photo_elt.outerHTML)
+        album_items <= photo_elt
+        # timer.set_timeout(lambda photo_elt=photo_elt: fake_finish(photo_elt), 5000)
+
+        bridge.fileHTTPUploadGetSlot(
+            file_.name,
+            file_.size,
+            file_.type or '',
+            files_service,
+            callback=lambda upload_slot, file_=file_, photo_elt=photo_elt:
+                on_slot_cb(file_, upload_slot, photo_elt),
+            errback=lambda failure, file_=file_, photo_elt=photo_elt:
+                on_slot_eb(file_, failure, photo_elt),
+        )
+
+
+@bind("#file_drop", "drop")
+def on_file_select(evt):
+    evt.stopPropagation()
+    evt.preventDefault()
+    files = evt.dataTransfer.files
+    upload_files(files)
+
+
+@bind("#file_drop", "dragover")
+def on_drag_over(evt):
+    evt.stopPropagation()
+    evt.preventDefault()
+    evt.dataTransfer.dropEffect = 'copy'
+
+
+@bind("#file_input", "change")
+def on_file_input_change(evt):
+    files = evt.currentTarget.files
+    upload_files(files)
+
+
+def file_delete_cb(item_elt, item):
+    item_elt.classList.add("state_deleted")
+    item_elt.bind("transitionend", lambda evt: item_elt.remove())
+    print(f"deleted {item['name']}")
+
+
+def file_delete_eb(failure, item_elt, item):
+    # TODO: cleaner error notification
+    window.alert(f"error while deleting {item['name']}: failure")
+
+
+def delete_ok(evt, notif_elt, item_elt, item):
+    file_path = f"{files_path.rstrip('/')}/{item['name']}"
+    bridge.fileSharingDelete(
+        files_service,
+        file_path,
+        "",
+        callback=lambda : file_delete_cb(item_elt, item),
+        errback=lambda failure: file_delete_eb(failure, item_elt, item),
+    )
+
+
+def delete_cancel(evt, notif_elt, item_elt, item):
+    notif_elt.remove()
+    item_elt.classList.remove("selected_for_deletion")
+
+
+def on_delete(evt):
+    evt.stopPropagation()
+    target = evt.currentTarget
+    item_elt = DOMNode(target.elt.closest('.item'))
+    item_elt.classList.add("selected_for_deletion")
+    item = JSON.parse(item_elt.dataset.item)
+    dialog.Confirm(
+        f"{item['name']!r} will be deleted, are you sure?",
+        ok_label="delete",
+    ).show(
+        ok_cb=lambda evt, notif_elt: delete_ok(evt, notif_elt, item_elt, item),
+        cancel_cb=lambda evt, notif_elt: delete_cancel(evt, notif_elt, item_elt, item),
+    )
+
+
+for elt in document.select('.action_delete'):
+    elt.bind("click", on_delete)