Commit 05fd2e34 authored by Benjamin Fischer's avatar Benjamin Fischer
Browse files

Merge

parents 1e44561c 1c13e818
...@@ -32,7 +32,7 @@ class BusController(AbstractController): ...@@ -32,7 +32,7 @@ class BusController(AbstractController):
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.ajax() @cherrypy.tools.ajax()
def poll(self, timeout=10): def poll(self, timeoutms=10000):
sid = cherrypy.session.id sid = cherrypy.session.id
uid = cherrypy.request.user.id uid = cherrypy.request.user.id
publisher = self.get_polling_publisher(sid, uid) publisher = self.get_polling_publisher(sid, uid)
...@@ -40,7 +40,7 @@ class BusController(AbstractController): ...@@ -40,7 +40,7 @@ class BusController(AbstractController):
return [] return []
POLLING_TIMESTAMPS[sid] = int(time()) POLLING_TIMESTAMPS[sid] = int(time())
self.release() self.release()
return publisher.fetch(int(timeout)) return publisher.fetch(int(timeoutms)*0.001)
@cherrypy.expose @cherrypy.expose
def send(self, *args, **kwargs): def send(self, *args, **kwargs):
......
...@@ -25,7 +25,8 @@ class FSController(AbstractController): ...@@ -25,7 +25,8 @@ class FSController(AbstractController):
download = True download = True
wid = cherrypy.request.private_params.get('_workspaceId', None) wid = cherrypy.request.private_params.get('_workspaceId', None)
data, contenttype, _ = self.handleDownload(path, wid) data, contenttype, _ = self.handleDownload(path, wid)
cherrypy.response.headers['Content-Type'] = contenttype if contenttype != None:
cherrypy.response.headers['Content-Type'] = contenttype
if download: # or not isbrowserfile: if download: # or not isbrowserfile:
disposition = 'attachment; filename=%s' % path.split('/')[-1] disposition = 'attachment; filename=%s' % path.split('/')[-1]
cherrypy.response.headers['Content-Disposition'] = disposition cherrypy.response.headers['Content-Disposition'] = disposition
...@@ -36,11 +37,11 @@ class FSController(AbstractController): ...@@ -36,11 +37,11 @@ class FSController(AbstractController):
# get the content type depending on the file extension # get the content type depending on the file extension
ext = path.split('.')[-1] ext = path.split('.')[-1]
mimetype = fs.get_mime_type(path) mimetype = fs.get_mime_type(path)
if mimetype is None: # if mimetype is None:
raise Exception('The file extension \'%s\ is not supported by this server' % ext) # raise Exception('The file extension \'%s\ is not supported by this server' % ext)
if not fs.exists(path, 'f'): if not fs.exists(path, 'f'):
raise Exception('The file \'%s\' does not exist' % path) raise MessageException('The file \'%s\' does not exist' % path)
# Set the Last-Modified response header, so that # Set the Last-Modified response header, so that
# modified-since validation code can work. # modified-since validation code can work.
...@@ -83,6 +84,19 @@ class FSAjaxController(AbstractController): ...@@ -83,6 +84,19 @@ class FSAjaxController(AbstractController):
else: else:
return "Failed" return "Failed"
@cherrypy.expose
@cherrypy.tools.ajax()
def filecount(self, path):
self.release_session()
fs = self.get('fs')
self.release_database()
count = fs.get_file_count(path)
if count < 0:
raise MessageException("%s does not exist" % path)
else:
return {"count": count}
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.ajax(encoded=True) @cherrypy.tools.ajax(encoded=True)
def filelist(self, path, deep=False, filefilter=None, reverse=False): def filelist(self, path, deep=False, filefilter=None, reverse=False):
......
...@@ -22,6 +22,6 @@ class CodeEditorExtension(AbstractExtension): ...@@ -22,6 +22,6 @@ class CodeEditorExtension(AbstractExtension):
self.add_js("js/preview.js") self.add_js("js/preview.js")
self.add_js("js/prefs.js") self.add_js("js/prefs.js")
self.add_css("css/styles.less") self.add_css("css/styles.css")
self.add_workspace_directoy() self.add_workspace_directoy()
.codeeditor {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
margin: 0px;
padding: 0px;
}
.codeeditor #execute {
min-width: 100px;
}
.codeeditor #abort {
margin-right: -1px;
min-width: 100px;
}
.codeeditor #command-line {
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
}
.codeeditor-left {
position: absolute;
top: 0px;
right: none;
bottom: 0px;
left: 0px;
width: 100%;
overflow: auto;
border: 1px solid #b8b8b8;
border-width: 0px 1px 0px 0px;
}
.codeeditor-right {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: none;
width: 0%;
overflow: auto;
padding-left: 1px;
}
.codeeditor-right-top {
position: absolute;
top: 0px;
right: 0px;
bottom: none;
left: 0px;
height: 100%;
overflow: hidden;
box-shadow: 0px 1px 0px #b8b8b8;
}
.codeeditor-right-bottom {
position: absolute;
top: none;
right: 0px;
bottom: 0px;
left: 0px;
height: 0%;
overflow: auto;
padding: 11px 10px 10px 10px;
}
.codeeditor-commandline > * {
border-radius: 0px;
}
.codeeditor-commandline > .input-group-addon {
border-left: 0px;
}
.codeeditor-commandline button {
border-radius: 0px;
}
.codeeditor-ace {
position: absolute !important;
top: 0px !important;
right: 0px !important;
bottom: 0px !important;
left: 0px !important;
}
.codeeditor-output {
position: absolute !important;
top: 35px !important;
right: 0px !important;
bottom: 0px !important;
left: 0px !important;
border-radius: 0px;
margin: 0px 0px 0px 1px;
border: 0px;
}
.codeeditor-output-buttons {
position: absolute;
top: 45px;
right: 10px;
}
.codeeditor-right-top pre {
overflow: auto;
}
.codeeditor-right-bottom .well {
position: absolute;
top: 55px;
right: 10px;
bottom: 10px;
left: 10px;
padding: 10px;
margin: 0px;
white-space: nowrap;
overflow-x: auto;
overflow-y: auto;
}
.codeeditor-right-bottom .codeeditor-preview {
position: relative;
display: inline-block;
margin: 0px 10px 10px 0px;
padding: 6px;
border-radius: 3px;
border: 1px solid #b8b8b8;
background-color: white;
float: left;
overflow: hidden;
}
.codeeditor-right-bottom .codeeditor-preview:hover {
border-color: #428bca;
}
.codeeditor-right-bottom .codeeditor-preview-label {
position: absolute;
top: 0px;
right: 0px;
left: 0px;
height: 24px;
text-align: center;
}
.codeeditor-right-bottom .codeeditor-preview-img {
position: absolute;
top: 24px;
right: 0px;
bottom: 0px;
left: 0px;
text-align: center;
}
.codeeditor-right-bottom .codeeditor-preview img {
padding-top: 24px;
height: 100px;
width: auto;
}
.codeeditor-ace div.ace_scrollbar {
overflow-x: auto !important;
overflow-y: auto !important;
}
...@@ -31,7 +31,6 @@ class DemoExtension(AbstractExtension): ...@@ -31,7 +31,6 @@ class DemoExtension(AbstractExtension):
# the paths are relative to vispa/extensions/<name>/static # the paths are relative to vispa/extensions/<name>/static
self.add_js("js/extension.js") self.add_js("js/extension.js")
self.add_css("css/style.css") self.add_css("css/style.css")
self.add_css("css/style.less")
# tell vispa to transfer files located in the workspace folder # tell vispa to transfer files located in the workspace folder
# (vispa/extensions/<name>/workspace) to selected workspaces # (vispa/extensions/<name>/workspace) to selected workspaces
......
/* /*
* This is a basic css file. In order to avoid naming collisions, you should * This is a less-css file. It allows class mixinx, variables, anc basic
* use prefixes in your class names. * computation tasks (addition, multiplication, etc). You can find more
* information on less-css at http://lesscss.org/. In order to avoid naming
* collisions, you should use prefixes in your class names.
*/ */
.demo-content { .demo-content {
background-color: rgba(61, 129, 187, 1.0); background-color: #3d81bb;
}
.demo-content-text {
color: #ffffff;
padding: 5px 10px;
} }
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
// define a variable for the text color // define a variable for the text color
@content-color: #ffffff; @content-color: #ffffff;
.demo-content {
background-color: rgba(61, 129, 187, 1.0);
}
// define a mixin class with default values // define a mixin class with default values
.demo-text-padding (@vertical: 5px, @horizontal: 10px) { .demo-text-padding (@vertical: 5px, @horizontal: 10px) {
padding: @vertical @horizontal; padding: @vertical @horizontal;
......
...@@ -44,6 +44,7 @@ class FileBrowserExtension(AbstractExtension): ...@@ -44,6 +44,7 @@ class FileBrowserExtension(AbstractExtension):
self.add_js('js/selector/selector.js') self.add_js('js/selector/selector.js')
self.add_js('js/selector/actions.js') self.add_js('js/selector/actions.js')
self.add_js('js/selector/items.js')
self.add_js('js/selector/selections.js') self.add_js('js/selector/selections.js')
self.add_js('js/selector/selectortableview.js') self.add_js('js/selector/selectortableview.js')
......
...@@ -71,7 +71,12 @@ var FileBaseActions = Class.extend({ ...@@ -71,7 +71,12 @@ var FileBaseActions = Class.extend({
function(result) { function(result) {
if (result === true) { if (result === true) {
self._openWithCodeEditor(path); self._openWithCodeEditor(path);
} } else self.FileBase.instance.confirm("Do you want to download \"" + name + " (" +
size + ")\"?", function(res2) {
if(res2 === true) {
self.download();
}
});
}); });
} }
// }) // })
......
...@@ -49,34 +49,47 @@ var FileBase = Class.extend({ ...@@ -49,34 +49,47 @@ var FileBase = Class.extend({
updateView: function() { updateView: function() {
var self = this; var self = this;
this.instance.setLoading(true);
this.selections.unselectAll();
// remove the links needed for the preview lightbox // remove the links needed for the preview lightbox
$("a[data-lightbox=" + this.view.previewBoxID + "]").remove(); $("a[data-lightbox=" + this.view.previewBoxID + "]").remove();
if (self.workflow.lastRefresh === null || $.now() - self.workflow.lastRefresh > 1000) { if (self.workflow.lastRefresh === null || $.now() - self.workflow.lastRefresh > 500) {
// Check if last request is less than one second away this.instance.GET("/ajax/fs/filecount", {
var promise = this.instance.GET("/ajax/fs/filelist", { path: this.workflow.path
"path": this.workflow.path, }).done(function(res) {
});
self.workflow.lastRefresh = $.now(); self.instance.setLoading(true, res.count > 50 ? 0 : null);
promise.done(function(content) {
// Check if last request is less than one second away
var promise = self.instance.GET("/ajax/fs/filelist", {
"path": self.workflow.path
});
self.workflow.lastRefresh = $.now(); self.workflow.lastRefresh = $.now();
if (Object.keys(content.filelist).length == 1 && content.filelist[0].warning !== if (self.view.fileContentContainer !== null) {
undefined) { self.selections.unselectAll()
self.instance.alert(content.filelist[0].warning); self.view.fileContentContainer.empty();
vispa.messenger.error(content.filelist[0].warning); };
content.filelist = [];
} promise.done(function(content) {
self.refresh(content); self.workflow.lastRefresh = $.now();
if (Object.keys(content.filelist).length == 1 && content.filelist[0].warning !==
undefined) {
self.instance.alert(content.filelist[0].warning);
vispa.messenger.error(content.filelist[0].warning);
content.filelist = [];
}
self.refresh(content);
}).fail(function(err) {
self.instance.setLoading(false);
});
}); });
} else {
this.instance.setLoading(false);
} }
}, },
refresh: function(content, sort, reverse, filter) { refresh: function(content, sort, reverse, filter) {
var self = this;
if (!content) { if (!content) {
return this; return;
} }
sort = sort === undefined ? this.workflow.sort : sort; sort = sort === undefined ? this.workflow.sort : sort;
reverse = reverse === undefined ? this.workflow.reverse : reverse; reverse = reverse === undefined ? this.workflow.reverse : reverse;
...@@ -100,8 +113,8 @@ var FileBase = Class.extend({ ...@@ -100,8 +113,8 @@ var FileBase = Class.extend({
} }
} }
this.helper.sortItems(content, sort, reverse); this.helper.sortItems(content, sort, reverse);
this.menuitems.hideMenu();
this.workflow.currentView.setContent(content); this.workflow.currentView.setContent(content);
this.menuitems.hideMenu();
this.instance.setLabel(this.workflow.path, true); this.instance.setLabel(this.workflow.path, true);
this.instance.setLoading(false); this.instance.setLoading(false);
} }
......
...@@ -43,18 +43,18 @@ var FileBaseView = Class.extend({ ...@@ -43,18 +43,18 @@ var FileBaseView = Class.extend({
}, },
// convert timestamp to dd.mm.jjjj hh:mm:ss // convert timestamp to dd.mm.jjjj hh:mm:ss
"mtime": { "mtime": {
"text": function(nodeObj) { "text": function() {
return self.FileBase.helper.convertTimestamp(this.mtime); return self.FileBase.helper.convertTimestamp(this.mtime);
} }
}, },
// convert size from bytes to kB, Mb, etc // convert size from bytes to kB, Mb, etc
"size": { "size": {
"text": function(nodeObj) { "text": function() {
return self.FileBase.helper.convertSize(this.size).size; return self.FileBase.helper.convertSize(this.size).size;
} }
}, },
"sizeSuffix": { "sizeSuffix": {
"text": function(nodeObj) { "text": function() {
return self.FileBase.helper.convertSize(this.size).sizeSuffix; return self.FileBase.helper.convertSize(this.size).sizeSuffix;
} }
} }
......
...@@ -26,7 +26,6 @@ var Symbolview = Class.extend({ ...@@ -26,7 +26,6 @@ var Symbolview = Class.extend({
this.data = data; this.data = data;
// Get the container, empty it and fill the template // Get the container, empty it and fill the template
this.fileContentContainer.empty();
this.fileContentContainer.html(this.template); this.fileContentContainer.html(this.template);
if (this.FileBase.instance.getPreference("Open") == "single" || vispa.device.hasTouch) { if (this.FileBase.instance.getPreference("Open") == "single" || vispa.device.hasTouch) {
......
...@@ -27,7 +27,6 @@ var Tableview = Class.extend({ ...@@ -27,7 +27,6 @@ var Tableview = Class.extend({
this.data = data; this.data = data;
// Get the container, empty it and fill the template // Get the container, empty it and fill the template
this.fileContentContainer.empty();
this.fileContentContainer.html(this.template); this.fileContentContainer.html(this.template);
// Set the right path // Set the right path
......
...@@ -25,6 +25,7 @@ function getFileMenuEntries() { ...@@ -25,6 +25,7 @@ function getFileMenuEntries() {
iconClass: "glyphicon glyphicon-arrow-up", iconClass: "glyphicon glyphicon-arrow-up",
buttonClass: "btn-default", buttonClass: "btn-default",
callback: function() { callback: function() {
this.fb.workflow.lastRefresh = null;
this.fb.workflow.path = this.fb.workflow.parentpath; this.fb.workflow.path = this.fb.workflow.parentpath;
this.fb.updateView(); this.fb.updateView();
} }
......
var FileSelectorItems = FileBaseMenuItems.extend({
init: function(FileBase) {
this._super(FileBase);
this.FileBase = FileBase;
},
getContextMenuPostion: function(event, contextMenu) {
var menuPostion = {};
var menuDimension = {};
// store the fileContentContainer fCC
var fCC = this.FileBase.view.fileContentContainer;
var xOffsetModal = +fCC.parent().parent().parent().position().left + fCC.parent().position()
.left;
var offset = fCC.offset().top;
menuDimension.x = contextMenu.outerWidth();
menuDimension.y = contextMenu.outerHeight();
menuPostion.x = 2 * event.clientX - event.pageX;
menuPostion.y = event.clientY - offset;
menuPostion.x -= xOffsetModal;
if (vispa.device.hasTouch) {
menuPostion.x += 5;
menuPostion.y += 5;
}
// Check if the side borders are reached
if (menuPostion.x + menuDimension.x > fCC.width()) {
menuPostion.x = fCC.width() - menuDimension.x;
}
// Check if the lower border is reached
if (menuPostion.y + menuDimension.y > fCC.height()) {
menuPostion.y = fCC.height() - menuDimension.y;
}
return menuPostion;
}
});
\ No newline at end of file
...@@ -68,6 +68,7 @@ var FileSelector = FileBase.extend({ ...@@ -68,6 +68,7 @@ var FileSelector = FileBase.extend({
// this.view = new SelectorView(this); // this.view = new SelectorView(this);
this.actions = new FileSelectorActions(this); this.actions = new FileSelectorActions(this);
this.selections = new FileSelectorSelections(this); this.selections = new FileSelectorSelections(this);
this.menuitems = new FileSelectorItems(this);
this.workflow.sort = args.sort !== undefined ? args.sort : this.workflow.sort; this.workflow.sort = args.sort !== undefined ? args.sort : this.workflow.sort;
this.workflow.reverse = args.reverse !== undefined ? args.reverse : this.workflow.reverse; this.workflow.reverse = args.reverse !== undefined ? args.reverse : this.workflow.reverse;
......
...@@ -4,63 +4,72 @@ function getShortcuts() { ...@@ -4,63 +4,72 @@ function getShortcuts() {
singleSelect: { singleSelect: {
description: "Key for selection of single files or folders", description: "Key for selection of single files or folders",
value: "down:"+ctrlMeta, value: "down:"+ctrlMeta,
callback: function() { callback: function(event) {
event.preventDefault();
this.fb.workflow.selectmode = true; this.fb.workflow.selectmode = true;
} }
}, },
abortSingleSelect: { abortSingleSelect: {
description: "Key for selection of single files or folders", description: "Key for selection of single files or folders",
value: "up:"+ctrlMeta, value: "up:"+ctrlMeta,
callback: function() { callback: function(event) {
event.preventDefault();
this.fb.workflow.selectmode = false; this.fb.workflow.selectmode = false;
} }
}, },
copy: {