nide
Version:
Beautiful IDE for Node.js
358 lines (311 loc) • 14.2 kB
JavaScript
(function() {
var VERSIONS_ANIMATION_DURATION = 1000
var inferCodeMirrorModeFromPath = function(path){
switch (true) {
case !!path.match(/\.js$/): return 'javascript'
case !!path.match(/\.coffee$/): return 'coffeescript'
case !!path.match(/\.json$/): return { name: 'javascript', json: true }
case !!path.match(/\.x?html?$/): return 'htmlmixed'
case !!path.match(/\.php$/): return 'php'
case !!path.match(/\.py$/): return 'python'
case !!path.match(/\.rb$/): return 'ruby'
case !!path.match(/\.lua$/): return 'lua'
case !!path.match(/\.(c|h|cpp|hpp|cc|m|cs|java)$/): return 'clike'
case !!path.match(/\.css$/): return 'css'
case !!path.match(/\.(xml|svg|od(t|p|s))$/): return 'xml'
case !!path.match(/\.ejs$/): return 'application/x-ejs'
case !!path.match(/\.jsp$/): return 'application/x-jsp'
case !!path.match(/\.aspx$/): return 'application/x-aspx'
default: return 'text/plain';
}
}
var makeViewPath = function(path) {
return document.location.protocol + "//" + document.location.hostname + ':' + ((parseInt(document.location.port) || 80) + 1) + path
}
var createCodeMirror = function(parentNode, contents, path, options) {
var mode = inferCodeMirrorModeFromPath(path);
var options = {
value: contents,
mode: mode,
lineNumbers: true,
onChange: options.onChange,
readOnly: options.readOnly,
indentUnit: 4,
enterMode: 'keep',
tabMode: 'shift',
electricChars: false,
smartHome: true,
matchBrackets: true
}
return CodeMirror(parentNode, options);
}
var createGalaxyBackground = function() {
var galaxyBackground = document.createElement('div')
galaxyBackground.innerHTML =
'<h1 class="now">Now</h1>' +
'<h1 class="then">Then</h1>' +
'<button class="done">Done</button>' +
'<button class="revert">Revert</button>' +
'<button class="backward" title="Go backward in time"><img src="img/backward.png" alt="Backward"></button>' +
'<button class="forward" title="Go forward in time"><img src="img/forward.png" alt="Forward"></button>' +
'<div class="no-previous">There are no previous versions for this file.</div>';
galaxyBackground.now = $(".now", galaxyBackground)[0];
galaxyBackground.then = $(".then", galaxyBackground)[0];
galaxyBackground.done = $(".done", galaxyBackground)[0];
galaxyBackground.revert = $(".revert", galaxyBackground)[0];
galaxyBackground.backward = $(".backward", galaxyBackground)[0];
galaxyBackground.forward = $(".forward", galaxyBackground)[0];
galaxyBackground.noPrevious = $(".no-previous", galaxyBackground)[0];
return galaxyBackground;
}
var createActionsBar = function(path) {
var actionsBar = document.createElement('div')
actionsBar.className = 'actions'
actionsBar.innerHTML = '<b>' + cwd + path + '</b> '
actionsBar.renameButton = document.createElement('button')
actionsBar.renameButton.innerHTML = 'Rename'
actionsBar.appendChild(actionsBar.renameButton)
actionsBar.versionsButton = document.createElement('button')
actionsBar.versionsButton.innerHTML = 'Versions'
actionsBar.appendChild(actionsBar.versionsButton)
if (path.match(/\.(x?html?|svg)$/)) {
actionsBar.viewButton = document.createElement('button')
actionsBar.viewButton.innerHTML = 'View'
actionsBar.appendChild(actionsBar.viewButton)
}
return actionsBar;
}
window.CodeEditor = function(entry) {
var codeMirror;
var currentVersion;
var galaxyBackground = createGalaxyBackground()
var actionsBar = createActionsBar(entry.path)
var editor = document.createElement('div')
var versionEditors = []
var versions;
$(actionsBar.renameButton).click(function(e) {
var newName = prompt('New filename:', entry.name)
if (newName) {
connection.renameFile(entry.path, entry.path.replace(/\/[^\/]+$/, '/' + newName))
}
})
if (actionsBar.viewButton) {
$(actionsBar.viewButton).click(function(e) {
var url = makeViewPath(entry.path);
window.open(url, 'view-window');
})
}
var loadVersionNumbered = function(i) {
if (!versions[i].content) {
connection.loadVersion(versions[i].uuid, function(err, contents) {
galaxyBackground.revert.disabled = false;
if (err) {
contents = '<ERROR: Could not load file contents>';
galaxyBackground.revert.disabled = true;
}
var codeMirror = createCodeMirror(versionEditors[i], contents, entry.path, { readOnly: true })
versions[i].content = contents;
})
}
}
function showVersions() {
currentVersion = versions.length - 1;
// "Morph" the user interface into versions mode
$(actionsBar).slideUp(VERSIONS_ANIMATION_DURATION);
$(galaxyBackground).animate({
left: '-250px'
}, VERSIONS_ANIMATION_DURATION)
$(editor).animate({
left: '5%',
top: '50px',
bottom: '50px',
right: '52.5%'
}, VERSIONS_ANIMATION_DURATION).addClass('windowed')
// Change the user interface if no previous versions are available
if (versions.length == 0) {
$(galaxyBackground.noPrevious).show()
$(".revert, .backward, .forward", galaxyBackground).hide()
return;
}
$(galaxyBackground.noPrevious).hide()
$(".revert, .backward, .forward", galaxyBackground).show()
var currentVersionDate = (new Date(versions[currentVersion].date)).toString();
$(galaxyBackground.then).html(currentVersionDate);
for (var i = 0; i < versions.length; i++) {
var version = versions[i]
var versionEditor = document.createElement('div')
versionEditor.className = 'code-editor'
versionEditor.style.zIndex = 98;
versionEditors.push(versionEditor)
galaxyBackground.appendChild(versionEditor)
$(versionEditor).animate({
right: '5%',
top: '50px',
bottom: '50px',
left: '52.5%'
}, VERSIONS_ANIMATION_DURATION).addClass('windowed');
if (versions.length - 1 - i > 3) {
$(versionEditor).hide()
} else {
$(versionEditor).css({
scale: (1 - (versions.length - 1 - i) * 0.05),
translateY: -(versions.length - 1 - i)*20,
opacity: (1 - (versions.length - 1 - i) * (1/3))
})
loadVersionNumbered(i);
}
}
}
$(galaxyBackground.revert).click(function(){
versionEditors[currentVersion].style.zIndex = 100
$(versionEditors[currentVersion]).animate({
left: '5%',
top: '50px',
bottom: '50px',
right: '52.5%'
}, VERSIONS_ANIMATION_DURATION, function() {
codeMirror.setValue(versions[currentVersion].content)
$(versionEditors[currentVersion]).hide()
hideVersions()
})
})
$(galaxyBackground.backward).click(function(){
goToVersion(-1)
})
$(galaxyBackground.forward).click(function(){
goToVersion(1)
})
var goToVersion = function(delta) {
if (versions === undefined || currentVersion === undefined || versionEditors.length === 0) {
throw new Error("Trying to navigate in version history with no versions loaded.")
}
currentVersion += delta;
if (currentVersion >= versions.length) {
currentVersion = versions.length - 1;
}
if (currentVersion <= 0) {
currentVersion = 0;
}
var currentVersionDate = (new Date(versions[currentVersion].date)).toString();
$(galaxyBackground.then).html(currentVersionDate)
for (var i = 0; i < versions.length; i++) {
var version = versions[i]
var versionEditor = versionEditors[i]
var hidden = false;
if (currentVersion - i > 3) {
$(versionEditor).fadeOut()
hidden = true
} else if (currentVersion - i < 0) {
$(versionEditor).fadeOut()
hidden = true
} else {
$(versionEditor).fadeIn()
}
if (hidden) {
$(versionEditor).animate({
scale: (1 - (currentVersion - i) * 0.05),
translateY: -(currentVersion - i)*20,
}, { queue: false })
} else {
loadVersionNumbered(i)
$(versionEditor).animate({
scale: (1 - (currentVersion - i) * 0.05),
translateY: -(currentVersion - i)*20,
opacity: (1 - (currentVersion - i) * (1/3))
}, { queue: false })
}
}
}
var hideVersions = function() {
$(actionsBar).slideDown(VERSIONS_ANIMATION_DURATION);
$(galaxyBackground).animate({
left: 0
}, VERSIONS_ANIMATION_DURATION)
$(editor).animate({
left: '0%',
top: '0px',
bottom: '0px',
right: '0%'
}, VERSIONS_ANIMATION_DURATION, function() {
$(editor).removeClass('windowed')
for (var i = 0; i < versionEditors.length; i++) {
galaxyBackground.removeChild(versionEditors[i])
}
versionEditors = []
versions = undefined
currentVersion = undefined
})
}
$(actionsBar.versionsButton).click(function(e) {
connection.loadVersions(entry.path, function(err, v) {
if (err) {
alert('Could not load versions: ' + err)
} else {
versions = v
showVersions()
}
})
})
$(galaxyBackground.done).click(function(e) {
hideVersions();
})
editor.appendChild(actionsBar)
editor.className = 'code-editor'
if (entry.path.match(/\.(jpe?g|png|gif|bmp)$/)) {
var image = document.createElement('img')
image.src = makeViewPath(entry.path);
image.className = 'view'
editor.appendChild(image);
$(actionsBar.versionsButton).hide();
} else {
connection.loadFile(entry.path, function(err, file) {
if (err) {
var errorBar = document.createElement('div');
errorBar.className = 'error'
errorBar.innerHTML = '<b>Unable to open file:</b> ' + err;
editor.appendChild(errorBar);
$(errorBar).hide();
$(errorBar).fadeIn(250);
} else {
codeMirror = createCodeMirror(editor, file, entry.path, { onChange: function(editor) {
content = editor.getValue()
changed = true
}})
codeMirror.focus()
var content = file
var changed = false;
var saving = false;
setInterval(function() {
if (changed && !saving) {
var done = false;
saving = true;
var selected = $('.selected')
selected.addClass('syncing')
connection.saveFile(entry.path, content, function(err){
if (!err) {
changed = false
done = true;
selected.removeClass('syncing')
}
saving = false
})
setTimeout(function() {
if (!done) {
saving = false
}
}, 8000)
}
}, 3000)
}
})
}
galaxyBackground.appendChild(editor)
galaxyBackground.className = 'galaxy-background'
galaxyBackground.focus = function() {
if (codeMirror) {
codeMirror.focus()
}
}
return galaxyBackground
}
})()