From 0054bb87946e27d534b49fb1cdf1acf1b261a888 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 4 Jan 2015 02:13:28 +0400 Subject: [PATCH] cleanup --- demo/kitchen-sink/doclist.js | 20 ++++- lib/ace/lib/net.js | 10 +-- lib/ace/mode/abap_highlight_rules.js | 2 +- static.js | 113 +++++++++++++++++++++------ static.py | 11 ++- tool/mode_creator.html | 4 +- tool/mode_creator.js | 92 ++++++++++++---------- 7 files changed, 165 insertions(+), 87 deletions(-) diff --git a/demo/kitchen-sink/doclist.js b/demo/kitchen-sink/doclist.js index abdc9a3e..a4848d50 100644 --- a/demo/kitchen-sink/doclist.js +++ b/demo/kitchen-sink/doclist.js @@ -169,9 +169,8 @@ function loadDoc(name, callback) { }); } -// callback is called with the error message from PUT (if any) function saveDoc(name, callback) { - var doc = fileCache[name]; + var doc = fileCache[name] || name; if (!doc || !doc.session) return callback("Unknown document: " + name); @@ -182,9 +181,24 @@ function saveDoc(name, callback) { else if (parts[0] == "ace") path = "lib/" + path; - net.request('PUT', path, doc.session.getValue(), callback); + upload(path, doc.session.getValue(), callback); } +function upload(url, data, callback) { + url = net.qualifyURL(url); + if (!/https?:/.test(url)) + return callback(new Error("Unsupported url scheme")); + var xhr = new XMLHttpRequest(); + xhr.open("PUT", url, true); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + callback(!/^2../.test(xhr.status)); + } + }; + xhr.send(data); +}; + + module.exports = { fileCache: fileCache, docs: sort(prepareDocList(docs)), diff --git a/lib/ace/lib/net.js b/lib/ace/lib/net.js index 357fcb9d..bba76df8 100644 --- a/lib/ace/lib/net.js +++ b/lib/ace/lib/net.js @@ -9,9 +9,9 @@ define(function(require, exports, module) { "use strict"; var dom = require("./dom"); -exports.request = function (verb, url, data, callback) { +exports.get = function (url, callback) { var xhr = new XMLHttpRequest(); - xhr.open(verb, url, true); + xhr.open('GET', url, true); xhr.onreadystatechange = function () { //Do not explicitly handle errors, those should be //visible via console output in the browser. @@ -19,11 +19,7 @@ exports.request = function (verb, url, data, callback) { callback(xhr.responseText); } }; - xhr.send(data); -}; - -exports.get = function (url, callback) { - this.request('GET', url, null, callback); + xhr.send(null); }; exports.loadScript = function(path, callback) { diff --git a/lib/ace/mode/abap_highlight_rules.js b/lib/ace/mode/abap_highlight_rules.js index 6b232c90..bab1e504 100644 --- a/lib/ace/mode/abap_highlight_rules.js +++ b/lib/ace/mode/abap_highlight_rules.js @@ -126,7 +126,7 @@ var AbapHighlightRules = function() { {token : "string", regex : "`", next : "start"}, {defaultToken : "string"} ] - } + }; }; oop.inherits(AbapHighlightRules, TextHighlightRules); diff --git a/static.js b/static.js index 4f7e7248..a711715e 100755 --- a/static.js +++ b/static.js @@ -10,37 +10,100 @@ var http = require("http") // compatibility with node 0.6 if (!fs.exists) - fs.exists = path.exists; + fs.exists = path.exists; -http.createServer(function(request, response) { +var allowSave = process.argv.indexOf("--allow-save") != -1; - var uri = url.parse(request.url).pathname - , filename = path.join(process.cwd(), uri); - - fs.exists(filename, function(exists) { - if(!exists) { - response.writeHead(404, {"Content-Type": "text/plain"}); - response.write("404 Not Found\n"); - response.end(); - return; +http.createServer(function(req, res) { + var uri = url.parse(req.url).pathname + , filename = path.join(process.cwd(), uri); + + if (req.method == "PUT") { + if (!allowSave) + return error(res, 404, "Saving not allowed pass --allow-save to enable"); + save(req, res, filename); } - if (fs.statSync(filename).isDirectory()) filename += '/index.html'; + fs.exists(filename, function(exists) { + if (!exists) + return error(res, 404, "404 Not Found\n"); - fs.readFile(filename, "binary", function(err, file) { - if(err) { - response.writeHead(500, {"Content-Type": "text/plain"}); - response.write(err + "\n"); - response.end(); - return; - } + if (fs.statSync(filename).isDirectory()) { + var files = fs.readdirSync(filename); + res.writeHead(200, {"Content-Type": "text/html"}); + + files.push(".", ".."); + var html = files.map(function(name) { + var href = uri + "/" + name; + href = href.replace(/[\/\\]+/g, "/").replace(/\/$/g, ""); + if (fs.statSync(filename + "/" + name + "/").isDirectory()) + href += "/"; + return "" + name + "
"; + }); - var contentType = mime.lookup(filename) || "text/plain"; - response.writeHead(200, {"Content-Type": contentType}); - response.write(file, "binary"); - response.end(); + res._hasBody && res.write(html.join("")); + res.end(); + return; + } + + fs.readFile(filename, "binary", function(err, file) { + if (err) { + res.writeHead(500, { "Content-Type": "text/plain" }); + res.write(err + "\n"); + res.end(); + return; + } + + var contentType = mime.lookup(filename) || "text/plain"; + res.writeHead(200, { "Content-Type": contentType }); + res.write(file, "binary"); + res.end(); + }); }); - }); }).listen(port, ip); -console.log("http://localhost:" + port); +function error(res, status, message, error) { + console.error(error || message); + res.writeHead(status, { "Content-Type": "text/plain" }); + res.write(message); + res.end(); +} + +function save(req, res, filePath) { + var data = ""; + req.on("data", function(chunk) { + data += chunk; + }); + req.on("error", function() { + error(res, 404, "Could't save file"); + }); + req.on("end", function() { + try { + fs.writeFileSync(filePath, data); + } + catch (e) { + return error(res, 404, "Could't save file", e); + } + res.statusCode = 200; + res.end("OK"); + }); +} + +function getLocalIps() { + var os = require("os"); + + var interfaces = os.networkInterfaces ? os.networkInterfaces() : {}; + var addresses = []; + for (var k in interfaces) { + for (var k2 in interfaces[k]) { + var address = interfaces[k][k2]; + if (address.family === "IPv4" && !address.internal) { + addresses.push(address.address); + } + } + } + return addresses; +} + +console.log("http://" + (ip == "0.0.0.0" ? getLocalIps()[0] : ip) + ":" + port); + diff --git a/static.py b/static.py index 913648e2..7a2faf91 100755 --- a/static.py +++ b/static.py @@ -263,13 +263,13 @@ def command(): puttable = set(path.abspath(p) for p in options.puttable.replace(","," ").split()) if puttable and host not in ('127.0.0.1', 'localhost'): - sys.exit("Permitting PUT access for non-localhost connections is unwise.") + print("Permitting PUT access for non-localhost connections may be unwise.") options.rootdir = path.abspath(options.rootdir) for p in puttable: - if not p.startswith(options.rootdir): - sys.exit("puttable path '%s' not under root '%s'" % (p, options.rootdir)) + if not p.startswith(options.rootdir): + sys.exit("puttable path '%s' not under root '%s'" % (p, options.rootdir)) # cut off root prefix from puttable paths puttable = set(p[len(options.rootdir):] for p in puttable) @@ -283,13 +283,12 @@ def command(): print "Serving %s to http://%s:%d" % (options.rootdir, host, port) if puttable: print("The following paths (relative to server root) may be "+ - "OVERWRITTEN via HTTP PUT.\n"+ - "I HOPE EVERY USER ON THIS SYSTEM IS TRUSTED!") + "OVERWRITTEN via HTTP PUT.") for p in puttable: print p make_server(host, port, app).serve_forever() except KeyboardInterrupt, ki: - print "Cio, baby!" + print "Ciao, baby!" except: sys.exit("Problem initializing server: %s" % sys.exc_info()[1]) diff --git a/tool/mode_creator.html b/tool/mode_creator.html index b4c66715..259ba64e 100644 --- a/tool/mode_creator.html +++ b/tool/mode_creator.html @@ -59,7 +59,7 @@ - + @@ -71,7 +71,7 @@ - + diff --git a/tool/mode_creator.js b/tool/mode_creator.js index c78345ac..e79c54c6 100644 --- a/tool/mode_creator.js +++ b/tool/mode_creator.js @@ -53,7 +53,8 @@ util.bindDropdown("doc", function(value) { doclist.loadDoc(value, function(session) { if (session) { editor2.setSession(session); - uploadEl2.disabled = session.getUndoManager().isClean(); + session.getUndoManager().markClean(); + updateSaveButtonState(null, editor2); } }); }); @@ -61,7 +62,7 @@ util.bindDropdown("doc", function(value) { var modeEl = document.getElementById("modeEl"); util.fillDropdown(modeEl, modelist.modes); var modeSessions = {}; -var savedLeadingComments = ""; + util.bindDropdown(modeEl, function(value) { if (modeSessions[value]) { editor1.setSession(modeSessions[value]); @@ -70,17 +71,18 @@ util.bindDropdown(modeEl, function(value) { } var hp = "./lib/ace/mode/" + value + "_highlight_rules.js"; net.get(hp, function(text) { - uploadEl1.disabled = true; - savedLeadingComments = text; - text = util.stripLeadingComments(text); - savedLeadingComments = savedLeadingComments.substr(0, savedLeadingComments.length - text.length); - var session = new EditSession(text); session.setUndoManager(new UndoManager()); + modeSessions[value] = session; - session.setMode("ace/mode/javascript"); + session.setMode("ace/mode/javascript", function() { + if (session.getLine(0).match(/^\s*\//)) + session.toggleFoldWidget(0); // fold licence comment + }); editor1.setSession(modeSessions[value]); + session.getUndoManager().markClean(); + updateSaveButtonState(null, editor1); schedule(); }); }); @@ -91,43 +93,47 @@ document.getElementById("syncToMode").onclick = function() { run(); }; -var uploadEl1 = document.getElementById("uploadToServer1"); -var uploadEl2 = document.getElementById("uploadToServer2"); -uploadEl1.onclick = function() { - var text = savedLeadingComments + editor1.getValue(); - var url = "./lib/ace/mode/" + modeEl.value + "_highlight_rules.js"; - net.request('PUT', url, text, function(text) { - handle_put_result(text, editor1, uploadEl1); - }); -}; -editor1.commands.bindKey("Ctrl-S", uploadEl1.onclick); -uploadEl2.onclick = function() { - doclist.saveDoc(docEl.value, function(text) { - handle_put_result(text, editor2, uploadEl2); - }); -}; -editor2.commands.bindKey("Ctrl-S", uploadEl2.onclick); -editor1.on('change', function() { - uploadEl1.disabled = false; -}); -editor2.on('change', function() { - uploadEl2.disabled = false; -}); +editor1.saveButton = document.getElementById("saveButton1"); +editor2.saveButton = document.getElementById("saveButton2"); +editor1.saveButton.editor = editor1; +editor2.saveButton.editor = editor2; -function handle_put_result(text, editor, buttonEl) { - text = text.trim(); - if (text.length == 0) { - buttonEl.disabled = true; - editor.getSession().getUndoManager().markClean(); - } else { - if (text.indexOf("405") == 0) { - log("Write access to this file is disabled.\n"+ - "To enable saving your changes to disk, clone the Ace repository"+ - "\nand run the included static.py web server with the option\n"+ - "--puttable='lib/ace/mode/*_highlight_rules.js,demo/kitchen-sink/docs/*'"); - } else - log(text); +editor1.saveButton.onclick = function() { + doclist.saveDoc({ + path: "./lib/ace/mode/" + modeEl.value + "_highlight_rules.js", + session: editor1.session + }, function(err) { + handleSaveResult(err, editor1); + }); +}; +editor1.commands.bindKey({ + win: "Ctrl-S", mac: "Cmd-s" +}, editor1.saveButton.onclick); +editor2.saveButton.onclick = function() { + doclist.saveDoc(docEl.value, function(err) { + handleSaveResult(err, editor2); + }); +}; +editor2.commands.bindKey({ + win: "Ctrl-S", mac: "Cmd-s" +}, editor2.saveButton.onclick); +function updateSaveButtonState(e, editor){ + editor.saveButton.disabled = editor.session.getUndoManager().isClean(); +} +editor1.on("input", updateSaveButtonState); +editor2.on("input", updateSaveButtonState); + +function handleSaveResult(err, editor) { + if (err) { + return log( + "Write access to this file is disabled.\n"+ + "To enable saving your changes to disk, clone the Ace repository\n"+ + "and run the included web server with the --allow-write option\n"+ + "`node static.js --allow-write` or `static.py --puttable=*`" + ); } + editor.session.getUndoManager().markClean(); + updateSaveButtonState(null, editor); } document.getElementById("perfTest").onclick = function() {