@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
650 lines (648 loc) • 22.6 kB
JavaScript
//#region ../src/kendo.filebrowser.js
const __meta__ = {
id: "filebrowser",
name: "FileBrowser",
category: "web",
description: "",
hidden: true,
depends: [
"selectable",
"listview",
"dropdownlist",
"upload",
"breadcrumb",
"icons"
]
};
(function($, undefined) {
var kendo = window.kendo, Widget = kendo.ui.Widget, isPlainObject = $.isPlainObject, extend = $.extend, encode = kendo.htmlEncode, isFunction = kendo.isFunction, trimSlashesRegExp = /(^\/|\/$)/g, CHANGE = "change", APPLY = "apply", ERROR = "error", CLICK = "click", NS = ".kendoFileBrowser", SEARCHBOXNS = ".kendoSearchBox", NAMEFIELD = "name", SIZEFIELD = "size", TYPEFIELD = "type", DEFAULTSORTORDER = {
field: TYPEFIELD,
dir: "asc"
}, EMPTYTILE = kendo.template(({ text }) => `<div class="k-listview-item k-listview-item-empty"><span class="k-file-preview"><span class="k-file-icon k-icon k-svg-icon k-i-none"></span></span><span class="k-file-name">${kendo.htmlEncode(text)}</span></div>`), UPLOADTEMPLATE = ({ messages }) => "<div class=\"k-upload k-upload-button-wrap\">" + "<div class=\"k-button k-upload-button\">" + kendo.ui.icon({
icon: "plus",
iconClass: "k-button-icon"
}) + `<span class="k-button-text">${kendo.htmlEncode(messages.uploadFile)}</span>` + "</div>" + "<input type=\"file\" name=\"file\" />" + "</div>", TOOLBARTMPL = ({ showCreate, showUpload, showDelete, messages }) => "<div class=\"k-widget k-filebrowser-toolbar k-toolbar k-floatwrap\">" + `${showCreate ? "<button type=\"button\" class=\"k-button k-icon-button\">" + kendo.ui.icon({
icon: "folder-add",
iconClass: "k-button-icon"
}) + "</button>" : ""}` + `${showUpload ? UPLOADTEMPLATE({ messages }) : ""}` + `${showDelete ? "<button type=\"button\" class=\"k-button k-icon-button k-disabled\">" + kendo.ui.icon({
icon: "x",
iconClass: "k-button-icon"
}) + "</button>" : ""}` + "<div class=\"k-tiles-arrange\">" + `<label>${kendo.htmlEncode(messages.orderBy)}: <select></select></label>` + "</div>" + "<span class=\"k-toolbar-spacer\"></span>" + "<input data-role=\"searchbox\" />" + "</div>";
extend(true, kendo.data, { schemas: { "filebrowser": {
data: function(data) {
return data.items || data || [];
},
model: {
id: "name",
fields: {
name: "name",
size: "size",
type: "type"
}
}
} } });
extend(true, kendo.data, { transports: { "filebrowser": kendo.data.RemoteTransport.extend({
init: function(options) {
kendo.data.RemoteTransport.fn.init.call(this, $.extend(true, {}, this.options, options));
},
_call: function(type, options) {
options.data = $.extend({}, options.data, { path: this.options.path() });
if (isFunction(this.options[type])) {
this.options[type].call(this, options);
} else {
kendo.data.RemoteTransport.fn[type].call(this, options);
}
},
read: function(options) {
this._call("read", options);
},
create: function(options) {
this._call("create", options);
},
destroy: function(options) {
this._call("destroy", options);
},
update: function() {},
options: {
read: { type: "POST" },
update: { type: "POST" },
create: { type: "POST" },
destroy: { type: "POST" }
}
}) } });
function bindDragEventWrappers(element, onDragEnter, onDragLeave) {
var hideInterval, lastDrag;
element.on("dragenter" + NS, function() {
onDragEnter();
lastDrag = new Date();
if (!hideInterval) {
hideInterval = setInterval(function() {
var sinceLastDrag = new Date() - lastDrag;
if (sinceLastDrag > 100) {
onDragLeave();
clearInterval(hideInterval);
hideInterval = null;
}
}, 100);
}
}).on("dragover" + NS, function() {
lastDrag = new Date();
});
}
function concatPaths(path, name) {
if (path === undefined || !path.match(/\/$/)) {
path = (path || "") + "/";
}
return path + name;
}
function sizeFormatter(value) {
if (!value) {
return "";
}
var suffix = " bytes";
if (value >= 1073741824) {
suffix = " GB";
value /= 1073741824;
} else if (value >= 1048576) {
suffix = " MB";
value /= 1048576;
} else if (value >= 1024) {
suffix = " KB";
value /= 1024;
}
return Math.round(value * 100) / 100 + suffix;
}
function fieldName(fields, name) {
var descriptor = fields[name];
if (isPlainObject(descriptor)) {
return descriptor.from || descriptor.field || name;
}
return descriptor;
}
var FileBrowser = Widget.extend({
init: function(element, options) {
var that = this;
options = options || {};
Widget.fn.init.call(that, element, options);
that.element.addClass("k-filebrowser");
that.element.on(CLICK + NS, ".k-filebrowser-toolbar button:not(.k-disabled):has(.k-i-x,.k-svg-i-x)", that._deleteClick.bind(that)).on(CLICK + NS, ".k-filebrowser-toolbar button:not(.k-disabled):has(.k-i-folder-add,.k-svg-i-folder-add)", that._addClick.bind(that)).on("keydown" + NS, ".k-listview-item.k-selected input", that._directoryKeyDown.bind(that)).on("blur" + NS, ".k-listview-item.k-selected input", that._directoryBlur.bind(that));
that._dataSource();
that.refresh();
that.path(that.options.path);
},
options: {
name: "FileBrowser",
messages: {
uploadFile: "Upload",
orderBy: "Arrange by",
orderByName: "Name",
orderBySize: "Size",
directoryNotFound: "A directory with this name was not found.",
emptyFolder: "Empty Folder",
deleteFile: "Are you sure you want to delete {0}?",
invalidFileType: "The selected file {0} is not valid. Supported file types are {1}.",
overwriteFile: "A file with name {0} already exists in the current directory. Do you want to overwrite it?",
dropFilesHere: "drop file here to upload",
search: "Search"
},
transport: {},
path: "/",
fileTypes: "*.*"
},
events: [
ERROR,
CHANGE,
APPLY
],
destroy: function() {
var that = this;
Widget.fn.destroy.call(that);
that.dataSource.unbind(ERROR, that._errorHandler);
that.element.add(that.list).add(that.toolbar).off(NS);
kendo.destroy(that.element);
},
value: function() {
var that = this, selected = that._selectedItem(), path, fileUrl = that.options.transport.fileUrl;
if (selected && selected.get(TYPEFIELD) === "f") {
path = concatPaths(that.path(), selected.get(NAMEFIELD)).replace(trimSlashesRegExp, "");
if (fileUrl) {
path = isFunction(fileUrl) ? fileUrl(path) : kendo.format(fileUrl, encodeURIComponent(path));
}
return path;
}
},
_selectedItem: function() {
var listView = this.listView, selected = listView.select();
if (selected.length) {
return this.dataSource.getByUid(selected.attr(kendo.attr("uid")));
}
},
_toolbar: function() {
var that = this, template = kendo.template(TOOLBARTMPL), messages = that.options.messages, arrangeBy = [{
text: messages.orderByName,
value: "name"
}, {
text: messages.orderBySize,
value: "size"
}];
that.toolbar = $(template({
messages,
showUpload: that.options.transport.uploadUrl,
showCreate: that.options.transport.create,
showDelete: that.options.transport.destroy
})).appendTo(that.element).find(".k-upload input").kendoUpload({
multiple: false,
localization: { dropFilesHere: messages.dropFilesHere },
async: {
saveUrl: that.options.transport.uploadUrl,
autoUpload: true
},
upload: that._fileUpload.bind(that),
error: function(e) {
that._error({
xhr: e.XMLHttpRequest,
status: "error"
});
}
}).end();
that.upload = that.toolbar.find(".k-upload input").data("kendoUpload");
that.arrangeBy = that.toolbar.find(".k-tiles-arrange select").kendoDropDownList({
dataSource: arrangeBy,
dataTextField: "text",
dataValueField: "value",
change: function() {
that.orderBy(this.value());
}
}).data("kendoDropDownList");
that.searchBox = that.toolbar.find("input[data-role='searchbox']").kendoSearchBox({
label: that.options.messages.search,
change: function() {
that.search(this.value());
}
}).data("kendoSearchBox");
that._attachDropzoneEvents();
},
_attachDropzoneEvents: function() {
var that = this;
if (that.options.transport.uploadUrl) {
bindDragEventWrappers($(document.documentElement), that._dropEnter.bind(that), that._dropLeave.bind(that));
that._scrollHandler = that._positionDropzone.bind(that);
}
},
_dropEnter: function() {
this._positionDropzone();
$(document).on("scroll" + NS, this._scrollHandler);
},
_dropLeave: function() {
this._removeDropzone();
$(document).off("scroll" + NS, this._scrollHandler);
},
_positionDropzone: function() {
var that = this, element = that.element, offset = element.offset();
that.toolbar.find(".k-dropzone").addClass("k-filebrowser-dropzone").offset(offset).css({
width: element[0].clientWidth,
height: element[0].clientHeight,
lineHeight: element[0].clientHeight + "px"
});
},
_removeDropzone: function() {
this.toolbar.find(".k-dropzone").removeClass("k-filebrowser-dropzone").css({
width: "",
height: "",
lineHeight: "",
top: "",
left: ""
});
},
_deleteClick: function() {
var that = this, item = that.listView.select(), message = encode(kendo.format(that.options.messages.deleteFile, item.find(".k-file-name").text()));
if (item.length && that._showMessage(message, "confirm")) {
that.listView.remove(item);
}
},
_addClick: function() {
this.createDirectory();
},
_getFieldName: function(name) {
return fieldName(this.dataSource.reader.model.fields, name);
},
_fileUpload: function(e) {
var that = this, options = that.options, fileTypes = options.fileTypes, filterRegExp = new RegExp(("(" + fileTypes.split(",").join(")|(") + ")").replace(/\*\./g, ".*."), "i"), fileName = e.files[0].name, fileSize = e.files[0].size, fileNameField = NAMEFIELD, sizeField = SIZEFIELD, file;
if (filterRegExp.test(fileName)) {
e.data = { path: that.path() };
file = that._createFile(fileName, fileSize);
if (!file) {
e.preventDefault();
} else {
that.upload.one("success", function(e) {
var model = that._insertFileToList(file);
if (model._override) {
model.set(fileNameField, e.response[that._getFieldName(fileNameField)]);
model.set(sizeField, e.response[that._getFieldName(sizeField)]);
that.listView.dataSource.pushUpdate(model);
}
that._tiles = that.listView.items().filter("[" + kendo.attr("type") + "=f]");
});
}
} else {
e.preventDefault();
that._showMessage(encode(kendo.format(options.messages.invalidFileType, fileName, fileTypes)));
}
},
_findFile: function(name) {
var data = this.dataSource.data(), idx, result, typeField = TYPEFIELD, nameField = NAMEFIELD, length;
name = name.toLowerCase();
for (idx = 0, length = data.length; idx < length; idx++) {
if (data[idx].get(typeField) === "f" && data[idx].get(nameField).toLowerCase() === name) {
result = data[idx];
break;
}
}
return result;
},
_createFile: function(fileName, fileSize) {
var that = this, model = {}, typeField = TYPEFIELD, file = that._findFile(fileName);
if (file) {
if (!that._showMessage(encode(kendo.format(that.options.messages.overwriteFile, fileName)), "confirm")) {
return null;
} else {
file._override = true;
return file;
}
}
model[typeField] = "f";
model[NAMEFIELD] = fileName;
model[SIZEFIELD] = fileSize;
return model;
},
_insertFileToList: function(model) {
var index;
if (model._override) {
return model;
}
var dataSource = this.dataSource;
var view = dataSource.view();
for (var i = 0, length = view.length; i < length; i++) {
if (view[i].get(TYPEFIELD) === "f") {
index = i;
break;
}
}
return dataSource.insert(++index, model);
},
createDirectory: function() {
var that = this, idx, length, lastDirectoryIdx = 0, typeField = TYPEFIELD, nameField = NAMEFIELD, view = that.dataSource.data(), name = that._nameDirectory(), model = new that.dataSource.reader.model();
for (idx = 0, length = view.length; idx < length; idx++) {
if (view[idx].get(typeField) === "d") {
lastDirectoryIdx = idx;
}
}
model.set(typeField, "d");
model.set(nameField, name);
that.listView.one("dataBound", function() {
var selected = that.listView.items().filter("[" + kendo.attr("uid") + "=" + model.uid + "]");
if (selected.length) {
this.edit(selected);
}
this.element.scrollTop(selected.attr("offsetTop") - this.element[0].offsetHeight);
setTimeout(function() {
that.listView.element.find(".k-edit-item input").select();
});
}).one("save", function(e) {
var value = e.model.get(nameField);
if (!value) {
e.model.set(nameField, name);
} else {
e.model.set(nameField, that._nameExists(value, model.uid) ? that._nameDirectory() : value);
}
});
that.dataSource.insert(++lastDirectoryIdx, model);
},
_directoryKeyDown: function(e) {
if (e.keyCode == 13) {
e.currentTarget.blur();
}
},
_directoryBlur: function() {
this.listView.save();
},
_nameExists: function(name, uid) {
var data = this.dataSource.data(), typeField = TYPEFIELD, nameField = NAMEFIELD, idx, length;
for (idx = 0, length = data.length; idx < length; idx++) {
if (data[idx].get(typeField) === "d" && data[idx].get(nameField).toLowerCase() === name.toLowerCase() && data[idx].uid !== uid) {
return true;
}
}
return false;
},
_nameDirectory: function() {
var name = "New folder", data = this.dataSource.data(), directoryNames = [], typeField = TYPEFIELD, nameField = NAMEFIELD, candidate, idx, length;
for (idx = 0, length = data.length; idx < length; idx++) {
if (data[idx].get(typeField) === "d" && data[idx].get(nameField).toLowerCase().indexOf(name.toLowerCase()) > -1) {
directoryNames.push(data[idx].get(nameField));
}
}
if ($.inArray(name, directoryNames) > -1) {
idx = 2;
do {
candidate = name + " (" + idx + ")";
idx++;
} while ($.inArray(candidate, directoryNames) > -1);
name = candidate;
}
return name;
},
orderBy: function(field) {
this.dataSource.sort([{
field: TYPEFIELD,
dir: "asc"
}, {
field,
dir: "asc"
}]);
},
search: function(name) {
this.dataSource.filter({
field: NAMEFIELD,
operator: "contains",
value: name
});
},
_content: function() {
var that = this;
that.list = $("<div class=\"k-filemanager-listview\" />").appendTo(that.element).on("dblclick" + NS, ".k-listview-item", that._dblClick.bind(that));
that.listView = new kendo.ui.ListView(that.list, {
layout: "flex",
flex: {
direction: "row",
wrap: "wrap"
},
dataSource: that.dataSource,
template: that._itemTmpl(),
editTemplate: that._editTmpl(),
selectable: true,
autoBind: false,
dataBinding: function(e) {
that.toolbar.find(".k-i-x,.k-svg-i-x").parent().addClass("k-disabled");
if (e.action === "remove" || e.action === "sync") {
e.preventDefault();
kendo.ui.progress(that.listView.content, false);
kendo.ui.progress(that.listView.wrapper, false);
}
},
dataBound: function() {
if (that.dataSource.view().length) {
that._tiles = this.items().filter("[" + kendo.attr("type") + "=f]");
} else {
this.content.append(EMPTYTILE({ text: that.options.messages.emptyFolder }));
}
},
change: that._listViewChange.bind(that)
});
},
_dblClick: function(e) {
var that = this, li = $(e.currentTarget);
if (li.hasClass("k-edit-item")) {
that._directoryBlur();
}
if (li.filter("[" + kendo.attr("type") + "=d]").length) {
var folder = that.dataSource.getByUid(li.attr(kendo.attr("uid")));
if (folder) {
that.path(concatPaths(that.path(), folder.get(NAMEFIELD)));
that.breadcrumbs.value("/" + that.path());
}
} else if (li.filter("[" + kendo.attr("type") + "=f]").length) {
that.trigger(APPLY);
}
},
_listViewChange: function() {
var selected = this._selectedItem();
if (selected) {
this.toolbar.find(".k-i-x,.k-svg-i-x").parent().removeClass("k-disabled");
this.trigger(CHANGE, { selected });
}
},
_dataSource: function() {
var that = this, options = that.options, transport = options.transport, typeSortOrder = extend({}, DEFAULTSORTORDER), nameSortOrder = {
field: NAMEFIELD,
dir: "asc"
}, schema, dataSource = {
type: transport.type || "filebrowser",
sort: [typeSortOrder, nameSortOrder]
};
if (isPlainObject(transport)) {
transport.path = that.path.bind(that);
dataSource.transport = transport;
}
if (isPlainObject(options.schema)) {
dataSource.schema = options.schema;
} else if (transport.type && isPlainObject(kendo.data.schemas[transport.type])) {
schema = kendo.data.schemas[transport.type];
}
if (that.dataSource && that._errorHandler) {
that.dataSource.unbind(ERROR, that._errorHandler);
} else {
that._errorHandler = that._error.bind(that);
}
that.dataSource = kendo.data.DataSource.create(dataSource).bind(ERROR, that._errorHandler);
},
_navigation: function() {
var that = this, navigation = $("<div class=\"k-floatwrap\"><nav></nav></div>").appendTo(this.element);
that.breadcrumbs = navigation.find("nav").first().kendoBreadcrumb({
editable: true,
gap: 50,
value: that.options.path || "/",
change: function() {
that.path(this.value());
}
}).data("kendoBreadcrumb");
},
_error: function(e) {
var that = this, status;
if (!that.trigger(ERROR, e)) {
status = e.xhr.status;
if (e.status == "error") {
if (status == "404") {
that._showMessage(kendo.htmlEncode(that.options.messages.directoryNotFound));
} else if (status != "0") {
that._showMessage("Error! The requested URL returned " + status + " - " + e.xhr.statusText);
}
} else if (status == "timeout") {
that._showMessage("Error! Server timeout.");
}
var dataSource = that.dataSource;
if (dataSource.hasChanges()) {
dataSource.cancelChanges();
}
}
},
_showMessage: function(message, type) {
return window[type || "alert"](message);
},
refresh: function() {
var that = this;
that._navigation();
that._toolbar();
that._content();
},
_editTmpl: function() {
const result = (data) => `<div class="k-listview-item k-selected" ${kendo.attr("uid")}="${data.uid}">` + `${data[TYPEFIELD] === "d" ? "<div class=\"k-file-preview\">" + kendo.ui.icon({
icon: "folder",
iconClass: "k-file-icon",
size: "xxxlarge"
}) + "</div>" : "<div class=\"k-file-preview\"><span class=\"k-file-icon k-icon k-i-loading\"></span></div>"}` + `${data[TYPEFIELD] === "d" ? `<span class="k-file-name">
<span class="k-textbox k-input">
<input class="k-input-inner" ${kendo.attr("bind")}="value:${NAMEFIELD}"/>
</span>
</span>` : ""}` + `</div>`;
return kendo.template(result);
},
_itemTmpl: function() {
const result = (data) => `<div class="k-listview-item" ${kendo.attr("uid")}="${data.uid}" ${kendo.attr("type")}="${data[TYPEFIELD]}">` + `${data[TYPEFIELD] === "d" ? "<div class=\"k-file-preview\">" + kendo.ui.icon({
icon: "folder",
iconClass: "k-file-icon",
size: "xxxlarge"
}) + "</div>" : "<div class=\"k-file-preview\">" + kendo.ui.icon({
icon: "file",
iconClass: "k-file-icon",
size: "xxxlarge"
}) + "</div>"}` + `<span class="k-file-name">${data[NAMEFIELD]}</span>` + `${data[TYPEFIELD] === "f" ? `<span class="k-file-size">${sizeFormatter(data[SIZEFIELD])}</span>` : ""}` + `</div>`;
return kendo.template(result);
},
path: function(value) {
var that = this, path = that._path || "";
if (value !== undefined) {
that._path = value.replace(trimSlashesRegExp, "") + "/";
that.dataSource.read({ path: that._path });
return;
}
if (path) {
path = path.replace(trimSlashesRegExp, "");
}
return path === "/" || path === "" ? "" : path + "/";
}
});
var SearchBox = Widget.extend({
init: function(element, options) {
var that = this;
options = options || {};
Widget.fn.init.call(that, element, options);
that.element.attr("placeholder", that.options.label);
that._wrapper();
that.element.on("keydown" + SEARCHBOXNS, that._keydown.bind(that)).on("change" + SEARCHBOXNS, that._updateValue.bind(that));
that.wrapper.on(CLICK + SEARCHBOXNS, "a", that._click.bind(that));
},
options: {
name: "SearchBox",
label: "Search",
value: ""
},
events: [CHANGE],
destroy: function() {
var that = this;
that.wrapper.add(that.element).add(that.label).off(SEARCHBOXNS);
Widget.fn.destroy.call(that);
},
_keydown: function(e) {
if (e.keyCode === 13) {
this._updateValue();
}
},
_click: function(e) {
e.preventDefault();
this._updateValue();
},
_updateValue: function() {
var that = this, value = that.element.val();
if (value !== that.value()) {
that.value(value);
that.trigger(CHANGE);
}
},
_blur: function() {
this._updateValue();
},
_focus: function() {
this.label.hide();
},
_wrapper: function() {
var element = this.element, wrapper = element.parents(".k-search-wrap");
element[0].style.width = "";
element.addClass("k-input-inner");
if (!wrapper.length) {
wrapper = element.wrap($("<div class=\"k-widget k-search-wrap\"><span class=\"k-textbox k-input\"></span></div>")).parents(".k-search-wrap");
$("<span class=\"k-input-suffix\">" + kendo.ui.icon($("<a href=\"#\" />"), {
icon: "search",
iconClass: "k-search"
}) + "</span>").appendTo(wrapper.find(".k-textbox"));
}
this.wrapper = wrapper;
this.label = wrapper.find(">label");
},
value: function(value) {
var that = this;
if (value !== undefined) {
that.options.value = value;
that.element.val(value);
return;
}
return that.options.value;
}
});
kendo.ui.plugin(FileBrowser);
kendo.ui.plugin(SearchBox);
})(window.kendo.jQuery);
var kendo_filebrowser_default = kendo;
//#endregion
Object.defineProperty(exports, '__meta__', {
enumerable: true,
get: function () {
return __meta__;
}
});
Object.defineProperty(exports, 'kendo_filebrowser_default', {
enumerable: true,
get: function () {
return kendo_filebrowser_default;
}
});