(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(''); 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(''); 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(''); $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.attr('src', response[key].url); // close var $close = $K.dom(''); $close.addClass('close'); $close.on('click', this._removeImage.bind(this)); // hidden var $hidden = $K.dom(''); $hidden.attr('type', 'hidden'); $hidden.attr('name', this._getHiddenName()); $hidden.val(response[key].id); // item var $item = $K.dom(''); $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(''); $item.addClass('upload-item'); $item.attr('data-id', response[key].id); // file var $file = $K.dom(''); $file.html(response[key].name); // close var $close = $K.dom(''); $close.addClass('close'); $close.on('click', this._removeFile.bind(this)); // hidden var $hidden = $K.dom(''); $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(''); $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);