You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

520 lines
14 KiB

(function($K)
{
$K.add('module', 'upload', {
init: function(app, context)
{
this.app = app;
this.utils = app.utils;
this.animate = app.animate;
this.response = app.response;
this.progress = app.progress;
// defaults
var defaults = {
size: 120, // pixels
url: false,
urlRemove: false,
param: false,
type: false, // image, file
multiple: false,
placeholder: 'Drop files here or click to upload',
progress: false,
target: false,
append: false
};
// context
this.context = context;
this.params = context.getParams(defaults);
this.$element = context.getElement();
this.$target = context.getTarget();
// local
this.statusMap = ['hover', 'error', 'success', 'drop'];
},
// public
start: function()
{
this._buildBox();
this._buildInput();
this._buildCount();
this._buildType();
this._buildPlaceholder();
this._buildSize();
this._buildMultiple();
this._buildItems();
this._buildEvents();
},
stop: function()
{
this.$box.remove();
this.$element.off('.kube.upload');
},
// private
_buildBox: function()
{
if (this.params.type === 'image')
{
this.$box = this.$element.find('.upload-item');
}
else
{
this.$box = this.$element;
}
},
_buildInput: function()
{
this.$input = $K.dom('<input>');
this.$input.attr('type', 'file');
this.$input.attr('name', this._getParamName());
this.$input.hide();
this.$element.before(this.$input);
},
_buildCount: function()
{
this.$inputCount = $K.dom('<input>');
this.$inputCount.attr('type', 'hidden');
this.$inputCount.attr('name', this._getParamName() + '-count');
this.$inputCount.val(0);
this.$element.before(this.$inputCount);
},
_buildType: function()
{
this.isBox = this.$element.hasClass('upload');
},
_buildPlaceholder: function()
{
if (this.isBox)
{
var $placeholder = $K.dom('<span>');
$placeholder.addClass('upload-placeholder');
$placeholder.html(this.params.placeholder);
this.$element.append($placeholder);
}
},
_buildSize: function()
{
if (this.isBox)
{
this.$box.css({
height: this.params.size + 'px'
});
}
else if (this.params.type === 'image')
{
this.$box.css({
width: this.params.size + 'px',
height: this.params.size + 'px'
});
}
},
_buildMultiple: function()
{
this.isMultiple = this.params.multiple;
if (this.isMultiple)
{
this.$input.attr('multiple', 'true');
}
},
_buildItems: function()
{
if (!this.params.type) return;
var isFile = (this.params.type === 'file');
var $target = (isFile) ? this.$target : this.$element;
var fn = (isFile) ? '_removeFile' : '_removeImage';
var $closes = $target.find('.close');
$closes.on('click', this[fn].bind(this));
if (!isFile)
{
$closes.closest('.upload-item').addClass('is-uploaded');
}
this.$inputCount.val($closes.length);
},
_buildEvents: function()
{
this.$input.on('change.redactor.upload', this._change.bind(this));
this.$box.on('click.redactor.upload', this._click.bind(this));
this.$box.on('drop.redactor.upload', this._drop.bind(this));
this.$box.on('dragover.redactor.upload', this._dragover.bind(this));
this.$box.on('dragleave.redactor.upload', this._dragleave.bind(this));
},
// Events
_click: function(e)
{
e.preventDefault();
var $el = $K.dom(e.target);
if ($el.hasClass('close')) return;
this.$input.click();
},
_change: function(e)
{
this.app.broadcast('upload.start', this);
this._send(e, this.$input.get().files);
},
_drop: function(e)
{
e.preventDefault();
this._clearStatuses();
this._setStatus('drop');
this.app.broadcast('upload.start', this);
this._send(e);
},
_dragover: function(e)
{
e.preventDefault();
this._setStatus('hover');
return false;
},
_dragleave: function(e)
{
e.preventDefault();
this._removeStatus('hover');
return false;
},
// Count
_upCount: function()
{
var val = this.$inputCount.val();
val++;
this.$inputCount.val(val);
},
_downCount: function()
{
var val = this.$inputCount.val();
val--;
val = (val < 0) ? 0 : val;
this.$inputCount.val(val);
},
_clearCount: function()
{
this.$inputCount.val(0);
},
// Name
_getParamName: function()
{
return (this.params.param) ? this.params.param : 'file';
},
_getHiddenName: function()
{
var name = this._getParamName();
return (this.isMultiple) ? name + '-uploaded[]' : name + '-uploaded';
},
// Status
_clearStatuses: function()
{
this.$box.removeClass('is-upload-' + this.statusMap.join(' is-upload-'));
},
_setStatus: function(status)
{
this.$box.addClass('is-upload-' + status);
},
_removeStatus: function(status)
{
this.$box.removeClass('is-upload-' + status);
},
// Target
_clearTarget: function()
{
var $items = this.$target.find('.upload-item');
$items.each(function(node)
{
var $node = $K.dom(node);
this._removeFileRequest($node.attr('data-id'));
}.bind(this));
this._clearCount();
this.$target.html('');
},
_clearBox: function()
{
var $items = this.$target.find('.upload-item');
$items.each(function(node)
{
var $node = $K.dom(node);
this._removeFileRequest($node.attr('data-id'));
}.bind(this));
this._clearCount();
this.$target.html('');
},
// Remove
_removeFile: function(e)
{
e.preventDefault();
var $el = $K.dom(e.target);
var $item = $el.closest('.upload-item');
var id = $item.attr('data-id');
this.animate.run($item, 'fadeOut', function()
{
$item.remove();
this._downCount();
this._removeFileRequest(id);
// clear target
if (this.$target.find('.upload-item').length === 0)
{
this.$target.html('');
}
}.bind(this))
},
_removeImage: function(e)
{
e.preventDefault();
var $el = $K.dom(e.target);
var $item = $el.closest('.upload-item');
var id = $item.attr('data-id');
if (this.isMultiple)
{
this.animate.run($item, 'fadeOut', function()
{
$item.remove();
this._downCount();
this._removeFileRequest(id);
}.bind(this))
}
else
{
var $img = $item.find('img');
$el.hide();
this.animate.run($img, 'fadeOut', function()
{
this.$box.html('');
this.$box.removeClass('is-uploaded');
this._clearCount();
this._removeFileRequest(id);
}.bind(this))
}
},
_removeFileRequest: function(id)
{
if (this.params.urlRemove)
{
$K.ajax.post({
url: this.params.urlRemove,
data: { id: id }
});
}
},
// Send
_send: function(e, files)
{
e = e.originalEvent || e;
files = (files) ? files : e.dataTransfer.files;
var data = new FormData();
var name = this._getParamName();
data = this._buildData(name, files, data);
if (this.params.append)
{
data = this.utils.extendData(data, this.params.append);
}
this._sendData(data, files, e);
},
_sendData: function(data, files, e)
{
if (this.params.progress) this.progress.show();
$K.ajax.post({
url: this.params.url,
data: data,
before: function(xhr)
{
return this.app.broadcast('upload.beforeSend', this, xhr);
}.bind(this),
success: function(response)
{
this._complete(response, e);
}.bind(this)
});
},
_buildData: function(name, files, data)
{
for (var i = 0; i < files.length; i++)
{
data.append(name + '[]', files[i]);
}
return data;
},
_complete: function (response, e)
{
this._clearStatuses();
if (this.params.progress) this.progress.hide();
// error
var json = (Array.isArray(response)) ? response[0] : response;
if (typeof json.type !== 'undefined' && json.type === 'error')
{
this._setStatus('error');
this.response.parse(response);
this.app.broadcast('upload.error', this, response);
}
// complete
else
{
this._setStatus('success');
switch (this.params.type)
{
case 'image':
this._completeBoxImage(response);
break;
case 'file':
this._completeBoxFile(response);
break;
default:
this._completeBoxUpload(response);
}
this.app.broadcast('upload.complete', this, response);
setTimeout(this._clearStatuses.bind(this), 500);
}
},
_completeBoxUpload: function(response)
{
this.response.parse(response);
},
_completeBoxImage: function(response)
{
for (var key in response)
{
// img
var $img = $K.dom('<img>');
$img.attr('src', response[key].url);
// close
var $close = $K.dom('<span>');
$close.addClass('close');
$close.on('click', this._removeImage.bind(this));
// hidden
var $hidden = $K.dom('<input>');
$hidden.attr('type', 'hidden');
$hidden.attr('name', this._getHiddenName());
$hidden.val(response[key].id);
// item
var $item = $K.dom('<div>');
$item.addClass('upload-item is-uploaded');
$item.attr('data-id', response[key].id);
if (this.isMultiple)
{
// append
$item.append($close);
$item.append($img);
$item.append($hidden);
this.$box.last().before($item);
}
// single
else
{
var $lastImg = this.$box.find('img');
if ($lastImg.length !== 0)
{
this._removeFileRequest(this.$box.attr('data-id'));
}
this.$box.html('');
this.$box.attr('data-id', response[key].id);
this.$box.append($close);
this.$box.append($img);
this.$box.append($hidden);
return;
}
}
},
_completeBoxFile: function(response)
{
if (!this.isMultiple) this._clearTarget();
for (var key in response)
{
// item
var $item = $K.dom('<div>');
$item.addClass('upload-item');
$item.attr('data-id', response[key].id);
// file
var $file = $K.dom('<span>');
$file.html(response[key].name);
// close
var $close = $K.dom('<span>');
$close.addClass('close');
$close.on('click', this._removeFile.bind(this));
// hidden
var $hidden = $K.dom('<input>');
$hidden.attr('type', 'hidden');
$hidden.attr('name', this._getHiddenName());
$hidden.val(response[key].id);
// size
if (typeof response[key].size !== 'undefined')
{
var $size = $K.dom('<em>');
$size.html(response[key].size);
$file.append($size);
}
// append
$item.append($close);
$item.append($file);
$item.append($hidden);
// target
this.$target.append($item);
this._upCount();
}
}
});
})(Kube);