310 lines
9.9 KiB
JavaScript
310 lines
9.9 KiB
JavaScript
'use strict';
|
|
|
|
/*@
|
|
Ox.FileInput <f> File Input
|
|
options <o> Options
|
|
disabled <b|false> If true, the element is disabled
|
|
maxFiles <n|-1> Maximum number of files (or -1 for unlimited)
|
|
maxLines <n|-1> Maximum number of lines to display (or -1 for unlimited)
|
|
maxSize <n|-1> Maximum total file size in bytes (or -1 for unlimited)
|
|
value <a|[]> Value (array of file objects)
|
|
width <w|256> Width in px
|
|
self <o> Shared private variable
|
|
([options[, self]]) -> <o:Ox.Element> File Input
|
|
change <!> change
|
|
@*/
|
|
|
|
Ox.FileInput = function(options, self) {
|
|
|
|
self = self || {};
|
|
var that = Ox.Element({}, self)
|
|
.defaults({
|
|
disabled: false,
|
|
maxFiles: -1,
|
|
maxLines: -1,
|
|
maxSize: -1,
|
|
value: [],
|
|
width: 256
|
|
})
|
|
.options(options || {})
|
|
.update({
|
|
disabled: function() {
|
|
that[self.options.disabled ? 'addClass' : 'removeClass']('OxDisabled');
|
|
self.$button.options({disabled: self.options.disabled});
|
|
self.$input && self.$input[self.options.disabled ? 'hide' : 'show']();
|
|
}
|
|
})
|
|
.addClass('OxFileInput' + (self.options.disabled ? ' OxDisabled' : ''))
|
|
.css({width: self.options.width + 'px'});
|
|
|
|
self.multiple = self.options.maxFiles != 1;
|
|
self.size = getSize();
|
|
|
|
self.$bar = Ox.Bar({size: 14})
|
|
.css(
|
|
Ox.extend({
|
|
width: self.options.width - 2 + 'px'
|
|
}, self.multiple && self.options.value.length ? {
|
|
borderBottomLeftRadius: 0,
|
|
borderBottomRightRadius: 0
|
|
} : {})
|
|
)
|
|
.appendTo(that);
|
|
|
|
self.$title = $('<div>')
|
|
.css({
|
|
float: 'left',
|
|
width: self.options.width - 102 + 'px',
|
|
paddingLeft: '4px',
|
|
overflow: 'hidden',
|
|
textOverflow: 'ellipsis'
|
|
})
|
|
.html(getTitleText())
|
|
.appendTo(self.$bar);
|
|
|
|
self.$size = $('<div>')
|
|
.css({
|
|
float: 'left',
|
|
width: '64px',
|
|
height: '14px',
|
|
paddingRight: '16px',
|
|
textAlign: 'right'
|
|
})
|
|
.html(getSizeText())
|
|
.appendTo(self.$bar);
|
|
|
|
self.$button = Ox.Button({
|
|
disabled: self.options.disabled,
|
|
style: 'symbol',
|
|
title: self.multiple || self.options.value.length == 0
|
|
? 'add' : 'close',
|
|
type: 'image'
|
|
})
|
|
.attr({
|
|
title: self.multiple || self.options.value.length == 0
|
|
? '' : 'Clear'
|
|
})
|
|
.css({
|
|
float: 'left',
|
|
marginTop: '-1px'
|
|
})
|
|
.bindEvent({
|
|
click: clearFile
|
|
})
|
|
.appendTo(self.$bar);
|
|
|
|
if (self.multiple || self.options.value.length == 0) {
|
|
self.$input = renderInput();
|
|
self.options.disabled && self.$input.hide();
|
|
}
|
|
|
|
if (self.multiple) {
|
|
self.$files = $('<div>')
|
|
.addClass('OxFiles')
|
|
.css({
|
|
width: self.options.width - 2 + 'px',
|
|
height: getHeight()
|
|
})
|
|
.appendTo(that);
|
|
self.options.value.length == 0 && self.$files.hide();
|
|
self.$list = Ox.TableList({
|
|
columns: [
|
|
{
|
|
id: 'name',
|
|
visible: true,
|
|
width: self.options.width - 94
|
|
},
|
|
{
|
|
align: 'right',
|
|
format: function(value) {
|
|
return Ox.formatValue(value, 'B');
|
|
},
|
|
id: 'size',
|
|
visible: true,
|
|
width: 64
|
|
},
|
|
{
|
|
align: 'right',
|
|
format: function(value, data) {
|
|
return Ox.Button({
|
|
style: 'symbol',
|
|
title: 'close',
|
|
type: 'image'
|
|
})
|
|
.attr({title: Ox._('Remove File')})
|
|
.css({margin: '-1px -4px 0 0'})
|
|
.bindEvent({
|
|
click: function() {
|
|
self.$list.options({selected: [value]});
|
|
removeFiles([value]);
|
|
}
|
|
});
|
|
},
|
|
id: 'id',
|
|
visible: true,
|
|
width: 28
|
|
}
|
|
],
|
|
items: getItems(),
|
|
sort: [{key: 'name', operator: '+'}],
|
|
unique: 'id'
|
|
})
|
|
.css({
|
|
left: 0,
|
|
top: 0,
|
|
width: self.options.width - 2 + 'px',
|
|
height: '64px'
|
|
})
|
|
.bindEvent({
|
|
'delete': function(data) {
|
|
removeFiles(data.ids);
|
|
}
|
|
})
|
|
.appendTo(self.$files);
|
|
}
|
|
|
|
function addFiles(e) {
|
|
var filelist = e.target.files,
|
|
files = [];
|
|
Ox.loop(filelist.length, function(i) {
|
|
files.push(filelist.item(i));
|
|
});
|
|
files.sort(self.options.maxSize == -1 ? function(a, b) {
|
|
a = a.name.toLowerCase();
|
|
b = b.name.toLowerCase();
|
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
} : function(a, b) {
|
|
// if there is a max size,
|
|
// try to add small files first
|
|
return a.size - b.size;
|
|
}).forEach(function(file) {
|
|
if (!exists(file) && (
|
|
self.options.maxFiles == -1
|
|
|| self.options.value.length < self.options.maxFiles
|
|
) && (
|
|
self.options.maxSize == -1
|
|
|| self.size + file.size < self.options.maxSize
|
|
)) {
|
|
self.options.value.push(file);
|
|
self.size += file.size;
|
|
}
|
|
});
|
|
self.$title.html(getTitleText());
|
|
self.$size.html(getSizeText());
|
|
if (self.multiple) {
|
|
self.$bar.css({
|
|
borderBottomLeftRadius: 0,
|
|
borderBottomRightRadius: 1
|
|
});
|
|
self.$files.css({height: getHeight()}).show();
|
|
self.$list.options({items: getItems()});
|
|
if (
|
|
self.options.value.length == self.options.maxFiles
|
|
|| self.size == self.options.maxSize
|
|
) {
|
|
self.$button.options({disabled: true});
|
|
}
|
|
self.$input = renderInput();
|
|
} else {
|
|
self.$button.options({title: 'close'}).attr({title: Ox._('Clear')});
|
|
self.$input.remove();
|
|
}
|
|
that.triggerEvent('change', {value: self.options.value});
|
|
}
|
|
|
|
function clearFile() {
|
|
self.options.value = [];
|
|
self.size = 0;
|
|
self.$title.html(getTitleText());
|
|
self.$size.html(getSizeText());
|
|
self.$button.options({title: 'add'}).attr({title: ''});
|
|
self.$input = renderInput();
|
|
that.triggerEvent('change', {value: self.options.value});
|
|
}
|
|
|
|
function exists(file) {
|
|
return self.options.value.some(function(f) {
|
|
return f.name == file.name
|
|
&& f.size == file.size
|
|
&& Ox.isEqual(f.lastModifiedDate, file.lastModifiedDate);
|
|
});
|
|
}
|
|
|
|
function getHeight() {
|
|
return (
|
|
self.options.maxLines == -1
|
|
? self.options.value.length
|
|
: Math.min(self.options.value.length, self.options.maxLines)
|
|
) * 16 + 'px';
|
|
}
|
|
|
|
function getItems() {
|
|
return self.options.value.map(function(file, i) {
|
|
return {name: file.name, size: file.size, id: i};
|
|
});
|
|
}
|
|
|
|
function getSize() {
|
|
return self.options.value.reduce(function(prev, curr) {
|
|
return prev + curr.size;
|
|
}, 0);
|
|
}
|
|
|
|
function getSizeText() {
|
|
return self.size ? Ox.formatValue(self.size, 'B') : '';
|
|
}
|
|
|
|
function getTitleText() {
|
|
var length = self.options.value.length
|
|
return length == 0
|
|
? Ox._('No file' + (self.multiple ? 's' : '') + ' selected')
|
|
: self.multiple
|
|
? Ox.formatCount(length, Ox._('file'), Ox._('files'))
|
|
: self.options.value[0].name;
|
|
}
|
|
|
|
function removeFiles(ids) {
|
|
self.options.value = self.options.value.filter(function(v, i) {
|
|
return ids.indexOf(i) == -1;
|
|
});
|
|
self.size = getSize();
|
|
if (self.options.value.length == 0) {
|
|
self.$bar.css({
|
|
borderBottomLeftRadius: '8px',
|
|
borderBottomRightRadius: '8px'
|
|
});
|
|
self.$files.hide();
|
|
}
|
|
self.$title.html(getTitleText());
|
|
self.$size.html(getSizeText());
|
|
self.$list.options({items: getItems(), selected: []});
|
|
self.$files.css({height: getHeight()});
|
|
that.triggerEvent('change', {value: self.options.value});
|
|
}
|
|
|
|
function renderInput() {
|
|
self.$input && self.$input.remove();
|
|
return $('<input>')
|
|
.attr(
|
|
Ox.extend({
|
|
title: self.multiple ? Ox._('Add Files') : Ox._('Select File'),
|
|
type: 'file'
|
|
}, self.multiple ? {
|
|
multiple: true
|
|
} : {})
|
|
)
|
|
.css({
|
|
float: 'left',
|
|
width: '16px',
|
|
height: '14px',
|
|
margin: '-1px -7px 0 -16px',
|
|
opacity: 0
|
|
})
|
|
.on({
|
|
change: addFiles
|
|
})
|
|
.appendTo(self.$bar);
|
|
}
|
|
|
|
return that;
|
|
};
|