Initial commit

This commit is contained in:
ECAILLE Fabrice (externe)
2017-05-03 16:46:01 +02:00
commit 2e64cb961e
117 changed files with 10765 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" data-bind="click: close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">New item</h4>
</div>
<div class="modal-body">
<form data-bind="submit: ok" class="form-horizontal">
<div class="row form-group">
<label class="col-sm-2">Type</label>
<div class="col-sm-10">
<label class="radio-inline">
<input type="radio" name="typeItem" id="typeItemFile" value="file" data-bind="checked: typeItem"> File
</label>
<label class="radio-inline">
<input type="radio" name="typeItem" id="typeItemFolder" value="folder" data-bind="checked: typeItem"> Folder
</label>
</div>
</div>
<div class="row form-group">
<label for="nameInput" class="col-sm-2 control-label">Name</label>
<div class="col-sm-10">
<input data-bind="value: input, valueUpdate: 'afterkeydown'" name="nameInput" class="form-control autofocus"/>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-primary" data-bind="click: ok, visible: isValid">Create</button>
<button class="btn btn-default" data-bind="click: close">Cancel</button>
</div>
</div>

View File

@@ -0,0 +1,34 @@
define(['plugins/dialog', 'knockout', 'knockout.validation'], function (dialog, ko, ko_validation) {
ko.validation = ko_validation;
var NewItemModal = function() {
var self = this;
self.input = ko.observable('').extend({
required: true,
pattern: {
message : 'The name must not contain a \'/\'',
params : '^[^/]+$'
}
});
self.typeItem = ko.observable('file');
self.form = ko.validatedObservable( {input: self.input} );
self.isValid = ko.computed(function() {
return self.form.isValid();
});
};
NewItemModal.prototype.ok = function() {
dialog.close(this, { name: this.input(), type: this.typeItem()});
};
NewItemModal.prototype.close = function() {
dialog.close(this);
};
NewItemModal.show = function(defaultValue){
return dialog.show(new NewItemModal(defaultValue));
};
return NewItemModal;
});

View File

@@ -0,0 +1,18 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" data-bind="click: close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Rename</h4>
</div>
<div class="modal-body">
<form data-bind="submit: ok" class="form-inline">
<div class="form-group">
<label for="renameInput">New name</label>
<input data-bind="value: input, valueUpdate: 'afterkeydown'" name="renameInput" class="form-control autofocus"/>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-primary" data-bind="click: ok, visible: isValid">Ok</button>
<button class="btn btn-default" data-bind="click: close">Cancel</button>
</div>
</div>

View File

@@ -0,0 +1,34 @@
define(['plugins/dialog', 'knockout', , 'knockout.validation'], function (dialog, ko, ko_validation) {
ko.validation = ko_validation;
var RenameModal = function(defaultValue) {
var self = this;
self.previousName = defaultValue;
self.input = ko.observable(defaultValue).extend({
required: true,
pattern: {
message : 'The name must not contain a \'/\'',
params : '^[^/]+$'
}
});
self.form = ko.validatedObservable( {input: self.input} );
self.isValid = ko.computed(function() {
return self.form.isValid() && self.input() != self.previousName;
});
};
RenameModal.prototype.ok = function() {
dialog.close(this, this.input());
};
RenameModal.prototype.close = function() {
dialog.close(this);
};
RenameModal.show = function(defaultValue){
return dialog.show(new RenameModal(defaultValue));
};
return RenameModal;
});

View File

@@ -0,0 +1,56 @@
<div id="filebrowser">
<!-- ko if: folder() -->
<!-- ko let: { loopRoot: $data } -->
<ul data-bind="template: { name: 'tree-template', foreach: folder().children() }" class="tree-file"></ul>
<!-- /ko -->
<!-- /ko -->
<script id="tree-template" type="text/html">
<!-- ko if: $data.type() === "folder" -->
<li class="folder">
<span data-bind="event: { contextmenu: loopRoot.openContextMenu, dblclick: loopRoot.open, click: loopRoot.select }">
<i class="fa fa-folder-o" data-bind="attr: {id: 'icon_folder_' + $data.uuid()}"></i>
<!-- ko text: $data.name --><!-- /ko -->
</span>
<input type="checkbox" data-bind="attr: {id: $data.uuid}" />
<ul data-bind="template: { name: 'tree-template', foreach: $data.children }"></ul>
</li>
<!-- /ko -->
<!--ko if: $data.type() !== "folder"-->
<li data-bind="attr: {'data-id': $data.uuid, 'data-filetype': $data.type()},
event: { contextmenu: loopRoot.openContextMenu, dblclick: loopRoot.open, click: loopRoot.select }"
class="file">
<!--ko ifnot: $data.type -->
<i data-bind="attr: {class: 'fa fa-file-o'}"></i>
<!-- /ko -->
<!--ko if: $data.type -->
<i data-bind="attr: {class: 'fa fa-file-' + $data.type() + '-o', title: $data.type()}"></i>
<!-- /ko -->
<span data-bind="text: $data.name, attr: {'data-extra': $data.extra ? $data.extra : ''}"></span>
</li>
<!-- /ko -->
</script>
<!-- Context menu -->
<div id="fileBrowserContextMenu" class="dropdown open" data-bind="visible: showContextMenu" tabindex="1">
<ul class="dropdown-menu" role="menu" aria-labelledby="contextMenu">
<li data-bind="visible: hasSelectedFolder()" >
<a role="menuitem" tabindex="-1" href="#" data-bind="click: newItem">New ...</a>
</li>
<li>
<a role="menuitem" tabindex="-1" href="#" data-bind="click: openRenamePopup">Rename</a>
</li>
<li>
<a role="menuitem" tabindex="-1" href="#" data-bind="click: copy">Copy</a>
</li>
<li data-bind="css: { 'disabled': !hasCopied()}, visible: hasSelectedFolder()">
<a role="menuitem" tabindex="-1" href="#" data-bind="click: paste">Paste</a>
</li>
<li>
<a role="menuitem" tabindex="-1" href="#" data-bind="click: openDeletePopup">Delete</a>
</li>
</ul>
</div>
<!-- End of Context menu -->
</div>

View File

@@ -0,0 +1,147 @@
define(['durandal/app', 'durandal/composition', 'plugins/http',
'jquery', 'knockout', 'knockout.mapping',
'perfect.scrollbar',
'./renameModal', './newItemModal'],
function(app, composition,http, $, ko, ko_mapping, perfectScrollbar, RenameModal, NewItemModal) {
ko.mapping = ko_mapping;
ko.bindingHandlers['let'] = {
'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
// Make a modified binding context, with extra properties, and apply it to descendant elements
var innerContext = bindingContext.extend(valueAccessor());
ko.applyBindingsToDescendants(innerContext, element);
return { controlsDescendantBindings: true };
}
};
ko.virtualElements.allowedBindings['let'] = true;
var ctor = function() {},
selected = ko.observable(),
showContextMenu = ko.observable(),
copied = ko.observable(undefined),
folder = ko.observable(ko.mapping.fromJS({children: []})),
scrollable = $('#filebrowser');
ctor.prototype.attached = function() {
showContextMenu(false);
$('#filebrowser').perfectScrollbar();
};
ctor.prototype.activate = function(settings) {
this.settings = settings;
this.selected = selected;
this.folder = folder;
this.showContextMenu = showContextMenu;
this.hasSelectedFolder = ko.computed(function() {
return selected() != undefined && selected().type === 'folder';
});
this.hasCopied = ko.computed( function() {
return copied() !== undefined;
});
};
ctor.prototype.open = function(object,event) {
console.log('Opening', object);
if( object.type() === 'folder' ) {
var id = object.uuid(),
checkbox = $('input[type=checkbox][id=' + id + ']');
checkbox.prop('checked', !checkbox.prop('checked'));
$('#icon_folder_' + id).toggleClass('fa-folder-o').toggleClass('fa-folder-open-o');
$('#filebrowser').perfectScrollbar('update');
} else {
var type = object.extra();
http.get(object.path()).then(function(response) {
app.trigger('filebrowser:open_file', {
type: type,
content: response
});
});
}
};
ctor.prototype.select = function(object, event) {
$('li > span.select').removeClass('select');
$(event.target).toggleClass('select');
selected( ko.mapping.fromJS(object) );
};
/** Context Menu **/
ctor.prototype.openContextMenu = function(object, event) {
// Position du menu, calculer la pos pour eviter sortie du viewport
var posX = event.pageX,
posY = event.pageY,
windowWidth = $(window).width(),
windowHeight = $(window).height(),
contextMenu = $('#fileBrowserContextMenu'),
menuWidth = contextMenu.width(),
menuHeight = contextMenu.height();
posX = Math.min(posX, windowWidth - menuWidth - 15);
posY = Math.min(posY, windowHeight - menuHeight - 10);
// affichage
contextMenu.css({
left : posX + 'px',
top : posY + 'px'
});
showContextMenu(true);
};
ctor.prototype.openRenamePopup = function(ctor, event) {
RenameModal.show(ctor.selected().name()).then(function(response) {
if( response !== undefined ) {
ctor.selected().name(response);
}
});
};
ctor.prototype.openDeletePopup = function(ctor, event) {
app.showMessage(
'Are you sure you want to delete this ' +
(ctor.selected().is_folder ? ' folder and all its content' : 'file') + '?',
'Delete ' + ctor.selected().name(), [ { text: "Yes", value: "yes" }, { text: "No", value: "no" }]).then( function( dialogResult ) {
if( dialogResult === 'yes' ) {
console.log('Deleting', ctor.selected().name());
}
});
};
ctor.prototype.copy = function(ctor, event) {
console.log('Copied', ctor.selected().name());
copied( ctor.selected() );
};
ctor.prototype.paste = function(ctor, event) {
if( copied() !== undefined ) {
console.log('Paste', copied().name(), 'into', ctor.selected().name());
copied( undefined );
}
};
ctor.prototype.newItem = function(ctor, event) {
NewItemModal.show().then(function(response) {
if( response !== undefined ) {
console.log('New item : ' + response.type + ' - ' + response.name );
}
});
};
$(document).on('click', function() {
showContextMenu(false);
});
/** End of Context Menu */
http.get('/data/filesystem.json').then(function(response) {
folder(ko.mapping.fromJS(response));
$('#filebrowser').perfectScrollbar('update');
});
return ctor;
});