Merge pull request #18630 from owncloud/files-combineuploadbutton
Combine upload action into the "New" menu
This commit is contained in:
commit
004de1425e
|
@ -18,11 +18,6 @@
|
||||||
z-index: -30;
|
z-index: -30;
|
||||||
}
|
}
|
||||||
|
|
||||||
#new {
|
|
||||||
z-index: 1010;
|
|
||||||
float: left;
|
|
||||||
padding: 0 !important; /* override default control bar button padding */
|
|
||||||
}
|
|
||||||
#trash {
|
#trash {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
float: right;
|
float: right;
|
||||||
|
@ -30,49 +25,8 @@
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
#new > a {
|
|
||||||
padding: 14px 10px;
|
|
||||||
position: relative;
|
|
||||||
top: 7px;
|
|
||||||
}
|
|
||||||
#new.active {
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
border-bottom: none;
|
|
||||||
background: #f8f8f8;
|
|
||||||
}
|
|
||||||
#new > ul {
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
min-width: 112px;
|
|
||||||
z-index: -10;
|
|
||||||
padding: 8px;
|
|
||||||
padding-bottom: 0;
|
|
||||||
margin-top: 13.5px;
|
|
||||||
margin-left: -1px;
|
|
||||||
text-align: left;
|
|
||||||
background: #f8f8f8;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border: 1px solid rgba(240, 240, 240, 0.9);
|
|
||||||
border-radius: 5px;
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
box-shadow: 0 2px 7px rgba(170,170,170,.4);
|
|
||||||
}
|
|
||||||
#new > ul > li {
|
|
||||||
height: 36px;
|
|
||||||
margin: 5px;
|
|
||||||
padding-left: 42px;
|
|
||||||
padding-bottom: 2px;
|
|
||||||
background-position: left center;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
#new > ul > li > p {
|
|
||||||
cursor: pointer;
|
|
||||||
padding-top: 7px;
|
|
||||||
padding-bottom: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#new .error, #fileList .error {
|
.newFileMenu .error, #fileList .error {
|
||||||
color: #e9322d;
|
color: #e9322d;
|
||||||
border-color: #e9322d;
|
border-color: #e9322d;
|
||||||
-webkit-box-shadow: 0 0 6px #f8b9b7;
|
-webkit-box-shadow: 0 0 6px #f8b9b7;
|
||||||
|
@ -144,6 +98,30 @@
|
||||||
margin-bottom: 44px;
|
margin-bottom: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#app-navigation .nav-files a.nav-icon-files {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
/* button needs overrides due to navigation styles */
|
||||||
|
#app-navigation .nav-files a.new {
|
||||||
|
width: 40px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0 10px;
|
||||||
|
margin: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-navigation .nav-files a {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-navigation .nav-files a.new.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-navigation .nav-files a.new.disabled {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
#filestable tbody tr {
|
#filestable tbody tr {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
@ -600,7 +578,8 @@ a.action > img {
|
||||||
#fileList a.action.action-menu {
|
#fileList a.action.action-menu {
|
||||||
padding: 17px 14px;
|
padding: 17px 14px;
|
||||||
}
|
}
|
||||||
#fileList .fileActionsMenu {
|
|
||||||
|
#fileList .popovermenu {
|
||||||
margin-right: 21px;
|
margin-right: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,13 +634,13 @@ a.action > img {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* properly display actions in the popover menu */
|
/* properly display actions in the popover menu */
|
||||||
#fileList .fileActionsMenu .action {
|
#fileList .popovermenu .action {
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)" !important;
|
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)" !important;
|
||||||
filter: alpha(opacity=50) !important;
|
filter: alpha(opacity=50) !important;
|
||||||
opacity: .5 !important;
|
opacity: .5 !important;
|
||||||
}
|
}
|
||||||
#fileList .fileActionsMenu .action:hover,
|
#fileList .popovermenu .action:hover,
|
||||||
#fileList .fileActionsMenu .action:focus {
|
#fileList .popovermenu .action:focus {
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)" !important;
|
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)" !important;
|
||||||
filter: alpha(opacity=100) !important;
|
filter: alpha(opacity=100) !important;
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
|
@ -745,43 +724,56 @@ table.dragshadow td.size {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fileActionsMenu {
|
#fileList .popovermenu a.action img {
|
||||||
padding: 4px 12px;
|
|
||||||
}
|
|
||||||
.fileActionsMenu li {
|
|
||||||
padding: 5px 0;
|
|
||||||
}
|
|
||||||
#fileList .fileActionsMenu a.action img {
|
|
||||||
padding: initial;
|
padding: initial;
|
||||||
}
|
}
|
||||||
#fileList .fileActionsMenu a.action {
|
|
||||||
|
#fileList .popovermenu a.action {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin: -10px;
|
margin: -10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fileActionsMenu.hidden {
|
.newFileMenu {
|
||||||
display: none;
|
width: 140px;
|
||||||
|
margin-left: -56px;
|
||||||
|
margin-top: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#fileList .fileActionsMenu .action {
|
.newFileMenu .menuitem {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.newFileMenu.popovermenu .menuitem .icon {
|
||||||
|
margin-bottom: -2px;
|
||||||
|
}
|
||||||
|
.newFileMenu.popovermenu a.menuitem,
|
||||||
|
.newFileMenu.popovermenu label.menuitem,
|
||||||
|
.newFileMenu.popovermenu .menuitem {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newFileMenu.bubble:after {
|
||||||
|
left: 75px;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
.newFileMenu.bubble:before {
|
||||||
|
left: 75px;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newFileMenu .filenameform {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newFileMenu .filenameform input {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#fileList .popovermenu .action {
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
color: #000;
|
color: #000;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fileActionsMenu .action img,
|
|
||||||
.fileActionsMenu .action .no-icon {
|
|
||||||
display: inline-block;
|
|
||||||
width: 16px;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fileActionsMenu .action {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fileActionsMenu li:hover .action {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,20 +24,6 @@
|
||||||
}
|
}
|
||||||
.file_upload_target { display:none; }
|
.file_upload_target { display:none; }
|
||||||
.file_upload_form { display:inline; float:left; margin:0; padding:0; cursor:pointer; overflow:visible; }
|
.file_upload_form { display:inline; float:left; margin:0; padding:0; cursor:pointer; overflow:visible; }
|
||||||
#file_upload_start {
|
|
||||||
position: relative;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 44px;
|
|
||||||
height: 44px;
|
|
||||||
margin: -5px -3px;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 16px;
|
|
||||||
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0;
|
|
||||||
z-index: 20;
|
|
||||||
cursor: pointer;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#uploadprogresswrapper, #uploadprogresswrapper * {
|
#uploadprogresswrapper, #uploadprogresswrapper * {
|
||||||
-moz-box-sizing: border-box;
|
-moz-box-sizing: border-box;
|
||||||
|
|
|
@ -38,6 +38,7 @@ OCP\Util::addStyle('files', 'upload');
|
||||||
OCP\Util::addStyle('files', 'mobile');
|
OCP\Util::addStyle('files', 'mobile');
|
||||||
OCP\Util::addscript('files', 'app');
|
OCP\Util::addscript('files', 'app');
|
||||||
OCP\Util::addscript('files', 'file-upload');
|
OCP\Util::addscript('files', 'file-upload');
|
||||||
|
OCP\Util::addscript('files', 'newfilemenu');
|
||||||
OCP\Util::addscript('files', 'jquery.iframe-transport');
|
OCP\Util::addscript('files', 'jquery.iframe-transport');
|
||||||
OCP\Util::addscript('files', 'jquery.fileupload');
|
OCP\Util::addscript('files', 'jquery.fileupload');
|
||||||
OCP\Util::addscript('files', 'jquery-visibility');
|
OCP\Util::addscript('files', 'jquery-visibility');
|
||||||
|
|
|
@ -551,155 +551,6 @@ OC.Upload = {
|
||||||
$('#file_upload_start').attr('multiple', 'multiple');
|
$('#file_upload_start').attr('multiple', 'multiple');
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).click(function(ev) {
|
|
||||||
// do not close when clicking in the dropdown
|
|
||||||
if ($(ev.target).closest('#new').length){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$('#new>ul').hide();
|
|
||||||
$('#new').removeClass('active');
|
|
||||||
if ($('#new .error').length > 0) {
|
|
||||||
$('#new .error').tipsy('hide');
|
|
||||||
}
|
|
||||||
$('#new li').each(function(i,element) {
|
|
||||||
if ($(element).children('p').length === 0) {
|
|
||||||
$(element).children('form').remove();
|
|
||||||
$(element).append('<p>' + $(element).data('text') + '</p>');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
$('#new').click(function(event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
});
|
|
||||||
$('#new>a').click(function() {
|
|
||||||
$('#new>ul').toggle();
|
|
||||||
$('#new').toggleClass('active');
|
|
||||||
});
|
|
||||||
$('#new li').click(function() {
|
|
||||||
if ($(this).children('p').length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#new .error').tipsy('hide');
|
|
||||||
|
|
||||||
$('#new li').each(function(i, element) {
|
|
||||||
if ($(element).children('p').length === 0) {
|
|
||||||
$(element).children('form').remove();
|
|
||||||
$(element).append('<p>' + $(element).data('text') + '</p>');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var type = $(this).data('type');
|
|
||||||
var text = $(this).children('p').text();
|
|
||||||
$(this).data('text', text);
|
|
||||||
$(this).children('p').remove();
|
|
||||||
|
|
||||||
// add input field
|
|
||||||
var form = $('<form></form>');
|
|
||||||
var input = $('<input type="text">');
|
|
||||||
var newName = $(this).attr('data-newname') || '';
|
|
||||||
var fileType = 'input-' + $(this).attr('data-type');
|
|
||||||
if (newName) {
|
|
||||||
input.val(newName);
|
|
||||||
input.attr('id', fileType);
|
|
||||||
}
|
|
||||||
var label = $('<label class="hidden-visually" for="">' + escapeHTML(newName) + '</label>');
|
|
||||||
label.attr('for', fileType);
|
|
||||||
|
|
||||||
form.append(label).append(input);
|
|
||||||
$(this).append(form);
|
|
||||||
var lastPos;
|
|
||||||
var checkInput = function () {
|
|
||||||
var filename = input.val();
|
|
||||||
if (!Files.isFileNameValid(filename)) {
|
|
||||||
// Files.isFileNameValid(filename) throws an exception itself
|
|
||||||
} else if (FileList.inList(filename)) {
|
|
||||||
throw t('files', '{new_name} already exists', {new_name: filename});
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// verify filename on typing
|
|
||||||
input.keyup(function(event) {
|
|
||||||
try {
|
|
||||||
checkInput();
|
|
||||||
input.tipsy('hide');
|
|
||||||
input.removeClass('error');
|
|
||||||
} catch (error) {
|
|
||||||
input.attr('title', error);
|
|
||||||
input.tipsy({gravity: 'w', trigger: 'manual'});
|
|
||||||
input.tipsy('show');
|
|
||||||
input.addClass('error');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
input.focus();
|
|
||||||
// pre select name up to the extension
|
|
||||||
lastPos = newName.lastIndexOf('.');
|
|
||||||
if (lastPos === -1) {
|
|
||||||
lastPos = newName.length;
|
|
||||||
}
|
|
||||||
input.selectRange(0, lastPos);
|
|
||||||
form.submit(function(event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
event.preventDefault();
|
|
||||||
try {
|
|
||||||
checkInput();
|
|
||||||
var newname = input.val();
|
|
||||||
if (FileList.lastAction) {
|
|
||||||
FileList.lastAction();
|
|
||||||
}
|
|
||||||
var name = FileList.getUniqueName(newname);
|
|
||||||
switch(type) {
|
|
||||||
case 'file':
|
|
||||||
$.post(
|
|
||||||
OC.filePath('files', 'ajax', 'newfile.php'),
|
|
||||||
{
|
|
||||||
dir: FileList.getCurrentDirectory(),
|
|
||||||
filename: name
|
|
||||||
},
|
|
||||||
function(result) {
|
|
||||||
if (result.status === 'success') {
|
|
||||||
FileList.add(result.data, {animate: true, scrollTo: true});
|
|
||||||
} else {
|
|
||||||
OC.dialogs.alert(result.data.message, t('core', 'Could not create file'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'folder':
|
|
||||||
$.post(
|
|
||||||
OC.filePath('files','ajax','newfolder.php'),
|
|
||||||
{
|
|
||||||
dir: FileList.getCurrentDirectory(),
|
|
||||||
foldername: name
|
|
||||||
},
|
|
||||||
function(result) {
|
|
||||||
if (result.status === 'success') {
|
|
||||||
FileList.add(result.data, {animate: true, scrollTo: true});
|
|
||||||
} else {
|
|
||||||
OC.dialogs.alert(result.data.message, t('core', 'Could not create folder'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var li = form.parent();
|
|
||||||
form.remove();
|
|
||||||
/* workaround for IE 9&10 click event trap, 2 lines: */
|
|
||||||
$('input').first().focus();
|
|
||||||
$('#content').focus();
|
|
||||||
li.append('<p>' + li.data('text') + '</p>');
|
|
||||||
$('#new>a').click();
|
|
||||||
} catch (error) {
|
|
||||||
input.attr('title', error);
|
|
||||||
input.tipsy({gravity: 'w', trigger: 'manual'});
|
|
||||||
input.tipsy('show');
|
|
||||||
input.addClass('error');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
window.file_upload_param = file_upload_param;
|
window.file_upload_param = file_upload_param;
|
||||||
return file_upload_param;
|
return file_upload_param;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
'<ul>' +
|
'<ul>' +
|
||||||
'{{#each items}}' +
|
'{{#each items}}' +
|
||||||
'<li>' +
|
'<li>' +
|
||||||
'<a href="#" class="action action-{{nameLowerCase}} permanent" data-action="{{name}}">{{#if icon}}<img src="{{icon}}"/>{{else}}<span class="no-icon"></span>{{/if}}<span>{{displayName}}</span></a>' +
|
'<a href="#" class="menuitem action action-{{nameLowerCase}} permanent" data-action="{{name}}">{{#if icon}}<img class="icon" src="{{icon}}"/>{{else}}<span class="no-icon"></span>{{/if}}<span>{{displayName}}</span></a>' +
|
||||||
'</li>' +
|
'</li>' +
|
||||||
'{{/each}}' +
|
'{{/each}}' +
|
||||||
'</ul>';
|
'</ul>';
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
*/
|
*/
|
||||||
var FileActionsMenu = OC.Backbone.View.extend({
|
var FileActionsMenu = OC.Backbone.View.extend({
|
||||||
tagName: 'div',
|
tagName: 'div',
|
||||||
className: 'fileActionsMenu bubble hidden open menu',
|
className: 'fileActionsMenu popovermenu bubble hidden open menu',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current context
|
* Current context
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
|
var TEMPLATE_ADDBUTTON = '<a href="#" class="button new" title="{{addText}}"><img src="{{iconUrl}}"></img></a>';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class OCA.Files.FileList
|
* @class OCA.Files.FileList
|
||||||
* @classdesc
|
* @classdesc
|
||||||
|
@ -220,6 +223,8 @@
|
||||||
|
|
||||||
this.$el.find('#controls').prepend(this.breadcrumb.$el);
|
this.$el.find('#controls').prepend(this.breadcrumb.$el);
|
||||||
|
|
||||||
|
this._renderNewButton();
|
||||||
|
|
||||||
this.$el.find('thead th .columntitle').click(_.bind(this._onClickHeader, this));
|
this.$el.find('thead th .columntitle').click(_.bind(this._onClickHeader, this));
|
||||||
|
|
||||||
this._onResize = _.debounce(_.bind(this._onResize, this), 100);
|
this._onResize = _.debounce(_.bind(this._onResize, this), 100);
|
||||||
|
@ -262,6 +267,12 @@
|
||||||
* Destroy / uninitialize this instance.
|
* Destroy / uninitialize this instance.
|
||||||
*/
|
*/
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
|
if (this._newFileMenu) {
|
||||||
|
this._newFileMenu.remove();
|
||||||
|
}
|
||||||
|
if (this._newButton) {
|
||||||
|
this._newButton.remove();
|
||||||
|
}
|
||||||
// TODO: also unregister other event handlers
|
// TODO: also unregister other event handlers
|
||||||
this.fileActions.off('registerAction', this._onFileActionsUpdated);
|
this.fileActions.off('registerAction', this._onFileActionsUpdated);
|
||||||
this.fileActions.off('setDefault', this._onFileActionsUpdated);
|
this.fileActions.off('setDefault', this._onFileActionsUpdated);
|
||||||
|
@ -1730,6 +1741,106 @@
|
||||||
form.trigger('submit');
|
form.trigger('submit');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an empty file inside the current directory.
|
||||||
|
*
|
||||||
|
* @param {string} name name of the file
|
||||||
|
*
|
||||||
|
* @return {Promise} promise that will be resolved after the
|
||||||
|
* file was created
|
||||||
|
*
|
||||||
|
* @since 8.2
|
||||||
|
*/
|
||||||
|
createFile: function(name) {
|
||||||
|
var self = this;
|
||||||
|
var deferred = $.Deferred();
|
||||||
|
var promise = deferred.promise();
|
||||||
|
|
||||||
|
OCA.Files.Files.isFileNameValid(name);
|
||||||
|
name = this.getUniqueName(name);
|
||||||
|
|
||||||
|
if (this.lastAction) {
|
||||||
|
this.lastAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
$.post(
|
||||||
|
OC.generateUrl('/apps/files/ajax/newfile.php'),
|
||||||
|
{
|
||||||
|
dir: this.getCurrentDirectory(),
|
||||||
|
filename: name
|
||||||
|
},
|
||||||
|
function(result) {
|
||||||
|
if (result.status === 'success') {
|
||||||
|
self.add(result.data, {animate: true, scrollTo: true});
|
||||||
|
deferred.resolve(result.status, result.data);
|
||||||
|
} else {
|
||||||
|
if (result.data && result.data.message) {
|
||||||
|
OC.Notification.showTemporary(result.data.message);
|
||||||
|
} else {
|
||||||
|
OC.Notification.showTemporary(t('core', 'Could not create file'));
|
||||||
|
}
|
||||||
|
deferred.reject(result.status, result.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a directory inside the current directory.
|
||||||
|
*
|
||||||
|
* @param {string} name name of the directory
|
||||||
|
*
|
||||||
|
* @return {Promise} promise that will be resolved after the
|
||||||
|
* directory was created
|
||||||
|
*
|
||||||
|
* @since 8.2
|
||||||
|
*/
|
||||||
|
createDirectory: function(name) {
|
||||||
|
var self = this;
|
||||||
|
var deferred = $.Deferred();
|
||||||
|
var promise = deferred.promise();
|
||||||
|
|
||||||
|
OCA.Files.Files.isFileNameValid(name);
|
||||||
|
name = this.getUniqueName(name);
|
||||||
|
|
||||||
|
if (this.lastAction) {
|
||||||
|
this.lastAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
$.post(
|
||||||
|
OC.generateUrl('/apps/files/ajax/newfolder.php'),
|
||||||
|
{
|
||||||
|
dir: this.getCurrentDirectory(),
|
||||||
|
foldername: name
|
||||||
|
},
|
||||||
|
function(result) {
|
||||||
|
if (result.status === 'success') {
|
||||||
|
self.add(result.data, {animate: true, scrollTo: true});
|
||||||
|
deferred.resolve(result.status, result.data);
|
||||||
|
} else {
|
||||||
|
if (result.data && result.data.message) {
|
||||||
|
OC.Notification.showTemporary(result.data.message);
|
||||||
|
} else {
|
||||||
|
OC.Notification.showTemporary(t('core', 'Could not create folder'));
|
||||||
|
}
|
||||||
|
deferred.reject(result.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given file name exists in the list
|
||||||
|
*
|
||||||
|
* @param {string} file file name
|
||||||
|
*
|
||||||
|
* @return {bool} true if the file exists in the list, false otherwise
|
||||||
|
*/
|
||||||
inList:function(file) {
|
inList:function(file) {
|
||||||
return this.findFileEl(file).length;
|
return this.findFileEl(file).length;
|
||||||
},
|
},
|
||||||
|
@ -2391,6 +2502,47 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_renderNewButton: function() {
|
||||||
|
// if an upload button (legacy) already exists, skip
|
||||||
|
if ($('#controls .button.upload').length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this._addButtonTemplate) {
|
||||||
|
this._addButtonTemplate = Handlebars.compile(TEMPLATE_ADDBUTTON);
|
||||||
|
}
|
||||||
|
var $newButton = $(this._addButtonTemplate({
|
||||||
|
addText: t('files', 'New'),
|
||||||
|
iconUrl: OC.imagePath('core', 'actions/add')
|
||||||
|
}));
|
||||||
|
|
||||||
|
$('#controls .actions').prepend($newButton);
|
||||||
|
$newButton.tooltip({'placement': 'bottom'});
|
||||||
|
|
||||||
|
$newButton.click(_.bind(this._onClickNewButton, this));
|
||||||
|
this._newButton = $newButton;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onClickNewButton: function(event) {
|
||||||
|
var $target = $(event.target);
|
||||||
|
if (!$target.hasClass('.button')) {
|
||||||
|
$target = $target.closest('.button');
|
||||||
|
}
|
||||||
|
this._newButton.tooltip('hide');
|
||||||
|
event.preventDefault();
|
||||||
|
if ($target.hasClass('disabled')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this._newFileMenu) {
|
||||||
|
this._newFileMenu = new OCA.Files.NewFileMenu({
|
||||||
|
fileList: this
|
||||||
|
});
|
||||||
|
$('body').append(this._newFileMenu.$el);
|
||||||
|
}
|
||||||
|
this._newFileMenu.showAt($target);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a tab view to be added to all views
|
* Register a tab view to be added to all views
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014
|
||||||
|
*
|
||||||
|
* This file is licensed under the Affero General Public License version 3
|
||||||
|
* or later.
|
||||||
|
*
|
||||||
|
* See the COPYING-README file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* global Files */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var TEMPLATE_MENU =
|
||||||
|
'<ul>' +
|
||||||
|
'<li>' +
|
||||||
|
'<label for="file_upload_start" class="menuitem" data-action="upload" title="{{uploadMaxHumanFilesize}}"><span class="svg icon icon-upload"></span><span class="displayname">{{uploadLabel}}</span></label>' +
|
||||||
|
'</li>' +
|
||||||
|
'{{#each items}}' +
|
||||||
|
'<li>' +
|
||||||
|
'<a href="#" class="menuitem" data-templatename="{{templateName}}" data-filetype="{{fileType}}" data-action="{{id}}"><span class="icon {{iconClass}} svg"></span><span class="displayname">{{displayName}}</span></a>' +
|
||||||
|
'</li>' +
|
||||||
|
'{{/each}}' +
|
||||||
|
'</ul>';
|
||||||
|
|
||||||
|
var TEMPLATE_FILENAME_FORM =
|
||||||
|
'<form class="filenameform">' +
|
||||||
|
'<label class="hidden-visually" for="{{cid}}-input-{{fileType}}">{{fileName}}</label>' +
|
||||||
|
'<input id="{{cid}}-input-{{fileType}}" type="text" value="{{fileName}}">' +
|
||||||
|
'</form>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new NewFileMenu instance
|
||||||
|
* @constructs NewFileMenu
|
||||||
|
*
|
||||||
|
* @memberof OCA.Files
|
||||||
|
*/
|
||||||
|
var NewFileMenu = OC.Backbone.View.extend({
|
||||||
|
tagName: 'div',
|
||||||
|
className: 'newFileMenu popovermenu bubble hidden open menu',
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click .menuitem': '_onClickAction'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function(options) {
|
||||||
|
var self = this;
|
||||||
|
var $uploadEl = $('#file_upload_start');
|
||||||
|
if ($uploadEl.length) {
|
||||||
|
$uploadEl.on('fileuploadstart', function() {
|
||||||
|
self.trigger('actionPerformed', 'upload');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn('Missing upload element "file_upload_start"');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._fileList = options && options.fileList;
|
||||||
|
},
|
||||||
|
|
||||||
|
template: function(data) {
|
||||||
|
if (!OCA.Files.NewFileMenu._TEMPLATE) {
|
||||||
|
OCA.Files.NewFileMenu._TEMPLATE = Handlebars.compile(TEMPLATE_MENU);
|
||||||
|
}
|
||||||
|
return OCA.Files.NewFileMenu._TEMPLATE(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler whenever an action has been clicked within the menu
|
||||||
|
*
|
||||||
|
* @param {Object} event event object
|
||||||
|
*/
|
||||||
|
_onClickAction: function(event) {
|
||||||
|
var $target = $(event.target);
|
||||||
|
if (!$target.hasClass('menuitem')) {
|
||||||
|
$target = $target.closest('.menuitem');
|
||||||
|
}
|
||||||
|
var action = $target.attr('data-action');
|
||||||
|
// note: clicking the upload label will automatically
|
||||||
|
// set the focus on the "file_upload_start" hidden field
|
||||||
|
// which itself triggers the upload dialog.
|
||||||
|
// Currently the upload logic is still in file-upload.js and filelist.js
|
||||||
|
if (action === 'upload') {
|
||||||
|
OC.hideMenus();
|
||||||
|
} else {
|
||||||
|
event.preventDefault();
|
||||||
|
this._promptFileName($target);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_promptFileName: function($target) {
|
||||||
|
var self = this;
|
||||||
|
if (!OCA.Files.NewFileMenu._TEMPLATE_FORM) {
|
||||||
|
OCA.Files.NewFileMenu._TEMPLATE_FORM = Handlebars.compile(TEMPLATE_FILENAME_FORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($target.find('form').length) {
|
||||||
|
$target.find('input').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// discard other forms
|
||||||
|
this.$el.find('form').remove();
|
||||||
|
this.$el.find('.displayname').removeClass('hidden');
|
||||||
|
|
||||||
|
$target.find('.displayname').addClass('hidden');
|
||||||
|
|
||||||
|
var newName = $target.attr('data-templatename');
|
||||||
|
var fileType = $target.attr('data-filetype');
|
||||||
|
var $form = $(OCA.Files.NewFileMenu._TEMPLATE_FORM({
|
||||||
|
fileName: newName,
|
||||||
|
cid: this.cid,
|
||||||
|
fileType: fileType
|
||||||
|
}));
|
||||||
|
|
||||||
|
//this.trigger('actionPerformed', action);
|
||||||
|
$target.append($form);
|
||||||
|
|
||||||
|
// here comes the OLD code
|
||||||
|
var $input = $form.find('input');
|
||||||
|
|
||||||
|
var lastPos;
|
||||||
|
var checkInput = function () {
|
||||||
|
var filename = $input.val();
|
||||||
|
try {
|
||||||
|
if (!Files.isFileNameValid(filename)) {
|
||||||
|
// Files.isFileNameValid(filename) throws an exception itself
|
||||||
|
} else if (self._fileList.inList(filename)) {
|
||||||
|
throw t('files', '{newname} already exists', {newname: filename});
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
$input.attr('title', error);
|
||||||
|
$input.tooltip({placement: 'right', trigger: 'manual'});
|
||||||
|
$input.tooltip('show');
|
||||||
|
$input.addClass('error');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// verify filename on typing
|
||||||
|
$input.keyup(function() {
|
||||||
|
if (checkInput()) {
|
||||||
|
$input.tooltip('hide');
|
||||||
|
$input.removeClass('error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.focus();
|
||||||
|
// pre select name up to the extension
|
||||||
|
lastPos = newName.lastIndexOf('.');
|
||||||
|
if (lastPos === -1) {
|
||||||
|
lastPos = newName.length;
|
||||||
|
}
|
||||||
|
$input.selectRange(0, lastPos);
|
||||||
|
|
||||||
|
$form.submit(function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (checkInput()) {
|
||||||
|
var newname = $input.val();
|
||||||
|
self._createFile(fileType, newname);
|
||||||
|
$form.remove();
|
||||||
|
$target.find('.displayname').removeClass('hidden');
|
||||||
|
OC.hideMenus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a file with the given type and name.
|
||||||
|
* This calls the matching methods on the attached file list.
|
||||||
|
*
|
||||||
|
* @param {string} fileType file type
|
||||||
|
* @param {string} name file name
|
||||||
|
*/
|
||||||
|
_createFile: function(fileType, name) {
|
||||||
|
switch(fileType) {
|
||||||
|
case 'file':
|
||||||
|
this._fileList.createFile(name);
|
||||||
|
break;
|
||||||
|
case 'folder':
|
||||||
|
this._fileList.createDirectory(name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn('Unknown file type "' + fileType + '"');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the menu with the currently set items
|
||||||
|
*/
|
||||||
|
render: function() {
|
||||||
|
this.$el.html(this.template({
|
||||||
|
uploadMaxHumanFileSize: 'TODO',
|
||||||
|
uploadLabel: t('files', 'Upload'),
|
||||||
|
items: [{
|
||||||
|
id: 'file',
|
||||||
|
displayName: t('files', 'Text file'),
|
||||||
|
templateName: t('files', 'New text file.txt'),
|
||||||
|
iconClass: 'icon-filetype-text',
|
||||||
|
fileType: 'file'
|
||||||
|
}, {
|
||||||
|
id: 'folder',
|
||||||
|
displayName: t('files', 'Folder'),
|
||||||
|
templateName: t('files', 'New folder'),
|
||||||
|
iconClass: 'icon-folder',
|
||||||
|
fileType: 'folder'
|
||||||
|
}]
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the menu under the given element
|
||||||
|
*
|
||||||
|
* @param {Object} $target target element
|
||||||
|
*/
|
||||||
|
showAt: function($target) {
|
||||||
|
this.render();
|
||||||
|
var targetOffset = $target.offset();
|
||||||
|
this.$el.css({
|
||||||
|
left: targetOffset.left,
|
||||||
|
top: targetOffset.top + $target.height()
|
||||||
|
});
|
||||||
|
this.$el.removeClass('hidden');
|
||||||
|
|
||||||
|
OC.showMenu(null, this.$el);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
OCA.Files.NewFileMenu = NewFileMenu;
|
||||||
|
|
||||||
|
})();
|
|
@ -1,40 +1,16 @@
|
||||||
<div id="controls">
|
<div id="controls">
|
||||||
<div class="actions creatable hidden">
|
<div class="actions creatable hidden">
|
||||||
<?php if(!isset($_['dirToken'])):?>
|
<?php /*
|
||||||
<div id="new" class="button">
|
Only show upload button for public page
|
||||||
<a><?php p($l->t('New'));?></a>
|
*/ ?>
|
||||||
<ul>
|
<?php if(isset($_['dirToken'])):?>
|
||||||
<li class="icon-filetype-text svg"
|
<div id="upload" class="button upload"
|
||||||
data-type="file" data-newname="<?php p($l->t('New text file')) ?>.txt">
|
|
||||||
<p><?php p($l->t('Text file'));?></p>
|
|
||||||
</li>
|
|
||||||
<li class="icon-filetype-folder svg"
|
|
||||||
data-type="folder" data-newname="<?php p($l->t('New folder')) ?>">
|
|
||||||
<p><?php p($l->t('Folder'));?></p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<?php endif;?>
|
|
||||||
<?php /* Note: the template attributes are here only for the public page. These are normally loaded
|
|
||||||
through ajax instead (updateStorageStatistics).
|
|
||||||
*/ ?>
|
|
||||||
<div id="upload" class="button"
|
|
||||||
title="<?php isset($_['uploadMaxHumanFilesize']) ? p($l->t('Upload (max. %s)', array($_['uploadMaxHumanFilesize']))) : '' ?>">
|
title="<?php isset($_['uploadMaxHumanFilesize']) ? p($l->t('Upload (max. %s)', array($_['uploadMaxHumanFilesize']))) : '' ?>">
|
||||||
<input type="hidden" id="max_upload" name="MAX_FILE_SIZE" value="<?php isset($_['uploadMaxFilesize']) ? p($_['uploadMaxFilesize']) : '' ?>">
|
|
||||||
<input type="hidden" id="upload_limit" value="<?php isset($_['uploadLimit']) ? p($_['uploadLimit']) : '' ?>">
|
|
||||||
<input type="hidden" id="free_space" value="<?php isset($_['freeSpace']) ? p($_['freeSpace']) : '' ?>">
|
|
||||||
<?php if(isset($_['dirToken'])):?>
|
|
||||||
<input type="hidden" id="publicUploadRequestToken" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
|
|
||||||
<input type="hidden" id="dirToken" name="dirToken" value="<?php p($_['dirToken']) ?>" />
|
|
||||||
<?php endif;?>
|
|
||||||
<input type="hidden" class="max_human_file_size"
|
|
||||||
value="(max <?php isset($_['uploadMaxHumanFilesize']) ? p($_['uploadMaxHumanFilesize']) : ''; ?>)">
|
|
||||||
<input type="file" id="file_upload_start" name='files[]'
|
|
||||||
data-url="<?php print_unescaped(OCP\Util::linkTo('files', 'ajax/upload.php')); ?>" />
|
|
||||||
<label for="file_upload_start" class="svg icon-upload">
|
<label for="file_upload_start" class="svg icon-upload">
|
||||||
<span class="hidden-visually"><?php p($l->t('Upload'))?></span>
|
<span class="hidden-visually"><?php p($l->t('Upload'))?></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
<div id="uploadprogresswrapper">
|
<div id="uploadprogresswrapper">
|
||||||
<div id="uploadprogressbar"></div>
|
<div id="uploadprogressbar"></div>
|
||||||
<button class="stop icon-close" style="display:none">
|
<button class="stop icon-close" style="display:none">
|
||||||
|
@ -48,7 +24,19 @@
|
||||||
<div class="notCreatable notPublic hidden">
|
<div class="notCreatable notPublic hidden">
|
||||||
<?php p($l->t('You don’t have permission to upload or create files here'))?>
|
<?php p($l->t('You don’t have permission to upload or create files here'))?>
|
||||||
</div>
|
</div>
|
||||||
|
<?php /* Note: the template attributes are here only for the public page. These are normally loaded
|
||||||
|
through ajax instead (updateStorageStatistics).
|
||||||
|
*/ ?>
|
||||||
<input type="hidden" name="permissions" value="" id="permissions">
|
<input type="hidden" name="permissions" value="" id="permissions">
|
||||||
|
<input type="hidden" id="max_upload" name="MAX_FILE_SIZE" value="<?php isset($_['uploadMaxFilesize']) ? p($_['uploadMaxFilesize']) : '' ?>">
|
||||||
|
<input type="hidden" id="upload_limit" value="<?php isset($_['uploadLimit']) ? p($_['uploadLimit']) : '' ?>">
|
||||||
|
<input type="hidden" id="free_space" value="<?php isset($_['freeSpace']) ? p($_['freeSpace']) : '' ?>">
|
||||||
|
<?php if(isset($_['dirToken'])):?>
|
||||||
|
<input type="hidden" id="publicUploadRequestToken" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
|
||||||
|
<input type="hidden" id="dirToken" name="dirToken" value="<?php p($_['dirToken']) ?>" />
|
||||||
|
<?php endif;?>
|
||||||
|
<input type="hidden" class="max_human_file_size"
|
||||||
|
value="(max <?php isset($_['uploadMaxHumanFilesize']) ? p($_['uploadMaxHumanFilesize']) : ''; ?>)">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="emptycontent" class="hidden">
|
<div id="emptycontent" class="hidden">
|
||||||
|
@ -101,6 +89,10 @@
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
<input type="hidden" name="dir" id="dir" value="" />
|
<input type="hidden" name="dir" id="dir" value="" />
|
||||||
|
<div class="hiddenuploadfield">
|
||||||
|
<input type="file" id="file_upload_start" class="hiddenuploadfield" name="files[]"
|
||||||
|
data-url="<?php print_unescaped(OCP\Util::linkTo('files', 'ajax/upload.php')); ?>" />
|
||||||
|
</div>
|
||||||
<div id="editor"></div><!-- FIXME Do not use this div in your app! It is deprecated and will be removed in the future! -->
|
<div id="editor"></div><!-- FIXME Do not use this div in your app! It is deprecated and will be removed in the future! -->
|
||||||
<div id="uploadsize-message" title="<?php p($l->t('Upload too large'))?>">
|
<div id="uploadsize-message" title="<?php p($l->t('Upload too large'))?>">
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* global OC */
|
|
||||||
describe('OC.Upload tests', function() {
|
describe('OC.Upload tests', function() {
|
||||||
var $dummyUploader;
|
var $dummyUploader;
|
||||||
var testFile;
|
var testFile;
|
||||||
|
@ -118,54 +117,4 @@ describe('OC.Upload tests', function() {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('New file', function() {
|
|
||||||
var $input;
|
|
||||||
var currentDirStub;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
OC.Upload.init();
|
|
||||||
$('#new>a').click();
|
|
||||||
$('#new li[data-type=file]').click();
|
|
||||||
$input = $('#new input[type=text]');
|
|
||||||
|
|
||||||
currentDirStub = sinon.stub(FileList, 'getCurrentDirectory');
|
|
||||||
currentDirStub.returns('testdir');
|
|
||||||
});
|
|
||||||
afterEach(function() {
|
|
||||||
currentDirStub.restore();
|
|
||||||
});
|
|
||||||
it('sets default text in field', function() {
|
|
||||||
expect($input.length).toEqual(1);
|
|
||||||
expect($input.val()).toEqual('New text file.txt');
|
|
||||||
});
|
|
||||||
it('creates file when enter is pressed', function() {
|
|
||||||
$input.val('somefile.txt');
|
|
||||||
$input.trigger(new $.Event('keyup', {keyCode: 13}));
|
|
||||||
$input.parent('form').submit();
|
|
||||||
expect(fakeServer.requests.length).toEqual(2);
|
|
||||||
|
|
||||||
var request = fakeServer.requests[1];
|
|
||||||
expect(request.method).toEqual('POST');
|
|
||||||
expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/newfile.php');
|
|
||||||
var query = OC.parseQueryString(request.requestBody);
|
|
||||||
expect(query).toEqual({
|
|
||||||
dir: 'testdir',
|
|
||||||
filename: 'somefile.txt'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('prevents entering invalid file names', function() {
|
|
||||||
$input.val('..');
|
|
||||||
$input.trigger(new $.Event('keyup', {keyCode: 13}));
|
|
||||||
$input.parent('form').submit();
|
|
||||||
expect(fakeServer.requests.length).toEqual(1);
|
|
||||||
});
|
|
||||||
it('prevents entering file names that already exist', function() {
|
|
||||||
var inListStub = sinon.stub(FileList, 'inList').returns(true);
|
|
||||||
$input.val('existing.txt');
|
|
||||||
$input.trigger(new $.Event('keyup', {keyCode: 13}));
|
|
||||||
$input.parent('form').submit();
|
|
||||||
expect(fakeServer.requests.length).toEqual(1);
|
|
||||||
inListStub.restore();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -2157,6 +2157,93 @@ describe('OCA.Files.FileList tests', function() {
|
||||||
expect(fileList.$fileList.find('tr').length).toEqual(5);
|
expect(fileList.$fileList.find('tr').length).toEqual(5);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('create file', function() {
|
||||||
|
var deferredCreate;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
deferredCreate = $.Deferred();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates file with given name and adds it to the list', function() {
|
||||||
|
var deferred = fileList.createFile('test file.txt');
|
||||||
|
var successStub = sinon.stub();
|
||||||
|
var failureStub = sinon.stub();
|
||||||
|
|
||||||
|
deferred.done(successStub);
|
||||||
|
deferred.fail(failureStub);
|
||||||
|
|
||||||
|
expect(fakeServer.requests.length).toEqual(1);
|
||||||
|
expect(fakeServer.requests[0].url).toEqual(OC.generateUrl('/apps/files/ajax/newfile.php'));
|
||||||
|
|
||||||
|
var query = fakeServer.requests[0].requestBody;
|
||||||
|
expect(OC.parseQueryString(query)).toEqual({
|
||||||
|
dir: '/subdir',
|
||||||
|
filename: 'test file.txt'
|
||||||
|
});
|
||||||
|
|
||||||
|
fakeServer.requests[0].respond(
|
||||||
|
200,
|
||||||
|
{ 'Content-Type': 'application/json' },
|
||||||
|
JSON.stringify({
|
||||||
|
status: 'success',
|
||||||
|
data: {
|
||||||
|
path: '/subdir',
|
||||||
|
name: 'test file.txt',
|
||||||
|
mimetype: 'text/plain'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
var $tr = fileList.findFileEl('test file.txt');
|
||||||
|
expect($tr.length).toEqual(1);
|
||||||
|
expect($tr.attr('data-mime')).toEqual('text/plain');
|
||||||
|
|
||||||
|
expect(successStub.calledOnce).toEqual(true);
|
||||||
|
expect(failureStub.notCalled).toEqual(true);
|
||||||
|
});
|
||||||
|
// TODO: error cases
|
||||||
|
// TODO: unique name cases
|
||||||
|
});
|
||||||
|
describe('create directory', function() {
|
||||||
|
it('creates directory with given name and adds it to the list', function() {
|
||||||
|
var deferred = fileList.createDirectory('test directory');
|
||||||
|
var successStub = sinon.stub();
|
||||||
|
var failureStub = sinon.stub();
|
||||||
|
|
||||||
|
deferred.done(successStub);
|
||||||
|
deferred.fail(failureStub);
|
||||||
|
|
||||||
|
expect(fakeServer.requests.length).toEqual(1);
|
||||||
|
expect(fakeServer.requests[0].url).toEqual(OC.generateUrl('/apps/files/ajax/newfolder.php'));
|
||||||
|
var query = fakeServer.requests[0].requestBody;
|
||||||
|
expect(OC.parseQueryString(query)).toEqual({
|
||||||
|
dir: '/subdir',
|
||||||
|
foldername: 'test directory'
|
||||||
|
});
|
||||||
|
|
||||||
|
fakeServer.requests[0].respond(
|
||||||
|
200,
|
||||||
|
{ 'Content-Type': 'application/json' },
|
||||||
|
JSON.stringify({
|
||||||
|
status: 'success',
|
||||||
|
data: {
|
||||||
|
path: '/subdir',
|
||||||
|
name: 'test directory',
|
||||||
|
mimetype: 'httpd/unix-directory'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
var $tr = fileList.findFileEl('test directory');
|
||||||
|
expect($tr.length).toEqual(1);
|
||||||
|
expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
|
||||||
|
|
||||||
|
expect(successStub.calledOnce).toEqual(true);
|
||||||
|
expect(failureStub.notCalled).toEqual(true);
|
||||||
|
});
|
||||||
|
// TODO: error cases
|
||||||
|
// TODO: unique name cases
|
||||||
|
});
|
||||||
/**
|
/**
|
||||||
* Test upload mostly by testing the code inside the event handlers
|
* Test upload mostly by testing the code inside the event handlers
|
||||||
* that were registered on the magic upload object
|
* that were registered on the magic upload object
|
||||||
|
@ -2359,4 +2446,36 @@ describe('OCA.Files.FileList tests', function() {
|
||||||
expect(fileInfo.type).toEqual('file');
|
expect(fileInfo.type).toEqual('file');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('new file menu', function() {
|
||||||
|
var newFileMenuStub;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
newFileMenuStub = sinon.stub(OCA.Files.NewFileMenu.prototype, 'showAt');
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
newFileMenuStub.restore();
|
||||||
|
})
|
||||||
|
it('renders new button when no legacy upload button exists', function() {
|
||||||
|
expect(fileList.$el.find('.button.upload').length).toEqual(0);
|
||||||
|
expect(fileList.$el.find('.button.new').length).toEqual(1);
|
||||||
|
});
|
||||||
|
it('does not render new button when no legacy upload button exists (public page)', function() {
|
||||||
|
fileList.destroy();
|
||||||
|
$('#controls').append('<input type="button" class="button upload" />');
|
||||||
|
fileList = new OCA.Files.FileList($('#app-content-files'));
|
||||||
|
expect(fileList.$el.find('.button.upload').length).toEqual(1);
|
||||||
|
expect(fileList.$el.find('.button.new').length).toEqual(0);
|
||||||
|
});
|
||||||
|
it('opens the new file menu when clicking on the "New" button', function() {
|
||||||
|
var $button = fileList.$el.find('.button.new');
|
||||||
|
$button.click();
|
||||||
|
expect(newFileMenuStub.calledOnce).toEqual(true);
|
||||||
|
});
|
||||||
|
it('does not open the new file menu when button is disabled', function() {
|
||||||
|
var $button = fileList.$el.find('.button.new');
|
||||||
|
$button.addClass('disabled');
|
||||||
|
$button.click();
|
||||||
|
expect(newFileMenuStub.notCalled).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/**
|
||||||
|
* ownCloud
|
||||||
|
*
|
||||||
|
* @author Vincent Petry
|
||||||
|
* @copyright 2015 Vincent Petry <pvince81@owncloud.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
describe('OCA.Files.NewFileMenu', function() {
|
||||||
|
var FileList = OCA.Files.FileList;
|
||||||
|
var menu, fileList, $uploadField, $trigger;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
// dummy upload button
|
||||||
|
var $container = $('<div id="app-content-files"></div>');
|
||||||
|
$uploadField = $('<input id="file_upload_start"></input>');
|
||||||
|
$trigger = $('<a href="#">Menu</a>');
|
||||||
|
$container.append($uploadField).append($trigger);
|
||||||
|
$('#testArea').append($container);
|
||||||
|
|
||||||
|
fileList = new FileList($container);
|
||||||
|
menu = new OCA.Files.NewFileMenu({
|
||||||
|
fileList: fileList
|
||||||
|
});
|
||||||
|
menu.showAt($trigger);
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
OC.hideMenus();
|
||||||
|
fileList = null;
|
||||||
|
menu = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('rendering', function() {
|
||||||
|
it('renders menu items', function() {
|
||||||
|
var $items = menu.$el.find('.menuitem');
|
||||||
|
expect($items.length).toEqual(3);
|
||||||
|
// label points to the file_upload_start item
|
||||||
|
var $item = $items.eq(0);
|
||||||
|
expect($item.is('label')).toEqual(true);
|
||||||
|
expect($item.attr('for')).toEqual('file_upload_start');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('New file/folder', function() {
|
||||||
|
var $input;
|
||||||
|
var createFileStub;
|
||||||
|
var createDirectoryStub;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
createFileStub = sinon.stub(FileList.prototype, 'createFile');
|
||||||
|
createDirectoryStub = sinon.stub(FileList.prototype, 'createDirectory');
|
||||||
|
menu.$el.find('.menuitem').eq(1).click();
|
||||||
|
$input = menu.$el.find('form.filenameform input');
|
||||||
|
});
|
||||||
|
afterEach(function() {
|
||||||
|
createFileStub.restore();
|
||||||
|
createDirectoryStub.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets default text in field', function() {
|
||||||
|
expect($input.length).toEqual(1);
|
||||||
|
expect($input.val()).toEqual('New text file.txt');
|
||||||
|
});
|
||||||
|
it('creates file when enter is pressed', function() {
|
||||||
|
$input.val('somefile.txt');
|
||||||
|
$input.trigger(new $.Event('keyup', {keyCode: 13}));
|
||||||
|
$input.parent('form').submit();
|
||||||
|
|
||||||
|
expect(createFileStub.calledOnce).toEqual(true);
|
||||||
|
expect(createFileStub.getCall(0).args[0]).toEqual('somefile.txt');
|
||||||
|
expect(createDirectoryStub.notCalled).toEqual(true);
|
||||||
|
});
|
||||||
|
it('prevents entering invalid file names', function() {
|
||||||
|
$input.val('..');
|
||||||
|
$input.trigger(new $.Event('keyup', {keyCode: 13}));
|
||||||
|
$input.closest('form').submit();
|
||||||
|
|
||||||
|
expect(createFileStub.notCalled).toEqual(true);
|
||||||
|
expect(createDirectoryStub.notCalled).toEqual(true);
|
||||||
|
});
|
||||||
|
it('prevents entering file names that already exist', function() {
|
||||||
|
var inListStub = sinon.stub(fileList, 'inList').returns(true);
|
||||||
|
$input.val('existing.txt');
|
||||||
|
$input.trigger(new $.Event('keyup', {keyCode: 13}));
|
||||||
|
$input.closest('form').submit();
|
||||||
|
|
||||||
|
expect(createFileStub.notCalled).toEqual(true);
|
||||||
|
expect(createDirectoryStub.notCalled).toEqual(true);
|
||||||
|
inListStub.restore();
|
||||||
|
});
|
||||||
|
it('switching fields removes the previous form', function() {
|
||||||
|
menu.$el.find('.menuitem').eq(2).click();
|
||||||
|
expect(menu.$el.find('form').length).toEqual(1);
|
||||||
|
});
|
||||||
|
it('creates directory when clicking on create directory field', function() {
|
||||||
|
menu.$el.find('.menuitem').eq(2).click();
|
||||||
|
$input = menu.$el.find('form.filenameform input');
|
||||||
|
$input.val('some folder');
|
||||||
|
$input.trigger(new $.Event('keyup', {keyCode: 13}));
|
||||||
|
$input.closest('form').submit();
|
||||||
|
|
||||||
|
expect(createDirectoryStub.calledOnce).toEqual(true);
|
||||||
|
expect(createDirectoryStub.getCall(0).args[0]).toEqual('some folder');
|
||||||
|
expect(createFileStub.notCalled).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -17,6 +17,7 @@ OCP\Util::addStyle('files', 'upload');
|
||||||
OCP\Util::addScript('files', 'filesummary');
|
OCP\Util::addScript('files', 'filesummary');
|
||||||
OCP\Util::addScript('files', 'breadcrumb');
|
OCP\Util::addScript('files', 'breadcrumb');
|
||||||
OCP\Util::addScript('files', 'fileinfomodel');
|
OCP\Util::addScript('files', 'fileinfomodel');
|
||||||
|
OCP\Util::addScript('files', 'newfilemenu');
|
||||||
OCP\Util::addScript('files', 'files');
|
OCP\Util::addScript('files', 'files');
|
||||||
OCP\Util::addScript('files', 'filelist');
|
OCP\Util::addScript('files', 'filelist');
|
||||||
OCP\Util::addscript('files', 'keyboardshortcuts');
|
OCP\Util::addscript('files', 'keyboardshortcuts');
|
||||||
|
|
|
@ -629,3 +629,68 @@ em {
|
||||||
.tabsContainer .tab {
|
.tabsContainer .tab {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* popover menu styles (use together with "bubble" class) */
|
||||||
|
.popovermenu .menuitem,
|
||||||
|
.popovermenu .menuitem>span {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovermenu .menuitem {
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
|
||||||
|
filter: alpha(opacity=50);
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovermenu .menuitem:hover,
|
||||||
|
.popovermenu .menuitem:focus {
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
|
||||||
|
filter: alpha(opacity=100);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovermenu {
|
||||||
|
padding: 4px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovermenu li {
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovermenu .menuitem img {
|
||||||
|
padding: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovermenu a.menuitem,
|
||||||
|
.popovermenu label.menuitem,
|
||||||
|
.popovermenu .menuitem {
|
||||||
|
padding: 10px;
|
||||||
|
margin: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovermenu.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovermenu .menuitem {
|
||||||
|
display: block;
|
||||||
|
line-height: 30px;
|
||||||
|
padding-left: 5px;
|
||||||
|
color: #000;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovermenu .menuitem .icon,
|
||||||
|
.popovermenu .menuitem .no-icon {
|
||||||
|
display: inline-block;
|
||||||
|
width: 16px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovermenu .menuitem {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popovermenu li:hover .menuitem {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
|
@ -955,6 +955,7 @@ a.bookmarklet { background-color:#ddd; border:1px solid #ccc; padding:5px;paddin
|
||||||
|
|
||||||
.ui-icon-circle-triangle-e{ background-image:url('../img/actions/play-next.svg'); }
|
.ui-icon-circle-triangle-e{ background-image:url('../img/actions/play-next.svg'); }
|
||||||
.ui-icon-circle-triangle-w{ background-image:url('../img/actions/play-previous.svg'); }
|
.ui-icon-circle-triangle-w{ background-image:url('../img/actions/play-previous.svg'); }
|
||||||
|
|
||||||
.ui-datepicker-prev,.ui-datepicker-next{ border:1px solid #ddd; background:#fff; }
|
.ui-datepicker-prev,.ui-datepicker-next{ border:1px solid #ddd; background:#fff; }
|
||||||
|
|
||||||
/* ---- DIALOGS ---- */
|
/* ---- DIALOGS ---- */
|
||||||
|
@ -1142,3 +1143,12 @@ fieldset.warning legend + p, fieldset.update legend + p {
|
||||||
@-ms-viewport {
|
@-ms-viewport {
|
||||||
width: device-width;
|
width: device-width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* hidden input type=file field */
|
||||||
|
.hiddenuploadfield {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue