Commit bf96eaac authored by ThorbenQuast's avatar ThorbenQuast
Browse files

editor: auto save in seperate file

parent d86bbe22
......@@ -19,8 +19,7 @@
Abort
</button>
</span>
<input type="text" class="form-control" id="command-line" placeholder="Commandline" value="" data-toggle="tooltip" data-placement="bottom"
title="Execution command relative to the filepath. %file is a variable holding the filename. (e.g. 'python %file')">
<input type="text" class="form-control" id="command-line" placeholder="Commandline" value="" data-toggle="tooltip" data-placement="bottom" title="Execution command relative to the filepath. %file is a variable holding the filename. (e.g. 'python %file')">
</div>
<pre class="codeeditor-output">Execution Output</pre>
<div class="codeeditor-output-buttons">
......@@ -54,4 +53,4 @@
</div>
</div>
</div>
\ No newline at end of file
</div>
......@@ -8,8 +8,8 @@ var CodeEditor = Emitter.extend({
this.path = path;
this.mtime = null;
this.lastContent = "";
this.modified_processing = false;
this.saving_processing = false;
this.modifiedProcessing = false;
this.savingProcessing = false;
this.ace = null;
this.originalAceCommands = null;
......@@ -40,28 +40,28 @@ var CodeEditor = Emitter.extend({
this.ace = ace.edit($(self.node).get(0));
this.ace.focus();
this.view.onSocket('watch', function(data) {
if (data.watch_id != 'code') {
this.view.onSocket("watch", function(data) {
if (data.watch_id != "code") {
return;
}
if (self.modified_processing)
if (self.modifiedProcessing)
return;
if (data.mtime == -1) {
self.modified_processing = true;
self.modifiedProcessing = true;
self.view.confirm(
"The file " + self.path + " has been deleted or renamed." +
"<br/>Do you want to recreate it?",
function(confirmed) {
if (confirmed) {
self.save(null, 'new');
self.save(null, "new");
} else {
self.path = null;
self.view.setLabel(null, false);
}
self.modified_processing = false;
self.modifiedProcessing = false;
});
} else if (data.mtime > self.mtime && !self.saving_processing) {
self.modified_processing = true;
} else if (data.mtime > self.mtime && !self.savingProcessing) {
self.modifiedProcessing = true;
self.view.confirm(
"The file " + self.path + " has changed on disk." +
"<br />Do you want to reload it?",
......@@ -72,7 +72,7 @@ var CodeEditor = Emitter.extend({
self.path = null;
self.view.setLabel(null, false);
}
self.modified_processing = false;
self.modifiedProcessing = false;
});
}
});
......@@ -105,13 +105,10 @@ var CodeEditor = Emitter.extend({
this.view.setLoading(true);
this.view.POST(vispa.url.dynamic("/ajax/fs/get_file"), {
path: path,
utf8: true,
watch_id: "code"
}).done(function(res) {
var initContent = function(res) {
if (!res.success) {
self.view.alert("<html>An internal server error has occured. <br /><br /> The editor has been closed. </html>")
self.view.alert("<html>An internal server error has occured. <br />" +
"<br /> The editor has been closed. </html>");
self.view.close();
}
self.path = path;
......@@ -123,7 +120,37 @@ var CodeEditor = Emitter.extend({
self.goToTop();
self.checkModifications();
self.setupAutoSave();
};
//new: check for auto save tmp file
this.view.POST(vispa.url.dynamic("/ajax/fs/get_file"), {
path: path + "_tmp",
utf8: true,
watch_id: "code"
}).done(function(res) {
if (res.success) { //an autosave file exists
self.view.confirm("An autosave file exists. Do you want to load its content?",
function(b) {
if (b)
initContent(res);
else
self.view.POST(vispa.url.dynamic("/ajax/fs/get_file"), {
path: path,
utf8: true,
watch_id: "code"
}).done(function(res) {
initContent(res);
});
});
} else {
self.view.POST(vispa.url.dynamic("/ajax/fs/get_file"), {
path: path,
utf8: true,
watch_id: "code"
}).done(function(res) {
initContent(res);
});
}
}).always(function() {
self.view.setLoading(false);
});
......@@ -136,14 +163,25 @@ var CodeEditor = Emitter.extend({
clearTimeout(this.autosaveTimeOut);
this.autosaveTimeOut = null;
var t = this.view.getPreference('autosave');
t = t * 1000.0
var t = this.view.getPreference("autosave");
t = t * 1000.0;
if (t == 0)
return this;
this.autosaveTimeOut = setTimeout(function() {
if (self.path)
self.save()
else
if (self.path && self.writable) {
self.savingProcessing = true;
var tempPath = self.path + "_tmp";
self.view.POST(vispa.url.dynamic("/ajax/fs/save_file"), {
path: tempPath,
content: self.getContent(),
utf8: true,
watch_id: "code"
}).done(function(res) {
self.savingProcessing = false;
self.mtime = res.mtime;
self.setupAutoSave();
});
} else
self.setupAutoSave();
}, t);
},
......@@ -163,8 +201,7 @@ var CodeEditor = Emitter.extend({
return this.ace.session.getLength();
},
checkModifications: function(option) {
var self = this;
checkModifications: function() {
clearTimeout(this.keyupMinTimeout);
clearTimeout(this.keyupMaxTimeout);
......@@ -187,19 +224,19 @@ var CodeEditor = Emitter.extend({
var type = this.path.split(".").pop();
var currentline = this.ace.selection.getCursor()['row'] + 1;
var currentline = this.ace.selection.getCursor().row + 1;
this.ace.gotoLine(currentline);
var sign = null
var sign = null;
switch (type) {
case "py":
sign = "#"
sign = "#";
break;
case "js":
case "h":
case "c":
case "cpp":
sign = "//"
sign = "//";
break;
default:
{
......@@ -229,7 +266,8 @@ var CodeEditor = Emitter.extend({
var fileExtension = path.split(".").pop().toLowerCase();
if (!~self.view._extension.fileExtensions.indexOf(fileExtension)) {
var msg = "<html>File extension '" + fileExtension + "' is not supported! <br /> Save anyway?</html>";
var msg = "<html>File extension '" + fileExtension +
"' is not supported! <br /> Save anyway?</html>";
self.view.confirm(msg, function(confirmed) {
if (confirmed) {
self.save(callback, "new", path);
......@@ -271,7 +309,7 @@ var CodeEditor = Emitter.extend({
}
this.view.setLoading(true);
this.saving_processing = true;
this.savingProcessing = true;
this.view.POST(vispa.url.dynamic("/ajax/fs/save_file"), {
path: path ? path : this.path,
......@@ -294,7 +332,7 @@ var CodeEditor = Emitter.extend({
}
}).always(function() {
self.view.setLoading(false);
self.saving_processing = false;
self.savingProcessing = false;
});
return this;
......@@ -420,7 +458,7 @@ var CodeEditor = Emitter.extend({
},
getAceMode: function(fileExtension) {
var mode = "ace/mode/"
var mode = "ace/mode/";
switch (fileExtension) {
case "c":
case "cpp":
......@@ -442,7 +480,6 @@ var CodeEditor = Emitter.extend({
case "py":
mode += "python";
break;
case "txt":
default:
mode += "text";
break;
......
......@@ -95,7 +95,7 @@ var CodeEditorView = vispa.ExtensionView.Center.extend({
var self = this;
this.setLoading(true);
var dfd = this.getTemplate("html/main.html", function(err, tmpl) {
this.getTemplate("html/main.html", function(err, tmpl) {
$(tmpl).appendTo(node);
// setup the ace editor
......@@ -120,7 +120,6 @@ var CodeEditorView = vispa.ExtensionView.Center.extend({
},
onBeforeShow: function() {
var self = this;
if (!this.editor.path || !this.editor.mtime)
return this;
......@@ -177,6 +176,10 @@ var CodeEditorView = vispa.ExtensionView.Center.extend({
// cleanup
var cleanUp = function() {
self.GET(vispa.url.dynamic("/ajax/fs/unwatch"), {});
self.GET(vispa.url.dynamic("/ajax/fs/remove"), {
"path": '["' + self.editor.path + '_tmp"]'
//syntax of path required for the fs remove function
});
self.POST("close");
self.output.running = false;
self.preview.clearInterval();
......@@ -188,18 +191,18 @@ var CodeEditorView = vispa.ExtensionView.Center.extend({
var doAsk = !this.forceClose && this.isModified();
if (doAsk)
this.confirm("Save changes before closing?", function(b) {
var after_save = function() {
var afterSave = function() {
self.forceClose = true;
cleanUp();
self.close(); //close the editor after saving
}
};
if (b) {
if (self.editor.writable)
self.editor.save(after_save);
self.editor.save(afterSave);
else
self.editor.saveAs(after_save);
self.editor.saveAs(afterSave);
} else
after_save();
afterSave();
});
else
cleanUp();
......@@ -227,7 +230,8 @@ var CodeEditorView = vispa.ExtensionView.Center.extend({
var path = paths[i];
var fileExtension = path.split(".").pop().toLowerCase();
if (self._extension.fileExtensions.indexOf(fileExtension) == -1) {
var msg = "<html>File extension '" + fileExtension + "' is not supported! <br /> Open anyway?</html>";
var msg = "<html>File extension '" + fileExtension +
"' is not supported! <br /> Open anyway?</html>";
self.confirm(msg, function(confirmed) {
if (confirmed)
self._extension.createInstance(self.getWorkspaceId(), "center", path);
......
......@@ -13,13 +13,13 @@ var CodeEditorOutput = Emitter.extend({
// commandline template -> list of extensions
this.commandlineTemplates = {
'python %file': ['py'],
'sh %file': ['sh'],
'php %file': ['php'],
'pdflatex %file': ['tex'],
'gcc %file -o %file.out && ./%file.out': ['c'],
'g++ %file -o %file.out && ./%file.out':
['cc', 'cp', 'cxx', 'cpp', 'CPP', 'c++', 'C']
"python %file": ["py"],
"sh %file": ["sh"],
"php %file": ["php"],
"pdflatex %file": ["tex"],
"gcc %file -o %file.out && ./%file.out": ["c"],
"g++ %file -o %file.out && ./%file.out":
["cc", "cp", "cxx", "cpp", "CPP", "c++", "C"]
};
},
......@@ -59,13 +59,13 @@ var CodeEditorOutput = Emitter.extend({
});
// command line setup
this.commandline = rightTopNode.find("#command-line").on('keypress', function(event) {
this.commandline = rightTopNode.find("#command-line").on("keypress", function(event) {
if (event.which == 13) { // return key pressed
self.execute();
event.preventDefault();
}
}).tooltip({
trigger: 'focus'
trigger: "focus"
});
self.setCommandLine();
......@@ -77,14 +77,14 @@ var CodeEditorOutput = Emitter.extend({
// register events
this.view.onSocket('start', function(data) {
this.view.onSocket("start", function(data) {
self.append(
"executing \"" + data.command + "\"\n" +
"--------------------\n" +
"OUTPUT:\n\n");
}).onSocket('data', function(data) {
}).onSocket("data", function(data) {
self.append(data);
}).onSocket('done', function(data) {
}).onSocket("done", function(data) {
self.append(
"\n--------------------\n" +
(data.aborted ? "process was aborted!\n" : "") +
......@@ -173,7 +173,7 @@ var CodeEditorOutput = Emitter.extend({
base: filePath
}).done(function(res) { //double check for running jobs
if (!res.success) {
self.view.alert("There's already a running job!");
self.view.alert("There is already a running job!");
}
});
});
......@@ -206,9 +206,10 @@ var CodeEditorOutput = Emitter.extend({
return this;
}
this.initialClear();
var textarray = text.split('\n');
var maxlines = this.view.getPreference("maxLines") < textarray.length ? this.view.getPreference("maxLines") : textarray.length;
var cleantext = textarray.slice(-maxlines).join("\n")
var textarray = text.split("\n");
var maxlines = this.view.getPreference("maxLines") < textarray.length ?
this.view.getPreference("maxLines") : textarray.length;
var cleantext = textarray.slice(-maxlines).join("\n");
this.preNode.text(cleantext);
return this;
},
......@@ -276,15 +277,15 @@ var CodeEditorOutput = Emitter.extend({
"path": path,
callback: function(path) {
var fileExtension = path.split(".").pop().toLowerCase();
if (fileExtension != 'txt')
self.view.alert("File extension '" + fileExtension + "' is not supported!");
if (fileExtension != "txt")
self.view.alert("File extension '" + fileExtension + "'' is not supported!");
else {
self.view.setLoading(true);
var req = {
path: path,
content: self.getText()
};
self.view.POST("savecontent", req).done(function(res) {
self.view.POST("savecontent", req).done(function() {
self.view.alert("Output saved in file " + path);
}).always(function() {
self.view.setLoading(false);
......
......@@ -114,4 +114,4 @@ var getDefaultCodeEditorShortcuts = function() {
}
}
};
}
};
......@@ -44,15 +44,15 @@ var CodeEditorPreview = Emitter.extend({
self.inputFocused = false;
});
this.view.onSocket('watch', function(data){
if (data.watch_id != 'preview') {
this.view.onSocket("watch", function(data){
if (data.watch_id != "preview") {
return;
}
if (data.event != 'modify') {
if (data.event != "modify") {
return;
}
self.previewChanged = true;
})
});
if (this.editor.path)
this.setPath(this.editor.path, true);
......@@ -109,7 +109,8 @@ var CodeEditorPreview = Emitter.extend({
watch_id: "preview"
}).done(function(res) {
var files = $.grep(res.filelist, function(file) {
return file.type == "f" && ~self.allowedExtensions.indexOf(file.name.split(".").pop().toLowerCase());
return file.type == "f" && ~self.allowedExtensions.indexOf(file.
name.split(".").pop().toLowerCase());
});
var previewData = [];
files.forEach(function(file) {
......@@ -225,7 +226,7 @@ var CodeEditorPreview = Emitter.extend({
callback: function(path) {
self.setPath(path, false);
}
}
};
var extension = vispa.extensions.getExtension("file");
extension.createInstance(this.view.getWorkspaceId(), "FileSelector", args);
......
......@@ -6,9 +6,9 @@ var CodeEditorUI = Emitter.extend({
this.view = view;
this.editor = view.editor;
this.x_dragbar = null;
this.y_dragbar = null;
this.old_y_drag_position = null;
this.xDragbar = null;
this.yDragbar = null;
this.oldYDragPosition = null;
},
setup: function() { //resize of divs per mouse drag
......@@ -16,48 +16,49 @@ var CodeEditorUI = Emitter.extend({
//.resizable of jquery-ui is not used because it interferes /
//does not work with bootstrap
var self = this;
this.x_dragbar = $(".codeeditor-x-dragbar", this.view._nodes.content);
this.y_dragbar = $(".codeeditor-y-dragbar", this.view._nodes.content);
this.xDragbar = $(".codeeditor-x-dragbar", this.view._nodes.content);
this.yDragbar = $(".codeeditor-y-dragbar", this.view._nodes.content);
this.x_dragbar.on({
this.xDragbar.on({
mouseover: function() {
$('body').css('cursor', 'col-resize');
$("body").css("cursor", "col-resize");
},
mouseleave: function() {
$('body').css('cursor', 'default');
$("body").css("cursor", "default");
}
});
this.x_dragbar.draggable({
this.xDragbar.draggable({
axis: "x",
stop: function(event, ui) {
var width = $(self.view._nodes.content).width();
var r = 100. * (event.pageX) / width;
var r = 100.0 * (event.pageX) / width;
self.setInputOutputRatio(r);
}
});
this.y_dragbar.on({
this.yDragbar.on({
mouseover: function() {
$('body').css('cursor', 'row-resize');
$("body").css("cursor", "row-resize");
},
mouseleave: function() {
$('body').css('cursor', 'default');
$("body").css("cursor", "default");
}
});
//the dragging here seems a little more complicated because we need to consider offsets
this.y_dragbar.draggable({
this.yDragbar.draggable({
axis: "y",
start: function(event, ui){
self.old_y_drag_position = self.y_dragbar.css("top");
start: function(event, ui) {
self.oldYDragPosition = self.yDragbar.css("top");
},
//revert: true does not do the desired job (position is fixed when resizing the window)-->own hack
//revert: true does not do the desired job (position is fixed
//when resizing the window)-->own hack
stop: function(event, ui) {
var height = $(self.view._nodes.content).height();
var offset = $(window).height() - height; //the offset in y due to the tabs etc.
var r = 100. * (event.pageY - offset) / height;
var r = 100.0 * (event.pageY - offset) / height;
if (event.pageY < offset) {
self.y_dragbar.css("top", self.old_y_drag_position); //restore old position
self.yDragbar.css("top", self.oldYDragPosition); //restore old position
return;
}
self.setTextPictureRatio(r);
......@@ -65,7 +66,7 @@ var CodeEditorUI = Emitter.extend({
});
},
setInputOutputRatio: function(r, option) { //r: ratio between left side width and total width
setInputOutputRatio: function(r) { //r: ratio between left side width and total width
r = r == null ? this.view.getPreference("inputOutputRatio") : r;
$(".codeeditor-left", this.view._nodes.content).css("width", String(r) + "%");
$(".codeeditor-x-dragbar", this.view._nodes.content).css("left", String(r) + "%");
......@@ -82,4 +83,4 @@ var CodeEditorUI = Emitter.extend({
return this;
},
});
\ No newline at end of file
});
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment