coffeescript-ui
Version:
Coffeescript User Interface System
491 lines (406 loc) • 9.31 kB
text/coffeescript
###
* coffeescript-ui - Coffeescript User Interface System (CUI)
* Copyright (c) 2013 - 2016 Programmfabrik GmbH
* MIT Licence
* https://github.com/programmfabrik/coffeescript-ui, http://www.coffeescript-ui.org
###
class CUI.FileUpload extends CUI.Element
constructor: (opts) ->
super(opts)
= []
= []
= 0
= 0
initOpts: ->
super()
url:
mandatory: true
check: String
name:
default: CUI.defaults.FileUpload.name
check: String
add_filename_to_url:
default: false
mandatory: true
check: Boolean
parallel:
default: 2
check: (v) ->
v >= 1
onAdd:
check: Function
onBatchStart:
check: Function
onBatchQueued:
check: Function
onBatchDone:
check: Function
onProgress:
check: Function
onDone:
check: Function
onUpdate:
check: Function
onDequeue:
check: Function
onRemove:
check: Function
onFail:
check: Function
onAlways:
check: Function
# callback which can be used
# to let the file reject or resolve
onBeforeDone:
check: Function
readOpts: ->
super()
()
setUrl: () ->
# console.info("FileUpload.setUrl: #{@getUrl()}.")
getUrl: ->
# returns all uploaded files including completed
getFiles: (filter) ->
if CUI.util.isString(filter)
filter = [ filter ]
files = []
for file in
if not filter or file.getStatus() in filter
files.push(file)
files
getInfo: ->
status = {}
total = 0
loaded = 0
count = 0
done = 0
all_done = true
for _fuf in ()
_p = _fuf.getProgress()
s = _p.status
if not status[s]
status[s] = 1
else
status[s]++
if not _fuf.isDone()
all_done = false
else
done += 1
total += _p.total
loaded += _p.loaded
count += 1
info =
status: status
total: total
count: count
done: done
loaded: loaded
percent: Math.floor(loaded / total * 100)
all_done: all_done
getUploadFileClass: ->
CUI.FileUploadFile
queueFiles: (files) ->
batch = ++
# console.debug "FileUpload.queueFiles", files
locked = false
done_queuing = =>
?()
()
locked = false
idx = -1
next_file = =>
locked = true
idx++
if idx == files.length
done_queuing()
return
file = files[idx]
cls = ()
f = new cls
file: file
fileUpload: @
batch: batch
onBeforeDone:
onDequeue: (f) =>
?(f)
?(f)
onRemove: (f) =>
?(f)
# we need to queue us here before the actually
# queuing happens, so that "onAdd" can also queue events
# which are called after onDone is called.
f.getPromise()
.progress =>
?(f)
?(f)
.done =>
?(f)
?(f)
()
.fail =>
?(f)
?(f)
()
.always =>
?(f)
(f)
dont_queue_file = =>
console.debug("FileUpload.onAdd: Skipping file, function returned 'false'.")
locked = false
return
queue_file = =>
.push(f)
?(f)
f.queue()
locked = false
return
= true
CUI.decide(?(f, idx, files.length))
.done =>
queue_file()
.fail =>
dont_queue_file()
.always =>
= false
?()
= new CUI.Deferred()
interval = window.setInterval(=>
if locked
# wait
return
if or
window.clearInterval(interval)
dfr =
delete()
if
delete()
done_queuing()
dfr.resolve()
else
delete()
dfr.reject()
return
if idx < files.length
# console.debug "queue", idx, files.length
next_file()
else
window.clearInterval(interval)
.resolve()
delete()
,
1)
@
isQueuing: ->
!!
stopQueuing: (abort = false) ->
dfr = new CUI.Deferred()
if
if not abort
= true
else
= true
.always(dfr.resolve)
else
dfr.resolve()
dfr.promise()
clear: ->
(true)
.done =>
while file = [0]
file.remove()
removeFile: (file) ->
CUI.util.removeFromArray(file, )
isDone: ->
if
return false
for f in
if not f.isDone()
return false
return true
isUploading: ->
for f in
if f.isUploading()
return true
return false
uploadNextFiles: ->
files = []
slots =
for f in
if f.getStatus() == "QUEUED"
files.push(f)
slots--
if f.isUploading()
slots--
if slots == 0
break
for file in files
# console.debug "uploading next file", file._file.name
(file)
@
uploadFile: (file) ->
if
file.upload(()+file.getName(), )
else
file.upload((), )
checkBatchDone: (file) ->
alarm = false
for f in
if f.getBatch() != file.getBatch()
continue
if not f.isDone()
return
alarm = true
if alarm
?()
return
initDropZone: (_opts={}) ->
opts = CUI.Element.readOpts _opts, "FileUpload.initDropZone",
dropZone:
mandatory: true
check: (v) ->
CUI.util.isElement(v) or CUI.util.isElement(v.DOM)
multiple:
mandatory: true
default: true
check: (v) ->
v == true or v == false or v instanceof Function
selector:
check: String
allow_drop: (ev) =>
check: Function
dropZone = opts.dropZone.DOM or opts.dropZone
selector = opts.selector
multiple = opts.multiple
CUI.Events.ignore
node: dropZone
instance: @
dropZone.classList.add("cui-file-upload-drop-zone")
CUI.Events.listen
node: dropZone
type: ["dragover"]
instance: @
selector: selector
call: (ev) =>
if opts.allow_drop and not opts.allow_drop(ev)
return ev.stop()
CUI.FileUpload.setDropClassByEvent(ev)
ev.stopPropagation()
ev.preventDefault()
return false
CUI.Events.listen
node: dropZone
type: "drop"
instance: @
selector: selector
call: (ev) =>
if opts.allow_drop and not opts.allow_drop(ev)
return ev.stop()
CUI.FileUpload.setDropClassByEvent(ev)
dt = ev.getNativeEvent().dataTransfer
if dt.files?.length > 0
warn = []
files = []
for file in dt.files
# if file.size == 0
# warn.push(file)
# else
files.push(file)
if multiple == false
break
if multiple instanceof Function and multiple() == false
break
if warn.length > 0
console.warn("Files empty or directories, not uploaded...", warn)
if files.length > 0
(files)
ev.stopPropagation()
ev.preventDefault()
return false
for dz in
if dz == dropZone
return @
.push(dropZone)
@
: (ev) ->
el = ev.getCurrentTarget()
# console.debug "FileUpload.setDropClassbyEvent", ev.getType(), el.nodeName, DOM.getAttribute(el, "row")
switch ev.getType()
when "dragover"
CUI.clearTimeout()
?.classList.remove("cui-file-upload-drag-over")
el.classList.add("cui-file-upload-drag-over")
= el
= CUI.setTimeout
# dragover fire's every 350ms in FF
ms: 500
call: =>
el.classList.remove("cui-file-upload-drag-over")
delete()
ev.getNativeEvent().dataTransfer.dropEffect = "copy"
when "drop"
el.classList.remove("cui-file-upload-drag-over")
@
openDialog: (_opts) ->
opts = CUI.Element.readOpts _opts, "FileUpload.openDialog",
directory:
check: Boolean
mandatory: true
default: false
multiple:
check: Boolean
mandatory: true
default: false
fileUpload:
check: (v) ->
if v?.nodeName == "INPUT" and v.type == "file"
return true
else
return false
fp = (opts)
opts.fileUpload.click()
return fp
initFilePicker: (opts) ->
if not opts.fileUpload
opts.fileUpload = document.getElementById("cui-file-upload-button")
opts.fileUpload.form.reset()
inp = opts.fileUpload
for k in ["webkitdirectory", "mozdirectory", "directory"]
if opts.directory
CUI.dom.setAttribute(inp, k, true)
else
CUI.dom.removeAttribute(inp, k)
if opts.accept
CUI.dom.setAttribute(inp, "accept", opts.accept)
else
CUI.dom.removeAttribute(inp, "accept")
if opts.multiple
CUI.dom.setAttribute(inp, "multiple", true)
else
CUI.dom.removeAttribute(inp, "multiple")
dfr = new CUI.Deferred()
CUI.Events.ignore
node: inp
CUI.Events.listen
type: "change"
node: inp
call: =>
files = (file for file in inp.files)
(files)
inp.form.reset()
dfr.resolve()
return
dfr.promise()
resetDropZones: ->
CUI.Events.ignore
instance: @
for dz in
CUI.dom.removeClass(dz, "cui-file-upload-drop-zone")
= []
@
destroy: ->
()
super()
@