From 8232126684bb1b1af0e139bebc8e8cc86d63fa73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Tue, 1 Sep 2015 16:03:57 +0200 Subject: [PATCH 01/25] WIP --- src/octoprint/static/js/app/client.js | 79 +++++++++++++++++++ src/octoprint/static/js/app/client/files.js | 21 +++++ .../static/js/app/client/octoprint.js | 65 +++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 src/octoprint/static/js/app/client.js create mode 100644 src/octoprint/static/js/app/client/files.js create mode 100644 src/octoprint/static/js/app/client/octoprint.js diff --git a/src/octoprint/static/js/app/client.js b/src/octoprint/static/js/app/client.js new file mode 100644 index 00000000..803635af --- /dev/null +++ b/src/octoprint/static/js/app/client.js @@ -0,0 +1,79 @@ +var OctoPrint = (function($, _, SockJS) { + var self = { + options: { + socketReconnectTimeouts: [0, 1, 1, 2, 3, 5, 8, 13, 20, 40, 100], + socketDebug: false, + socketNormalClose: 1000 + } + }; + + var _socket = undefined; + var _socketAddress = undefined; + var _socketReconnecting = false; + var _socketReconnectTrial = 0; + var _socketIgnoreReconnects = 1; + + function callCallback(callback, arguments) { + if (!_.isFunction(self.options[callback])) { + throw Error("No such callback: " + callback); + } + + self.options[callback].bind(arguments); + } + + function connect(socketAddress) { + var address = socketAddress || _socketAddress; + if (address == undefined) { + return; + } + + var socketOptions = { + debug: options.socketDebug || false + }; + + if (_socket != undefined) { + self._socket.close(); + delete self._socket; + } + + _socketAddress = address; + _socket = new SockJS(address, undefined, socketOptions); + _socket.onopen = onSocketOpen; + _socket.onclose = onSocketClose; + _socket.onmessage = onSocketMessage; + } + + function onSocketOpen() { + _socketReconnecting = false; + _socketReconnectTrial = 0; + } + + function onSocketClose(error) { + if (error.code == options.socketNormalClose) { + return; + } + + if (_socketReconnectTrial >= _socketIgnoreReconnects) { + if (options.onAttemptingReconnect) { + options.onAttemptingReconnect(_socketReconnectTrial); + } + } + + if (_socketReconnectTrial < options.socketReconnectTimeouts.length) { + var timeout = options.socketReconnectTimeouts[_socketReconnectTrial]; + log.info("Reconnect trial #" + self._autoReconnectTrial + ", waiting " + timeout + "s"); + setTimeout(connect, timeout * 1000); + _socketReconnectTrial++; + } else { + if (options.onReconnectFailed) { + options.onReconnectFailed(); + } + } + } + + function onSocketMessage(data) { + } + + return self; + +}(jQuery, _, SockJS)); diff --git a/src/octoprint/static/js/app/client/files.js b/src/octoprint/static/js/app/client/files.js new file mode 100644 index 00000000..39c5384a --- /dev/null +++ b/src/octoprint/static/js/app/client/files.js @@ -0,0 +1,21 @@ +OctoPrint.files = (function($, _) { + var self = {}; + + self.get = function(opts) { + var url = "api/files"; + var origin = opts.origin || ""; + + if (origin && _.contains(["local", "sdcard"], origin)) { + url += origin + "/" + } + + OctoPrint.get_json({ + url: url, + success: opts.success, + error: opts.error, + complete: opts.complete + }) + }; + + return self; +})($, _); diff --git a/src/octoprint/static/js/app/client/octoprint.js b/src/octoprint/static/js/app/client/octoprint.js new file mode 100644 index 00000000..362c4910 --- /dev/null +++ b/src/octoprint/static/js/app/client/octoprint.js @@ -0,0 +1,65 @@ +var OctoPrint = (function($) { + var self = {}; + + self.options = { + "baseurl": undefined, + "apikey": undefined + }; + + self.ajax = function(opts) { + var url = self.options.baseurl + opts.url; + var headers = $.extend({}, opts.headers || {}); + headers["X-Api-Key"] = self.options.apikey; + + var params = $.extend({}, opts); + params.url = url; + + $.ajax(params); + }; + + self.get = function(opts) { + var params = $.extend({}, opts); + params.type = "GET"; + + self.ajax(params); + }; + + self.post = function(opts) { + var headers = $.extend({}, opts.headers || {}); + headers["Cache-Control"] = "no-cache"; + + var params = $.extend({}, opts); + params.type = "POST"; + params.data = JSON.stringify(data); + params.headers = headers; + + self.ajax(params); + }; + + self.delete = function(opts) { + var params = $.extend({}, opts); + params.type = "DELETE"; + + self.ajax(params); + }; + + self.get_json = function(opts) { + var params = $.extend({}, opts); + params.dataType = "json"; + + self.get(params); + }; + + self.post_json = function(opts) { + var data = opts.data || {}; + + var params = $.extend({}, opts); + params.contentType = "application/json; charset=UTF-8"; + params.dataType = "json"; + params.data = JSON.stringify(data); + + self.post(params); + }; + + return self; +})($); From 5f8c3d967c980677d6b2ad5ef2a7434346fdd3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Tue, 22 Sep 2015 18:33:27 +0200 Subject: [PATCH 02/25] Added files and connection API and socket library --- .../static/js/app/client/connection.js | 41 ++++++ src/octoprint/static/js/app/client/files.js | 94 ++++++++++++-- .../static/js/app/client/octoprint.js | 59 +++++---- src/octoprint/static/js/app/client/socket.js | 119 ++++++++++++++++++ 4 files changed, 278 insertions(+), 35 deletions(-) create mode 100644 src/octoprint/static/js/app/client/connection.js create mode 100644 src/octoprint/static/js/app/client/socket.js diff --git a/src/octoprint/static/js/app/client/connection.js b/src/octoprint/static/js/app/client/connection.js new file mode 100644 index 00000000..7179b727 --- /dev/null +++ b/src/octoprint/static/js/app/client/connection.js @@ -0,0 +1,41 @@ +OctoPrint.connection = (function() { + var self = {}; + + self.getSettings = function(opts) { + opts = opts || {}; + + var params = $.extend({}, opts); + params.url = "api/connection"; + + return OctoPrint.getJson(params); + }; + + self.connect = function(data, opts) { + data = data || {}; + + return self.issueCommand("connect", data, opts); + }; + + self.disconnect = function(opts) { + return self.issueCommand("disconnect", {}, opts); + }; + + self.fakeAck = function(opts) { + return self.issueCommand("fake_ack", {}, opts); + }; + + self.issueCommand = function(command, data, opts) { + opts = opts || {}; + data = data || {}; + + var payload = $.extend({}, data); + payload.command = command; + + var params = $.extend({}, opts); + params.url = "api/connection"; + + return OctoPrint.postJson(payload, params); + }; + + return self; +})($, _); diff --git a/src/octoprint/static/js/app/client/files.js b/src/octoprint/static/js/app/client/files.js index 39c5384a..7fbe4788 100644 --- a/src/octoprint/static/js/app/client/files.js +++ b/src/octoprint/static/js/app/client/files.js @@ -1,21 +1,89 @@ OctoPrint.files = (function($, _) { - var self = {}; + var exports = {}; - self.get = function(opts) { - var url = "api/files"; - var origin = opts.origin || ""; + exports.get = function(opts) { + opts = opts || {}; - if (origin && _.contains(["local", "sdcard"], origin)) { - url += origin + "/" + var path = "api/files"; + var location = opts.location || ""; + + if (location && _.contains(["local", "sdcard"], location)) { + path += "/" + location; } - OctoPrint.get_json({ - url: url, - success: opts.success, - error: opts.error, - complete: opts.complete - }) + var params = _.extend({}, opts); + params.url = path; + + return OctoPrint.getJson(params); }; - return self; + exports.listAll = function(opts) { + opts = opts || {}; + + if (opts.location) { + opts.location = undefined; + } + + return exports.get(opts); + }; + + exports.listAllForLocation = function(location, opts) { + opts = opts || {}; + opts.location = location; + + return exports.get(opts); + }; + + exports.getInfoForFile = function(location, filename, opts) { + opts = opts || {}; + + var params = $.extend({}, opts); + params.url = exports.resourceForFile(location, filename); + + return OctoPrint.getJson(params); + }; + + exports.selectFile = function(location, filename, print, opts) { + print = print || false; + + var data = { + print: print + }; + + return exports.issueFileCommand(location, filename, "select", data, opts); + }; + + exports.sliceFile = function(location, filename, parameters, opts) { + parameters = parameters || {}; + + return exports.issueFileCommand(location, filename, "slice", parameters, opts); + }; + + exports.issueFileCommand = function(location, filename, command, data, opts) { + opts = opts || {}; + data = data || {}; + + var payload = $.extend({}, data); + payload.command = command; + + var params = $.extend({}, opts); + params.url = exports.resourceForFile(location, filename); + + return OctoPrint.postJson(payload, params); + }; + + exports.deleteFile = function(location, filename, opts) { + opts = opts || {}; + + var params = $.extend({}, opts); + params.url = exports.resourceForFile(location, filename); + + return OctoPrint.delete(opts); + }; + + exports.resourceForFile = function(location, filename) { + return "api/files/" + location + "/" + filename; + }; + + return exports; })($, _); diff --git a/src/octoprint/static/js/app/client/octoprint.js b/src/octoprint/static/js/app/client/octoprint.js index 362c4910..d2432308 100644 --- a/src/octoprint/static/js/app/client/octoprint.js +++ b/src/octoprint/static/js/app/client/octoprint.js @@ -1,65 +1,80 @@ -var OctoPrint = (function($) { - var self = {}; +var OctoPrint = (function($, _) { + var exports = {}; - self.options = { + exports.options = { "baseurl": undefined, "apikey": undefined }; - self.ajax = function(opts) { - var url = self.options.baseurl + opts.url; + exports.ajax = function(opts) { + opts = opts || {}; + + var url = exports.options.baseurl; + if (!_.endsWith(url, "/")) { + url = url + "/"; + } + url += opts.url; + var headers = $.extend({}, opts.headers || {}); - headers["X-Api-Key"] = self.options.apikey; + headers["X-Api-Key"] = exports.options.apikey; var params = $.extend({}, opts); params.url = url; + params.headers = headers; - $.ajax(params); + return $.ajax(params); }; - self.get = function(opts) { + exports.get = function(opts) { + opts = opts || {}; + var params = $.extend({}, opts); params.type = "GET"; - self.ajax(params); + return exports.ajax(params); }; - self.post = function(opts) { + exports.post = function(data, opts) { + opts = opts || {}; + var headers = $.extend({}, opts.headers || {}); headers["Cache-Control"] = "no-cache"; var params = $.extend({}, opts); params.type = "POST"; - params.data = JSON.stringify(data); + params.data = data; params.headers = headers; - self.ajax(params); + return exports.ajax(params); }; - self.delete = function(opts) { + exports.delete = function(opts) { + opts = opts || {}; + var params = $.extend({}, opts); params.type = "DELETE"; - self.ajax(params); + return exports.ajax(params); }; - self.get_json = function(opts) { + exports.getJson = function(opts) { + opts = opts || {}; + var params = $.extend({}, opts); params.dataType = "json"; - self.get(params); + return exports.get(params); }; - self.post_json = function(opts) { - var data = opts.data || {}; + exports.postJson = function(data, opts) { + opts = opts || {}; var params = $.extend({}, opts); params.contentType = "application/json; charset=UTF-8"; params.dataType = "json"; - params.data = JSON.stringify(data); - self.post(params); + return exports.post(JSON.stringify(data), params); }; - return self; -})($); + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/socket.js b/src/octoprint/static/js/app/client/socket.js new file mode 100644 index 00000000..3156fa86 --- /dev/null +++ b/src/octoprint/static/js/app/client/socket.js @@ -0,0 +1,119 @@ +OctoPrint.socket = (function($, _, SockJS) { + var exports = {}; + + exports.options = { + timeouts: [0, 1, 1, 2, 3, 5, 8, 13, 20, 40, 100] + }; + + var normalClose = 1000; + + var socket = undefined; + var reconnecting = false; + var reconnectTrial = 0; + + var onOpen = function() { + reconnecting = false; + reconnectTrial = 0; + }; + + var onClose = function(e) { + if (e.code == normalClose) { + return; + } + + if (exports.onReconnectAttempt(reconnectTrial)) { + return; + } + + if (reconnectTrial < exports.options.timeouts.length) { + var timeout = exports.options.timeouts[reconnectTrial]; + setTimeout(exports.reconnect, timeout * 1000); + reconnectTrial++; + } else { + exports.onReconnectFailed(); + } + }; + + var onMessage = function(msg) { + for (var prop in msg.data) { + if (!msg.data.hasOwnProperty(prop)) { + continue; + } + + var data = msg.data[prop]; + + switch (prop) { + case "connected": { + exports.onConnected(data); + break; + } + case "history": { + exports.onHistoryData(data); + break; + } + case "current": { + exports.onCurrentData(data); + break; + } + case "event": { + var event = data["type"]; + var payload = data["payload"]; + exports.onEvent(event, payload); + break; + } + case "plugin": { + exports.onPluginMessage(data.plugin, data.data); + break; + } + case "timelapse": { + exports.onTimelapseSettings(data); + break; + } + case "slicingProgress": { + exports.onSlicingProgress(data.slicer, data.model_path, data.machinecode_path, data.progress); + break; + } + } + } + }; + + exports.connect = function(opts) { + opts = opts || {}; + + exports.disconnect(); + + var url = OctoPrint.options.baseurl; + if (!_.endsWith(url, "/")) { + url += "/"; + } + + socket = new SockJS(url + "sockjs", undefined, opts); + socket.onopen = onOpen; + socket.onclose = onClose; + socket.onmessage = onMessage; + }; + + exports.reconnect = function() { + exports.disconnect(); + socket = undefined; + exports.connect(); + }; + + exports.disconnect = function() { + if (socket != undefined) { + socket.close(); + } + }; + + exports.onConnected = function(data) {}; + exports.onCurrentData = function(data) {}; + exports.onHistoryData = function(data) {}; + exports.onEvent = function(event, data) {}; + exports.onPluginMessage = function(plugin, message) {}; + exports.onTimelapseSettings = function(data) {}; + exports.onSlicingProgress = function(slicer, modelPath, machinecodePath, progress) {}; + exports.onReconnectAttempt = function(trial) {}; + exports.onReconnectFailed = function() {}; + + return exports; +})($, _, SockJS); From 1678951d849853ae7d0176f79f6a880cb857c73d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Fri, 25 Sep 2015 13:52:31 +0200 Subject: [PATCH 03/25] Client library should now cover all APIs TODO: Testing & Debugging --- src/octoprint/static/js/app/client/browser.js | 22 ++ .../static/js/app/client/connection.js | 40 +-- src/octoprint/static/js/app/client/control.js | 44 +++ src/octoprint/static/js/app/client/files.js | 101 +++---- src/octoprint/static/js/app/client/job.js | 31 +++ .../static/js/app/client/languages.js | 20 ++ src/octoprint/static/js/app/client/logs.js | 21 ++ .../static/js/app/client/octoprint.js | 251 +++++++++++++++--- src/octoprint/static/js/app/client/printer.js | 197 ++++++++++++++ .../static/js/app/client/printerprofiles.js | 37 +++ .../static/js/app/client/settings.js | 16 ++ src/octoprint/static/js/app/client/slicing.js | 38 +++ src/octoprint/static/js/app/client/socket.js | 75 +++--- .../static/js/app/client/timelapse.js | 50 ++++ src/octoprint/static/js/app/client/users.js | 74 ++++++ src/octoprint/static/js/app/client/util.js | 11 + src/octoprint/static/js/app/client/wizard.js | 15 ++ 17 files changed, 867 insertions(+), 176 deletions(-) create mode 100644 src/octoprint/static/js/app/client/browser.js create mode 100644 src/octoprint/static/js/app/client/control.js create mode 100644 src/octoprint/static/js/app/client/job.js create mode 100644 src/octoprint/static/js/app/client/languages.js create mode 100644 src/octoprint/static/js/app/client/logs.js create mode 100644 src/octoprint/static/js/app/client/printer.js create mode 100644 src/octoprint/static/js/app/client/printerprofiles.js create mode 100644 src/octoprint/static/js/app/client/settings.js create mode 100644 src/octoprint/static/js/app/client/slicing.js create mode 100644 src/octoprint/static/js/app/client/timelapse.js create mode 100644 src/octoprint/static/js/app/client/users.js create mode 100644 src/octoprint/static/js/app/client/util.js create mode 100644 src/octoprint/static/js/app/client/wizard.js diff --git a/src/octoprint/static/js/app/client/browser.js b/src/octoprint/static/js/app/client/browser.js new file mode 100644 index 00000000..bb7b8c5a --- /dev/null +++ b/src/octoprint/static/js/app/client/browser.js @@ -0,0 +1,22 @@ +OctoPrint.browser = (function($, _) { + var exports = {}; + + exports.login = function(username, password, remember, opts) { + var data = { + user: username, + pass: password, + remember: !!remember + }; + return OctoPrint.postJson("api/login", data, opts); + }; + + exports.passiveLogin = function(opts) { + return OctoPrint.postJson("api/login", {passive: true}, opts); + }; + + exports.logout = function(opts) { + return OctoPrint.postJson("api/logout", {}, opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/connection.js b/src/octoprint/static/js/app/client/connection.js index 7179b727..197c1c2e 100644 --- a/src/octoprint/static/js/app/client/connection.js +++ b/src/octoprint/static/js/app/client/connection.js @@ -1,41 +1,25 @@ OctoPrint.connection = (function() { - var self = {}; + var exports = {}; - self.getSettings = function(opts) { - opts = opts || {}; - - var params = $.extend({}, opts); - params.url = "api/connection"; - - return OctoPrint.getJson(params); + exports.getSettings = function(opts) { + return OctoPrint.get("api/connection", opts); }; - self.connect = function(data, opts) { - data = data || {}; - - return self.issueCommand("connect", data, opts); + exports.connect = function(data, opts) { + return exports.issueCommand("connect", data || {}, opts); }; - self.disconnect = function(opts) { - return self.issueCommand("disconnect", {}, opts); + exports.disconnect = function(opts) { + return exports.issueCommand("disconnect", {}, opts); }; - self.fakeAck = function(opts) { - return self.issueCommand("fake_ack", {}, opts); + exports.fakeAck = function(opts) { + return exports.issueCommand("fake_ack", {}, opts); }; - self.issueCommand = function(command, data, opts) { - opts = opts || {}; - data = data || {}; - - var payload = $.extend({}, data); - payload.command = command; - - var params = $.extend({}, opts); - params.url = "api/connection"; - - return OctoPrint.postJson(payload, params); + exports.issueCommand = function(command, data, opts) { + return OctoPrint.issueCommand("api/connection", command, data, opts); }; - return self; + return exports; })($, _); diff --git a/src/octoprint/static/js/app/client/control.js b/src/octoprint/static/js/app/client/control.js new file mode 100644 index 00000000..4b9e9872 --- /dev/null +++ b/src/octoprint/static/js/app/client/control.js @@ -0,0 +1,44 @@ +OctoPrint.control = (function($, _) { + var exports = {}; + + var customUrl = "api/printer/command/custom"; + var commandUrl = "api/printer/command"; + + exports.getCustomControls = function(opts) { + return OctoPrint.get(customUrl, opts); + }; + + exports.sendGcode = function(commands, opts) { + commands = commands || []; + + if (typeof commands === "string") { + commands = [commands]; + } + + return OctoPrint.postJson(commandUrl, {commands: commands}, opts); + }; + + exports.sendGcodeWithParameters = function(commands, parameters, opts) { + commands = commands || []; + parameters = parameters || {}; + + if (typeof commands === "string") { + commands = [commands]; + } + + return OctoPrint.postJson(commandUrl, {commands: commands, parameters: parameters}, opts); + }; + + exports.sendGcodeScript = function(script, context, opts) { + script = script || ""; + context = context || {}; + + return OctoPrint.postJson(commandUrl, {script: script, context: context}, opts); + }; + + exports.executeSystemCommand = function(action, opts) { + return OctoPrint.postJson("api/system", {action: action}, opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/files.js b/src/octoprint/static/js/app/client/files.js index 7fbe4788..bb0d6c0f 100644 --- a/src/octoprint/static/js/app/client/files.js +++ b/src/octoprint/static/js/app/client/files.js @@ -1,88 +1,69 @@ OctoPrint.files = (function($, _) { var exports = {}; - exports.get = function(opts) { - opts = opts || {}; - - var path = "api/files"; - var location = opts.location || ""; - - if (location && _.contains(["local", "sdcard"], location)) { - path += "/" + location; - } - - var params = _.extend({}, opts); - params.url = path; - - return OctoPrint.getJson(params); + var resourceForFile = function(location, filename) { + return "api/files/" + location + "/" + filename; }; - exports.listAll = function(opts) { - opts = opts || {}; - - if (opts.location) { - opts.location = undefined; - } - - return exports.get(opts); + var issueFileCommand = function(location, filename, command, data, opts) { + var url = resourceForFile(location, filename); + return OctoPrint.issueCommand(url, command, data, opts); }; - exports.listAllForLocation = function(location, opts) { - opts = opts || {}; - opts.location = location; - - return exports.get(opts); + exports.list = function(opts) { + return OctoPrint.get("api/files", opts); }; - exports.getInfoForFile = function(location, filename, opts) { - opts = opts || {}; - - var params = $.extend({}, opts); - params.url = exports.resourceForFile(location, filename); - - return OctoPrint.getJson(params); + exports.listForLocation = function(location, opts) { + return OctoPrint.get("api/files/" + location, opts); }; - exports.selectFile = function(location, filename, print, opts) { + exports.get = function(location, filename, opts) { + return OctoPrint.get(resourceForFile(location, filename), opts); + }; + + exports.select = function(location, filename, print, opts) { print = print || false; var data = { print: print }; - return exports.issueFileCommand(location, filename, "select", data, opts); + return issueFileCommand(location, filename, "select", data, opts); }; - exports.sliceFile = function(location, filename, parameters, opts) { - parameters = parameters || {}; - - return exports.issueFileCommand(location, filename, "slice", parameters, opts); + exports.slice = function(location, filename, parameters, opts) { + return issueFileCommand(location, filename, "slice", + parameters || {}, opts); }; - exports.issueFileCommand = function(location, filename, command, data, opts) { - opts = opts || {}; + exports.delete = function(location, filename, opts) { + return OctoPrint.delete(resourceForFile(location, filename), opts); + }; + + exports.upload = function(location, file, data) { data = data || {}; - var payload = $.extend({}, data); - payload.command = command; - - var params = $.extend({}, opts); - params.url = exports.resourceForFile(location, filename); - - return OctoPrint.postJson(payload, params); + var filename = data.filename || undefined; + return OctoPrint.upload("api/files/" + location, file, filename, data); }; - exports.deleteFile = function(location, filename, opts) { - opts = opts || {}; - - var params = $.extend({}, opts); - params.url = exports.resourceForFile(location, filename); - - return OctoPrint.delete(opts); - }; - - exports.resourceForFile = function(location, filename) { - return "api/files/" + location + "/" + filename; + exports.download = function(location, filename, opts) { + var deferred = $.Deferred(); + exports.get(location, filename, opts) + .done(function(response) { + OctoPrint.download(response.refs.download, opts) + .done(function() { + deferred.resolve.apply(null, arguments); + }) + .fail(function() { + deferred.reject.apply(null, arguments); + }); + }) + .fail(function() { + deferred.reject.apply(null, arguments); + }); + return deferred.promise(); }; return exports; diff --git a/src/octoprint/static/js/app/client/job.js b/src/octoprint/static/js/app/client/job.js new file mode 100644 index 00000000..84497dec --- /dev/null +++ b/src/octoprint/static/js/app/client/job.js @@ -0,0 +1,31 @@ +OctoPrint.job = (function($, _) { + var exports = {}; + + var url = "api/job"; + + var issueCommand = function(command, data, opts) { + return OctoPrint.issueCommand(url, command, data, opts); + }; + + exports.get = function(opts) { + return OctoPrint.get(url, opts); + }; + + exports.start = function(opts) { + return issueCommand("start", {}, opts); + }; + + exports.restart = function(opts) { + return issueCommand("restart", {}, opts); + }; + + exports.pause = function(opts) { + return issueCommand("pause", {}, opts); + }; + + exports.cancel = function(opts) { + return issueCommand("cancel", {}, opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/languages.js b/src/octoprint/static/js/app/client/languages.js new file mode 100644 index 00000000..d9bc3ac6 --- /dev/null +++ b/src/octoprint/static/js/app/client/languages.js @@ -0,0 +1,20 @@ +OctoPrint.languages = (function($, _) { + var exports = {}; + + var url = "api/languages"; + + exports.list = function(opt) { + return OctoPrint.get(url, opt); + }; + + exports.upload = function(file) { + return OctoPrint.upload(url, file); + }; + + exports.delete = function(locale, pack, opts) { + var packUrl = url + "/" + locale + "/" + pack; + return OctoPrint.delete(packUrl, opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/logs.js b/src/octoprint/static/js/app/client/logs.js new file mode 100644 index 00000000..609ca246 --- /dev/null +++ b/src/octoprint/static/js/app/client/logs.js @@ -0,0 +1,21 @@ +OctoPrint.logs = (function($, _) { + var exports = {}; + + var url = "api/logs"; + + exports.list = function(opts) { + return OctoPrint.get(url, opts); + }; + + exports.delete = function(file, opts) { + var fileUrl = url + "/" + file; + return OctoPrint.delete(fileUrl, opts); + }; + + exports.download = function(file, opts) { + var fileUrl = url + "/" + file; + return OctoPrint.download(fileUrl, opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/octoprint.js b/src/octoprint/static/js/app/client/octoprint.js index d2432308..b2ce0346 100644 --- a/src/octoprint/static/js/app/client/octoprint.js +++ b/src/octoprint/static/js/app/client/octoprint.js @@ -1,80 +1,243 @@ var OctoPrint = (function($, _) { var exports = {}; + var noCache = function(opts) { + opts = opts || {}; + + var params = $.extend({}, opts); + params.headers = $.extend({}, params.headers || {}); + params.headers["Cache-Control"] = "no-cache"; + + return params; + }; + + var contentTypeJson = function(opts) { + opts = opts || {}; + + var params = $.extend({}, opts); + params.contentType = "application/json; charset=UTF-8"; + + return params; + }; + exports.options = { "baseurl": undefined, "apikey": undefined }; - exports.ajax = function(opts) { - opts = opts || {}; + exports.plugins = {}; + exports.getBaseUrl = function() { var url = exports.options.baseurl; if (!_.endsWith(url, "/")) { url = url + "/"; } - url += opts.url; + return url; + }; - var headers = $.extend({}, opts.headers || {}); + exports.getRequestHeaders = function(additional) { + additional = additional || {}; + + var headers = $.extend({}, additional); headers["X-Api-Key"] = exports.options.apikey; + return headers; + }; + + exports.ajax = function(method, url, opts) { + opts = opts || {}; + + method = opts.method || method || "GET"; + url = opts.url || url || ""; + + var urlToCall = url; + if (!_.startsWith(url, "http://") && !_.startsWith(url, "https://")) { + urlToCall = exports.getBaseUrl() + url; + } + + var headers = exports.getRequestHeaders(opts.headers); + var params = $.extend({}, opts); - params.url = url; + params.type = method; params.headers = headers; + params.dataType = params.dataType || "json"; - return $.ajax(params); + return $.ajax(urlToCall, params); }; - exports.get = function(opts) { + exports.ajaxWithData = function(method, url, data, opts) { opts = opts || {}; var params = $.extend({}, opts); - params.type = "GET"; - - return exports.ajax(params); - }; - - exports.post = function(data, opts) { - opts = opts || {}; - - var headers = $.extend({}, opts.headers || {}); - headers["Cache-Control"] = "no-cache"; - - var params = $.extend({}, opts); - params.type = "POST"; params.data = data; - params.headers = headers; - return exports.ajax(params); + return exports.ajax(method, url, params); }; - exports.delete = function(opts) { - opts = opts || {}; - - var params = $.extend({}, opts); - params.type = "DELETE"; - - return exports.ajax(params); + exports.get = function(url, opts) { + return exports.ajax("GET", url, opts); }; - exports.getJson = function(opts) { - opts = opts || {}; - - var params = $.extend({}, opts); - params.dataType = "json"; - - return exports.get(params); + exports.post = function(url, data, opts) { + return exports.ajaxWithData("POST", url, data, noCache(opts)); }; - exports.postJson = function(data, opts) { - opts = opts || {}; - - var params = $.extend({}, opts); - params.contentType = "application/json; charset=UTF-8"; - params.dataType = "json"; - - return exports.post(JSON.stringify(data), params); + exports.postJson = function(url, data, opts) { + return exports.post(url, JSON.stringify(data), contentTypeJson(opts)); }; + exports.put = function(url, data, opts) { + return exports.ajaxWithData("PUT", url, data, noCache(opts)); + }; + + exports.putJson = function(url, data, opts) { + return exports.put(url, data, contentTypeJson(opts)); + }; + + exports.patch = function(url, data, opts) { + return exports.ajaxWithData("PATCH", url, data, noCache(opts)); + }; + + exports.patchJson = function(url, data, opts) { + return exports.patch(url, JSON.stringify(data), contentTypeJson(opts)); + }; + + exports.delete = function(url, opts) { + return exports.ajax("DELETE", url, opts); + }; + + exports.download = function(url, opts) { + var params = $.extend({}, opts || {}); + params.dataType = "text"; + return exports.get(url, params); + }; + + exports.upload = function(url, file, filename, additional) { + additional = additional || {}; + + var fileData; + if (file instanceof jQuery) { + fileData = file[0].files[0]; + } else if (typeof file == "string") { + fileData = $(file)[0].files[0]; + } else { + fileData = file; + } + + filename = filename || fileData.name; + + var form = new FormData(); + form.append("file", fileData, filename); + + _.each(additional, function(value, key) { + form.append(key, value); + }); + + var deferred = $.Deferred(); + + var request = new XMLHttpRequest(); + request.onreadystatechange = function() { + if (request.readyState == 4) { + deferred.notify({loaded: filesize, total: filesize}); + + var success = request.status >= 200 && request.status < 300 + || request.status === 304; + var error, json, statusText; + + try { + json = JSON.parse(request.response); + statusText = "success"; + } catch (e) { + success = false; + error = e; + statusText = "parsererror"; + } + + if (success) { + deferred.resolve([json, statusText, request]); + } else { + if (!statusText) { + statusText = request.statusText; + } + deferred.reject([request, statusText, error]); + } + } + }; + request.ontimeout = function() { + deferred.reject([request, "timeout", "Timeout"]); + }; + request.upload.addEventListener("loadstart", function(e) { + deferred.notify({loaded: e.loaded, total: e.total}); + }); + request.upload.addEventListener("progress", function(e) { + deferred.notify({loaded: e.loaded, total: e.total}); + }); + request.upload.addEventListener("loadend", function(e) { + deferred.notify({loaded: e.loaded, total: e.total}); + }); + + var headers = OctoPrint.getRequestHeaders(); + + request.open("POST", OctoPrint.getBaseUrl() + url); + _.each(headers, function(value, key) { + request.setRequestHeader(key, value); + }); + request.send(form); + + return deferred.promise(); + }; + + exports.issueCommand = function(url, command, payload, opts) { + payload = payload || {}; + + var data = $.extend({}, payload); + data.command = command; + + return exports.postJson(url, data, opts); + }; + + exports.getSimpleApiUrl = function(plugin) { + return "api/plugin/" + plugin; + }; + + exports.simpleApiGet = function(plugin, opts) { + return OctoPrint.get(exports.getSimpleApiUrl(plugin), opts); + }; + + exports.simpleApiCommand = function(plugin, command, payload, opts) { + return OctoPrint.issueCommand(exports.getSimpleApiUrl(plugin), command, payload, opts); + }; + + exports.getBlueprintUrl = function(plugin) { + return "plugin/" + plugin + "/"; + }; + + exports.createRejectedDeferred = function() { + var deferred = $.Deferred(); + deferred.reject(arguments); + return deferred; + }; + + exports.createCustomException = function(name) { + var constructor; + + if (_.isFunction(name)) { + constructor = name; + } else { + constructor = function(message) { + this.name = name; + this.message = message; + this.stack = (new Error()).stack; + }; + } + + constructor.prototype = Object.create(Error.prototype); + constructor.prototype.constructor = constructor; + + return constructor; + }; + + exports.InvalidArgumentError = exports.createCustomException("InvalidArgumentError"); + return exports; })($, _); diff --git a/src/octoprint/static/js/app/client/printer.js b/src/octoprint/static/js/app/client/printer.js new file mode 100644 index 00000000..96217dde --- /dev/null +++ b/src/octoprint/static/js/app/client/printer.js @@ -0,0 +1,197 @@ +OctoPrint.printer = (function($, _) { + var exports = {}; + + var issuePrintheadCommand = function(command, payload, opts) { + return OctoPrint.issueCommand("api/printer/printhead", command, payload, opts); + }; + + var issueToolCommand = function(command, payload, opts) { + return OctoPrint.issueCommand("api/printer/tool", command, payload, opts); + }; + + var issueBedCommand = function(command, payload, opts) { + return OctoPrint.issueCommand("api/printer/bed", command, payload, opts); + }; + + var issueSdCommand = function(command, payload, opts) { + return OctoPrint.issueCommand("api/printer/sd", command, payload, opts); + }; + + exports.getFullState = function(data, opts) { + data = data || {}; + + var history = data.history || undefined; + var limit = data.limit || undefined; + var exclude = data.exclude || undefined; + + var url = "api/printer"; + if (history || exclude) { + url += "?"; + if (history) { + url += "history=true&"; + if (limit) { + url += "limit=" + limit + "&"; + } + } + + if (exclude) { + url += "exclude=" + exclude.join(",") + "&"; + } + } + + return OctoPrint.get(url, opts); + }; + + exports.getToolState = function(data, opts) { + data = data || {}; + + var history = data.history || undefined; + var limit = data.limit || undefined; + + var url = "api/printer/tool"; + if (history) { + url += "?history=true"; + if (limit) { + url += "&limit=" + limit; + } + } + + return OctoPrint.get(url, opts); + }; + + exports.getBedState = function(data, opts) { + data = data || {}; + + var history = data.history || undefined; + var limit = data.limit || undefined; + + var url = "api/printer/bed"; + if (history) { + url += "?history=true"; + if (limit) { + url += "&limit=" + limit; + } + } + + return OctoPrint.get(url, opts); + }; + + exports.getSdState = function(opts) { + return OctoPrint.get("api/printer/sd", opts); + }; + + exports.jog = function(data, opts) { + data = data || {}; + + var payload = {}; + if (data.x) payload.x = data.x; + if (data.y) payload.y = data.y; + if (data.z) payload.z = data.z; + + return issuePrintheadCommand("jog", payload, opts); + }; + + exports.home = function(axes, opts) { + axes = axes || []; + + var payload = { + axes: axes + }; + + return issuePrintheadCommand("home", payload, opts); + }; + + exports.setFeedrate = function(factor, opts) { + factor = factor || 100; + + var payload = { + factor: factor + }; + + return issuePrintheadCommand("feedrate", payload, opts); + }; + + exports.setToolTargetTemperatures = function(targets, opts) { + targets = targets || {}; + + var payload = { + targets: targets + }; + + return issueToolCommand("target", payload, opts); + }; + + exports.setToolTemperatureOffsets = function(offsets, opts) { + offsets = offsets || {}; + + var payload = { + offsets: offsets + }; + + return issueToolCommand("offset", payload, opts); + }; + + exports.selectTool = function(tool, opts) { + tool = tool || undefined; + + var payload = { + tool: tool + }; + + return issueToolCommand("select", payload, opts); + }; + + exports.extrude = function(amount, opts) { + amount = amount || undefined; + + var payload = { + amount: amount + }; + + return issueToolCommand("extrude", payload, opts); + }; + + exports.setFlowrate = function(factor, opts) { + factor = factor || 100; + + var payload = { + factor: factor + }; + + return issueToolCommand("flowrate", payload, opts); + }; + + exports.setBedTargetTemperature = function(temperature, opts) { + temperature = temperature || 0; + + var payload = { + target: temperature + }; + + return issueBedCommand("target", payload, opts); + }; + + exports.setBedTemperatureOffset = function(offset, opts) { + offset = offset || 0; + + var payload = { + offset: offset + }; + + return issueBedCommand("offset", payload, opts); + }; + + exports.initSd = function(opts) { + return issueSdCommand("init", {}, opts); + }; + + exports.refreshSd = function(opts) { + return issueSdCommand("refresh", {}, opts); + }; + + exports.releaseSd = function(opts) { + return issueSdCommand("release", {}, opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/printerprofiles.js b/src/octoprint/static/js/app/client/printerprofiles.js new file mode 100644 index 00000000..5f4c49c7 --- /dev/null +++ b/src/octoprint/static/js/app/client/printerprofiles.js @@ -0,0 +1,37 @@ +OctoPrint.printerprofiles = (function($, _) { + var exports = {}; + + var url = "api/printerprofiles"; + + exports.get = function(opts) { + return OctoPrint.get(url, opts); + }; + + exports.add = function(profile, additional, opts) { + profile = profile || {}; + additional = additional || {}; + + var data = $.extend({}, additional); + data.profile = profile; + + return OctoPrint.postJson(url, data, opts); + }; + + exports.update = function(id, profile, additional, opts) { + profile = profile || {}; + additional = addtional || {}; + + var data = $.extend({}, additional); + data.profile = profile; + + var profileUrl = url + "/" + id; + return OctoPrint.patchJson(profileUrl, data, opts); + }; + + exports.delete = function(id, opts) { + var profileUrl = url + "/" + id; + return OctoPrint.delete(profileUrl, opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/settings.js b/src/octoprint/static/js/app/client/settings.js new file mode 100644 index 00000000..cf701699 --- /dev/null +++ b/src/octoprint/static/js/app/client/settings.js @@ -0,0 +1,16 @@ +OctoPrint.settings = (function($, _) { + var exports = {}; + + var url = "api/settings"; + + exports.get = function(opts) { + return OctoPrint.get(url, opts); + }; + + exports.save = function(settings, opts) { + settings = settings || {}; + return OctoPrint.postJson(url, settings, opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/slicing.js b/src/octoprint/static/js/app/client/slicing.js new file mode 100644 index 00000000..33c6294f --- /dev/null +++ b/src/octoprint/static/js/app/client/slicing.js @@ -0,0 +1,38 @@ +OctoPrint.slicing = (function($, _) { + var exports = {}; + + var url = "api/slicing"; + + var getProfileUrl = function(slicer, profileId) { + return url + "/" + slicer + "/profiles/" + profileId; + }; + + exports.listAllSlicersAndProfiles = function(opts) { + return OctoPrint.get(url, opts); + }; + + exports.listProfilesForSlicer = function(slicer, opts) { + var slicerUrl = url + "/" + slicer + "/profiles"; + return OctoPrint.get(slicerUrl, opts); + }; + + exports.getProfileForSlicer = function(slicer, profileId, opts) { + return OctoPrint.get(getProfileUrl(slicer, profileId), opts); + }; + + exports.addProfileForSlicer = function(slicer, profileId, profile, opts) { + profile = profile || {}; + return OctoPrint.putJson(getProfileUrl(slicer, profileId), profile, opts); + }; + + exports.updateProfileForSlicer = function(slicer, profileId, profile, opts) { + profile = profile || {}; + return OctoPrint.patchJson(getProfileUrl(slicer, profileId), profile, opts); + }; + + exports.deleteProfileForSlicer = function(slicer, profileId, opts) { + return OctoPrint.delete(getProfileUrl(slicer, profileId), opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/socket.js b/src/octoprint/static/js/app/client/socket.js index 3156fa86..e511d24e 100644 --- a/src/octoprint/static/js/app/client/socket.js +++ b/src/octoprint/static/js/app/client/socket.js @@ -10,6 +10,7 @@ OctoPrint.socket = (function($, _, SockJS) { var socket = undefined; var reconnecting = false; var reconnectTrial = 0; + var registeredHandlers = {}; var onOpen = function() { reconnecting = false; @@ -35,45 +36,30 @@ OctoPrint.socket = (function($, _, SockJS) { }; var onMessage = function(msg) { - for (var prop in msg.data) { - if (!msg.data.hasOwnProperty(prop)) { - continue; - } + _.each(msg.data, function(data, key) { + propagateMessage(key, data); + }); + }; - var data = msg.data[prop]; + var propagateMessage = function(event, data) { + if (!registeredHandlers.hasOwnProperty(event)) { + return; + } - switch (prop) { - case "connected": { - exports.onConnected(data); - break; - } - case "history": { - exports.onHistoryData(data); - break; - } - case "current": { - exports.onCurrentData(data); - break; - } - case "event": { - var event = data["type"]; - var payload = data["payload"]; - exports.onEvent(event, payload); - break; - } - case "plugin": { - exports.onPluginMessage(data.plugin, data.data); - break; - } - case "timelapse": { - exports.onTimelapseSettings(data); - break; - } - case "slicingProgress": { - exports.onSlicingProgress(data.slicer, data.model_path, data.machinecode_path, data.progress); - break; - } - } + var eventObj = {event: event, data: data}; + + var catchAllHandlers = registeredHandlers["*"]; + if (catchAllHandlers && catchAllHandlers.length) { + _.each(catchAllHandlers, function(handler) { + handler({event: eventObj}) + }); + } + + var handlers = registeredHandlers[event]; + if (handlers && handlers.length) { + _.each(handlers, function(handler) { + handler(eventObj); + }); } }; @@ -105,13 +91,14 @@ OctoPrint.socket = (function($, _, SockJS) { } }; - exports.onConnected = function(data) {}; - exports.onCurrentData = function(data) {}; - exports.onHistoryData = function(data) {}; - exports.onEvent = function(event, data) {}; - exports.onPluginMessage = function(plugin, message) {}; - exports.onTimelapseSettings = function(data) {}; - exports.onSlicingProgress = function(slicer, modelPath, machinecodePath, progress) {}; + exports.onMessage = function(message, handler) { + if (!registeredHandlers.hasOwnProperty(message)) { + registeredHandlers[message] = []; + } + registeredHandlers[message].push(handler); + return exports; + }; + exports.onReconnectAttempt = function(trial) {}; exports.onReconnectFailed = function() {}; diff --git a/src/octoprint/static/js/app/client/timelapse.js b/src/octoprint/static/js/app/client/timelapse.js new file mode 100644 index 00000000..21824ca3 --- /dev/null +++ b/src/octoprint/static/js/app/client/timelapse.js @@ -0,0 +1,50 @@ +OctoPrint.timelapse = (function($, _) { + var exports = {}; + + var url = "api/timelapse"; + + exports.get = function(opts) { + return OctoPrint.get(url, opts); + }; + + exports.list = function(opts) { + var deferred = $.Deferred(); + + exports.get(opts) + .done(function(response, status, request) { + deferred.resolve(response.files, status, request); + }) + .fail(function() { + deferred.reject.apply(null, arguments); + }); + + return deferred.promise(); + }; + + exports.download = function(filename, opts) { + return OctoPrint.download(url + "/" + filename, opts); + }; + + exports.delete = function(filename, opts) { + return OctoPrint.delete(url + "/" + filename, opts); + }; + + exports.getConfig = function(opts) { + var deferred = $.Deferred(); + exports.get(opts) + .done(function(response, status, request) { + deferred.resolve(response.config, status, request); + }) + .fail(function() { + deferred.reject.apply(null, arguments); + }); + return deferred.promise(); + }; + + exports.saveConfig = function(config, opts) { + config = config || {}; + return OctoPrint.postJson(url, config, opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/users.js b/src/octoprint/static/js/app/client/users.js new file mode 100644 index 00000000..f5572b33 --- /dev/null +++ b/src/octoprint/static/js/app/client/users.js @@ -0,0 +1,74 @@ +OctoPrint.users = (function($, _) { + var exports = {}; + + var baseUrl = "api/users"; + + var url = function() { + if (arguments.length) { + return baseUrl + "/" + Array.prototype.join.call(arguments, "/"); + } else { + return baseUrl; + } + }; + + exports.list = function(opts) { + return OctoPrint.get(url(), opts); + }; + + exports.add = function(user, opts) { + if (!user.name || !user.password) { + throw new OctoPrint.InvalidArgumentError("Both user's name and password need to be set"); + } + + var data = { + name: user.name, + password: user.password, + active: user.hasOwnProperty("active") ? !!user.active : true, + admin: user.hasOwnProperty("admin") ? !!user.admin : false + }; + + return OctoPrint.postJson(url(), data, opts); + }; + + exports.get = function(name, opts) { + return OctoPrint.get(url(name), opts); + }; + + exports.update = function(name, active, admin, opts) { + var data = { + active: !!active, + admin: !!admin + }; + return OctoPrint.putJson(url(name), data, opts); + }; + + exports.delete = function(name, opts) { + return OctoPrint.delete(url(name), opts); + }; + + exports.changePassword = function(name, password, opts) { + var data = { + password: password + }; + return OctoPrint.putJson(url(name, "password"), data, opts); + }; + + exports.generateApiKey = function(name, opts) { + return OctoPrint.postJson(url(name, "apikey"), opts); + }; + + exports.resetApiKey = function(name, opts) { + return OctoPrint.delete(url(name, "apikey"), opts); + }; + + exports.getSettings = function(name, opts) { + return OctoPrint.get(url(name, "settings"), opts); + }; + + exports.saveSettings = function(name, settings, opts) { + settings = settings || {}; + return OctoPrint.patchJson(url(name, "settings"), settings, opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/util.js b/src/octoprint/static/js/app/client/util.js new file mode 100644 index 00000000..5f22356c --- /dev/null +++ b/src/octoprint/static/js/app/client/util.js @@ -0,0 +1,11 @@ +OctoPrint.util = (function($, _) { + var exports = {}; + + var url = "api/util"; + + exports.test = function(command, data, opts) { + return OctoPrint.issueCommand(url + "/test", command, data, opts); + }; + + return exports; +})($, _); diff --git a/src/octoprint/static/js/app/client/wizard.js b/src/octoprint/static/js/app/client/wizard.js new file mode 100644 index 00000000..70182dba --- /dev/null +++ b/src/octoprint/static/js/app/client/wizard.js @@ -0,0 +1,15 @@ +OctoPrint.wizard = (function($, _) { + var exports = {}; + + var url = "api/setup/wizard"; + + exports.get = function(opts) { + return OctoPrint.get(url, opts); + }; + + exports.finish = function(handled, opts) { + return OctoPrint.postJson(url, {handled: handled || []}, opts); + }; + + return exports; +})($, _); From bbd728c51bad7e24a2adca424030fc3281ac4285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Fri, 25 Sep 2015 13:53:42 +0200 Subject: [PATCH 04/25] Migrated existing javascript application files to use client lib TODO: Testing & Debugging --- .../corewizard/static/js/corewizard.js | 18 +- src/octoprint/plugins/cura/static/js/cura.js | 45 +- .../pluginmanager/static/js/pluginmanager.js | 203 +++++---- .../static/js/softwareupdate.js | 70 +-- src/octoprint/server/__init__.py | 22 + src/octoprint/server/api/__init__.py | 8 +- src/octoprint/server/views.py | 1 - src/octoprint/static/js/app/client.js | 79 ---- src/octoprint/static/js/app/dataupdater.js | 415 ++++++++---------- src/octoprint/static/js/app/main.js | 16 + .../static/js/app/viewmodels/connection.js | 33 +- .../static/js/app/viewmodels/control.js | 121 ++--- .../static/js/app/viewmodels/files.js | 67 ++- .../static/js/app/viewmodels/gcode.js | 14 +- src/octoprint/static/js/app/viewmodels/log.js | 18 +- .../static/js/app/viewmodels/loginstate.js | 41 +- .../static/js/app/viewmodels/navigation.js | 17 +- .../js/app/viewmodels/printerprofiles.js | 70 ++- .../static/js/app/viewmodels/printerstate.js | 30 +- .../static/js/app/viewmodels/settings.js | 103 ++--- .../static/js/app/viewmodels/slicing.js | 32 +- .../static/js/app/viewmodels/temperature.js | 123 +++--- .../static/js/app/viewmodels/terminal.js | 29 +- .../static/js/app/viewmodels/timelapse.js | 39 +- .../static/js/app/viewmodels/users.js | 181 +++----- .../static/js/app/viewmodels/usersettings.js | 25 +- .../static/js/app/viewmodels/wizard.js | 74 ++-- src/octoprint/templates/javascripts.jinja2 | 4 + 28 files changed, 779 insertions(+), 1119 deletions(-) delete mode 100644 src/octoprint/static/js/app/client.js diff --git a/src/octoprint/plugins/corewizard/static/js/corewizard.js b/src/octoprint/plugins/corewizard/static/js/corewizard.js index f909057e..c4b587ed 100644 --- a/src/octoprint/plugins/corewizard/static/js/corewizard.js +++ b/src/octoprint/plugins/corewizard/static/js/corewizard.js @@ -53,26 +53,22 @@ $(function() { }; self._sendData = function(data, callback) { - $.ajax({ - url: BASEURL + "plugin/corewizard/acl", - type: "POST", - dataType: "json", - data: data, - success: function() { + OctoPrint.postJson("plugin/corewizard/acl", data) + .done(function() { self.setup(true); self.decision(data.ac); if (data.ac) { // we now log the user in var user = data.user; var pass = data.pass1; - self.loginStateViewModel.login(user, pass, true, function() { - if (callback) callback(); - }); + self.loginStateViewModel.login(user, pass, true) + .done(function() { + if (callback) callback(); + }); } else { if (callback) callback(); } - } - }); + }); }; self.onWizardTabChange = function(current, next) { diff --git a/src/octoprint/plugins/cura/static/js/cura.js b/src/octoprint/plugins/cura/static/js/cura.js index fb551689..fb8fb62a 100644 --- a/src/octoprint/plugins/cura/static/js/cura.js +++ b/src/octoprint/plugins/cura/static/js/cura.js @@ -70,6 +70,7 @@ $(function() { dataType: "json", maxNumberOfFiles: 1, autoUpload: false, + headers: OctoPrint.getRequestHeaders(), add: function(e, data) { if (data.files.length == 0) { return false; @@ -131,14 +132,11 @@ $(function() { return (item.key == data.key); }); - $.ajax({ - url: data.resource(), - type: "DELETE", - success: function() { + OctoPrint.slicing.deleteProfileForSlicer("cura", data.key, {url: data.resource}) + .done(function() { self.requestData(); self.slicingViewModel.requestData(); - } - }); + }); }; self.makeProfileDefault = function(data) { @@ -156,16 +154,10 @@ $(function() { item.isdefault(true); } - $.ajax({ - url: data.resource(), - type: "PATCH", - dataType: "json", - data: JSON.stringify({default: true}), - contentType: "application/json; charset=UTF-8", - success: function() { + OctoPrint.slicing.updateProfileForSlicer("cura", data.key, {default: true}, {url: data.resource()}) + .done(function() { self.requestData(); - } - }); + }); }; self.showImportProfileDialog = function(makeDefault) { @@ -199,28 +191,13 @@ $(function() { } } - $.ajax({ - url: API_BASEURL + "util/test", - type: "POST", - dataType: "json", - data: JSON.stringify({ - command: "path", - path: enginePath, - check_type: "file", - check_access: "x" - }), - contentType: "application/json; charset=UTF-8", - success: successCallback - }) + OctoPrint.util.test("path", {path: enginePath, check_type: "file", check_access: "x"}) + .done(successCallback); }; self.requestData = function() { - $.ajax({ - url: API_BASEURL + "slicing/cura/profiles", - type: "GET", - dataType: "json", - success: self.fromResponse - }); + OctoPrint.slicing.listProfilesForSlicer("cura") + .done(self.fromResponse); }; self.fromResponse = function(data) { diff --git a/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js b/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js index 7c5265ff..d75c7d24 100644 --- a/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js +++ b/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js @@ -1,4 +1,66 @@ $(function() { + + OctoPrint.plugins.pluginmanager = (function($, _) { + var exports = {}; + + exports.get = function(refresh, opts) { + return OctoPrint.get(OctoPrint.getSimpleApiUrl("pluginmanager") + ((refresh) ? "?refresh_repository=true" : ""), opts); + }; + + exports.getWithRefresh = function(opts) { + return exports.get(true, opts); + }; + + exports.getWithoutRefresh = function(opts) { + return exports.get(false, opts); + }; + + exports.install = function(pluginUrl, dependencyLinks, opts) { + var data = { + url: pluginUrl, + dependency_links: !!dependencyLinks + }; + return OctoPrint.simpleApiCommand(plugin, "install", data, opts); + }; + + exports.reinstall = function(plugin, pluginUrl, dependencyLinks, opts) { + var data = { + url: pluginUrl, + dependency_links: !!dependencyLinks, + reinstall: plugin, + force: true + }; + return OctoPrint.simpleApiCommand(plugin, "install", data, opts); + }; + + exports.uninstall = function(plugin, opts) { + var data = { + plugin: plugin + }; + return OctoPrint.simpleApiCommand(plugin, "uninstall", data, opts); + }; + + exports.enable = function(plugin, opts) { + var data = { + plugin: plugin + }; + return OctoPrint.simpleApiCommand(plugin, "enable", data, opts); + }; + + exports.disable = function(plugin, opts) { + var data = { + plugin: plugin + }; + return OctoPrint.simpleApiCommand(plugin, "disable", data, opts); + }; + + exports.upload = function(file) { + return OctoPrint.upload(OctoPrint.getBlueprintUrl("pluginmanager") + "upload_archive", file); + }; + + return exports; + })($, _); + function PluginManagerViewModel(parameters) { var self = this; @@ -193,12 +255,8 @@ $(function() { return; } - $.ajax({ - url: API_BASEURL + "plugin/pluginmanager" + ((includeRepo) ? "?refresh_repository=true" : ""), - type: "GET", - dataType: "json", - success: self.fromResponse - }); + OctoPrint.plugins.pluginmanager.get(includeRepo) + .done(self.fromResponse); }; self.togglePlugin = function(data) { @@ -212,19 +270,25 @@ $(function() { if (data.key == "pluginmanager") return; - var command = self._getToggleCommand(data); + var onSuccess = self.requestData, + onError = function() { + new PNotify({ + title: gettext("Something went wrong"), + text: gettext("Please consult octoprint.log for details"), + type: "error", + hide: false + }) + }; - var payload = {plugin: data.key}; - self._postCommand(command, payload, function(response) { - self.requestData(); - }, function() { - new PNotify({ - title: gettext("Something went wrong"), - text: gettext("Please consult octoprint.log for details"), - type: "error", - hide: false - }) - }); + if (self._getToggleCommand(data) == "enable") { + OctoPrint.plugins.pluginmanager.enable(data.key) + .done(onSuccess) + .fail(onError); + } else { + OctoPrint.plugins.pluginmanager.disable(data.key) + .done(onSuccess) + .fail(onError); + } }; self.showRepository = function() { @@ -244,11 +308,7 @@ $(function() { return; } - if (self.installed(data)) { - self.installPlugin(data.archive, data.title, data.id, data.follow_dependency_links || self.followDependencyLinks()); - } else { - self.installPlugin(data.archive, data.title, undefined, data.follow_dependency_links || self.followDependencyLinks()); - } + self.installPlugin(data.archive, data.title, (self.installed(data) ? data.id : undefined), data.follow_dependency_links || self.followDependencyLinks()); }; self.installPlugin = function(url, name, reinstall, followDependencyLinks) { @@ -283,26 +343,33 @@ $(function() { } self._markWorking(workTitle, workText); - var command = "install"; - var payload = {url: url, dependency_links: followDependencyLinks}; - if (reinstall) { - payload["plugin"] = reinstall; - payload["force"] = true; - } + var onSuccess = function() { + self.requestData(); + self.installUrl(""); + }, + onError = function() { + new PNotify({ + title: gettext("Something went wrong"), + text: gettext("Please consult octoprint.log for details"), + type: "error", + hide: false + }); + }, + onAlways = function() { + self._markDone(); + }; - self._postCommand(command, payload, function(response) { - self.requestData(); - self._markDone(); - self.installUrl(""); - }, function() { - new PNotify({ - title: gettext("Something went wrong"), - text: gettext("Please consult octoprint.log for details"), - type: "error", - hide: false - }); - self._markDone(); - }); + if (reinstall) { + OctoPrint.plugins.pluginmanager.reinstall(reinstall, url, followDependencyLinks) + .done(onSuccess) + .fail(onError) + .always(onAlways); + } else { + OctoPrint.plugins.pluginmanager.install(url, followDependencyLinks) + .done(onSuccess) + .fail(onError) + .always(onAlways); + } }; self.uninstallPlugin = function(data) { @@ -319,20 +386,19 @@ $(function() { self._markWorking(gettext("Uninstalling plugin..."), _.sprintf(gettext("Uninstalling plugin \"%(name)s\""), {name: data.name})); - var command = "uninstall"; - var payload = {plugin: data.key}; - self._postCommand(command, payload, function(response) { - self.requestData(); - self._markDone(); - }, function() { - new PNotify({ - title: gettext("Something went wrong"), - text: gettext("Please consult octoprint.log for details"), - type: "error", - hide: false + OctoPrint.plugins.pluginmanager.uninstall(data.key) + .done(self.requestData) + .fail(function() { + new PNotify({ + title: gettext("Something went wrong"), + text: gettext("Please consult octoprint.log for details"), + type: "error", + hide: false + }); + }) + .always(function() { + self._markDone(); }); - self._markDone(); - }); }; self.refreshRepository = function() { @@ -400,33 +466,6 @@ $(function() { } }; - self._postCommand = function (command, data, successCallback, failureCallback, alwaysCallback, timeout) { - var payload = _.extend(data, {command: command}); - - var params = { - url: API_BASEURL + "plugin/pluginmanager", - type: "POST", - dataType: "json", - data: JSON.stringify(payload), - contentType: "application/json; charset=UTF-8", - success: function(response) { - if (successCallback) successCallback(response); - }, - error: function() { - if (failureCallback) failureCallback(); - }, - complete: function() { - if (alwaysCallback) alwaysCallback(); - } - }; - - if (timeout != undefined) { - params.timeout = timeout; - } - - $.ajax(params); - }; - self._markWorking = function(title, line) { self.working(true); self.workingTitle(title); diff --git a/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js b/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js index b9223ddf..4be1e147 100644 --- a/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js +++ b/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js @@ -1,4 +1,38 @@ $(function() { + OctoPrint.plugins.softwareupdate = (function($, _) { + var exports = {}; + + var url = OctoPrint.getBlueprintUrl("softwareupdate"); + var checkUrl = url + "check"; + var updateUrl = url + "update"; + + exports.check = function(force, opts) { + return OctoPrint.get(checkUrl + ((!!force) ? "?force=true" : ""), opts); + }; + + exports.update = function(entries, force, opts) { + entries = entries || []; + if (typeof entries == "string") { + entries = [entries]; + } + + var data = { + entries: entries, + force: !!force + }; + return OctoPrint.postJson(updateUrl, data, opts); + }; + + exports.updateAll = function(force, opts) { + var data = { + force: !!force + }; + return OctoPrint.postJson(updateUrl, data, opts); + }; + + return exports; + })($, _); + function SoftwareUpdateViewModel(parameters) { var self = this; @@ -221,20 +255,10 @@ $(function() { self.performCheck = function(showIfNothingNew, force, ignoreSeen) { if (!self.loginState.isUser()) return; - - var url = PLUGIN_BASEURL + "softwareupdate/check"; - if (force) { - url += "?force=true"; - } - - $.ajax({ - url: url, - type: "GET", - dataType: "json", - success: function(data) { + OctoPrint.plugins.softwareupdate.check(force) + .done(function(data) { self.fromCheckResponse(data, ignoreSeen, showIfNothingNew); - } - }); + }); }; self._markNotificationAsSeen = function(data) { @@ -285,13 +309,12 @@ $(function() { }; self._showPopup(options); - $.ajax({ - url: PLUGIN_BASEURL + "softwareupdate/update", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify({force: (force == true)}), - error: function() { + OctoPrint.plugins.softwareupdate.updateAll(force) + .done(function(data) { + self.currentlyBeingUpdated = data.checks; + self._markWorking(gettext("Updating..."), gettext("Updating, please wait.")); + }) + .fail(function() { self.updateInProgress = false; self._showPopup({ title: gettext("Update not started!"), @@ -302,12 +325,7 @@ $(function() { sticker: false } }); - }, - success: function(data) { - self.currentlyBeingUpdated = data.checks; - self._markWorking(gettext("Updating..."), gettext("Updating, please wait.")); - } - }); + }); }; self.update = function(force) { diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index a64b5109..77ddcf78 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -912,6 +912,25 @@ class Server(object): "js/lib/loglevel.min.js", "js/lib/sockjs-0.3.4.min.js" ] + js_client = [ + "js/app/client/octoprint.js", + "js/app/client/socket.js", + "js/app/client/browser.js", + "js/app/client/connection.js", + "js/app/client/control.js", + "js/app/client/files.js", + "js/app/client/job.js", + "js/app/client/languages.js", + "js/app/client/logs.js", + "js/app/client/printer.js", + "js/app/client/printerprofiles.js", + "js/app/client/settings.js", + "js/app/client/slicing.js", + "js/app/client/timelapse.js", + "js/app/client/users.js", + "js/app/client/util.js", + "js/app/client/wizard.js" + ] js_app = dynamic_assets["js"] + [ "js/app/dataupdater.js", "js/app/helpers.js", @@ -966,8 +985,10 @@ class Server(object): js_libs_bundle = Bundle(*js_libs, output="webassets/packed_libs.js", filters="js_delimiter_bundler") if minify: + js_client_bundle = Bundle(*js_client, output="webassets/packed_client.js", filters="rjsmin, js_delimiter_bundler") js_app_bundle = Bundle(*js_app, output="webassets/packed_app.js", filters="rjsmin, js_delimiter_bundler") else: + js_client_bundle = Bundle(*js_client, output="webassets/packed_client.js", filters="js_delimiter_bundler") js_app_bundle = Bundle(*js_app, output="webassets/packed_app.js", filters="js_delimiter_bundler") css_libs_bundle = Bundle(*css_libs, output="webassets/packed_libs.css") @@ -976,6 +997,7 @@ class Server(object): all_less_bundle = Bundle(*less_app, output="webassets/packed_app.less", filters="cssrewrite, less_importrewrite") assets.register("js_libs", js_libs_bundle) + assets.register("js_client", js_client_bundle) assets.register("js_app", js_app_bundle) assets.register("css_libs", css_libs_bundle) assets.register("css_app", css_app_bundle) diff --git a/src/octoprint/server/api/__init__.py b/src/octoprint/server/api/__init__.py index 7bb87bc4..9d953edf 100644 --- a/src/octoprint/server/api/__init__.py +++ b/src/octoprint/server/api/__init__.py @@ -217,7 +217,11 @@ def performSystemAction(): @api.route("/login", methods=["POST"]) def login(): - if octoprint.server.userManager is not None and "user" in request.values.keys() and "pass" in request.values.keys(): + data = request.values + if hasattr(request, "json") and request.json: + data = request.json + + if octoprint.server.userManager is not None and "user" in data and "pass" in data: username = request.values["user"] password = request.values["pass"] @@ -241,7 +245,7 @@ def login(): return jsonify(user.asDict()) return make_response(("User unknown or password incorrect", 401, [])) - elif "passive" in request.values: + elif "passive" in data: return passive_login() return NO_CONTENT diff --git a/src/octoprint/server/views.py b/src/octoprint/server/views.py index 961ba445..0f1b8c70 100644 --- a/src/octoprint/server/views.py +++ b/src/octoprint/server/views.py @@ -573,4 +573,3 @@ def localeJs(locale, domain): def plugin_assets(name, filename): return redirect(url_for("plugin." + name + ".static", filename=filename)) - diff --git a/src/octoprint/static/js/app/client.js b/src/octoprint/static/js/app/client.js deleted file mode 100644 index 803635af..00000000 --- a/src/octoprint/static/js/app/client.js +++ /dev/null @@ -1,79 +0,0 @@ -var OctoPrint = (function($, _, SockJS) { - var self = { - options: { - socketReconnectTimeouts: [0, 1, 1, 2, 3, 5, 8, 13, 20, 40, 100], - socketDebug: false, - socketNormalClose: 1000 - } - }; - - var _socket = undefined; - var _socketAddress = undefined; - var _socketReconnecting = false; - var _socketReconnectTrial = 0; - var _socketIgnoreReconnects = 1; - - function callCallback(callback, arguments) { - if (!_.isFunction(self.options[callback])) { - throw Error("No such callback: " + callback); - } - - self.options[callback].bind(arguments); - } - - function connect(socketAddress) { - var address = socketAddress || _socketAddress; - if (address == undefined) { - return; - } - - var socketOptions = { - debug: options.socketDebug || false - }; - - if (_socket != undefined) { - self._socket.close(); - delete self._socket; - } - - _socketAddress = address; - _socket = new SockJS(address, undefined, socketOptions); - _socket.onopen = onSocketOpen; - _socket.onclose = onSocketClose; - _socket.onmessage = onSocketMessage; - } - - function onSocketOpen() { - _socketReconnecting = false; - _socketReconnectTrial = 0; - } - - function onSocketClose(error) { - if (error.code == options.socketNormalClose) { - return; - } - - if (_socketReconnectTrial >= _socketIgnoreReconnects) { - if (options.onAttemptingReconnect) { - options.onAttemptingReconnect(_socketReconnectTrial); - } - } - - if (_socketReconnectTrial < options.socketReconnectTimeouts.length) { - var timeout = options.socketReconnectTimeouts[_socketReconnectTrial]; - log.info("Reconnect trial #" + self._autoReconnectTrial + ", waiting " + timeout + "s"); - setTimeout(connect, timeout * 1000); - _socketReconnectTrial++; - } else { - if (options.onReconnectFailed) { - options.onReconnectFailed(); - } - } - } - - function onSocketMessage(data) { - } - - return self; - -}(jQuery, _, SockJS)); diff --git a/src/octoprint/static/js/app/dataupdater.js b/src/octoprint/static/js/app/dataupdater.js index 52293417..fa42e519 100644 --- a/src/octoprint/static/js/app/dataupdater.js +++ b/src/octoprint/static/js/app/dataupdater.js @@ -3,12 +3,6 @@ function DataUpdater(allViewModels) { self.allViewModels = allViewModels; - self._socket = undefined; - self._autoReconnecting = false; - self._autoReconnectTrial = 0; - self._autoReconnectTimeouts = [0, 1, 1, 2, 3, 5, 8, 13, 20, 40, 100]; - self._autoReconnectDialogIndex = 1; - self._pluginHash = undefined; self._configHash = undefined; @@ -16,65 +10,39 @@ function DataUpdater(allViewModels) { $("#reloadui_overlay_reload").click(function() { location.reload(true); }); self.connect = function() { - var options = {}; - if (SOCKJS_DEBUG) { - options["debug"] = true; - } - - self._socket = new SockJS(SOCKJS_URI, undefined, options); - self._socket.onopen = self._onconnect; - self._socket.onclose = self._onclose; - self._socket.onmessage = self._onmessage; + OctoPrint.socket.connect({debug: !!SOCKJS_DEBUG}); }; self.reconnect = function() { - self._socket.close(); - delete self._socket; - self.connect(); + OctoPrint.socket.reconnect(); }; - self._onconnect = function() { - self._autoReconnecting = false; - self._autoReconnectTrial = 0; - }; - - self._onclose = function(e) { - if (e.code == SOCKJS_CLOSE_NORMAL) { + self._onReconnectAttempt = function(trial) { + if (trial <= 0) { + // Only consider it a real disconnect if the trial number has exceeded our threshold. return; } - if (self._autoReconnectTrial >= self._autoReconnectDialogIndex) { - // Only consider it a real disconnect if the trial number has exceeded our threshold. - var handled = false; - callViewModelsIf( - self.allViewModels, - "onServerDisconnect", - function() { return !handled; }, - function(method) { handled = !method() || handled; } - ); + var handled = false; + callViewModelsIf( + self.allViewModels, + "onServerDisconnect", + function() { return !handled; }, + function(method) { handled = !method() || handled; } + ); - if (handled) { - return; - } - - showOfflineOverlay( - gettext("Server is offline"), - gettext("The server appears to be offline, at least I'm not getting any response from it. I'll try to reconnect automatically over the next couple of minutes, however you are welcome to try a manual reconnect anytime using the button below."), - self.reconnect - ); + if (handled) { + return true; } - if (self._autoReconnectTrial < self._autoReconnectTimeouts.length) { - var timeout = self._autoReconnectTimeouts[self._autoReconnectTrial]; - log.info("Reconnect trial #" + self._autoReconnectTrial + ", waiting " + timeout + "s"); - setTimeout(self.reconnect, timeout * 1000); - self._autoReconnectTrial++; - } else { - self._onreconnectfailed(); - } + showOfflineOverlay( + gettext("Server is offline"), + gettext("The server appears to be offline, at least I'm not getting any response from it. I'll try to reconnect automatically over the next couple of minutes, however you are welcome to try a manual reconnect anytime using the button below."), + self.reconnect + ); }; - self._onreconnectfailed = function() { + self._onReconnectFailed = function() { var handled = false; callViewModelsIf( self.allViewModels, @@ -91,182 +59,181 @@ function DataUpdater(allViewModels) { $("#offline_overlay_message").html(gettext("The server appears to be offline, at least I'm not getting any response from it. I could not reconnect automatically, but you may try a manual reconnect using the button below.")); }; - self._onmessage = function(e) { - for (var prop in e.data) { - if (!e.data.hasOwnProperty(prop)) { - continue; + self._onConnected = function(event) { + var data = event.data; + + // update version information + var oldVersion = VERSION; + VERSION = data["version"]; + DISPLAY_VERSION = data["display_version"]; + BRANCH = data["branch"]; + $("span.version").text(DISPLAY_VERSION); + + // update plugin hash + var oldPluginHash = self._pluginHash; + self._pluginHash = data["plugin_hash"]; + + // update config hash + var oldConfigHash = self._configHash; + self._configHash = data["config_hash"]; + + // if the offline overlay is still showing, now's a good time to + // hide it, plus reload the camera feed if it's currently displayed + if ($("#offline_overlay").is(":visible")) { + hideOfflineOverlay(); + callViewModels(self.allViewModels, "onDataUpdaterReconnect"); + + if ($('#tabs li[class="active"] a').attr("href") == "#control") { + $("#webcam_image").attr("src", CONFIG_WEBCAM_STREAM + "?" + new Date().getTime()); } + } - var data = e.data[prop]; - - var gcodeUploadProgress = $("#gcode_upload_progress"); - var gcodeUploadProgressBar = $(".bar", gcodeUploadProgress); - - switch (prop) { - case "connected": { - // update the current UI API key and send it with any request - UI_API_KEY = data["apikey"]; - $.ajaxSetup({ - headers: {"X-Api-Key": UI_API_KEY} - }); - - var oldVersion = VERSION; - VERSION = data["version"]; - DISPLAY_VERSION = data["display_version"]; - BRANCH = data["branch"]; - $("span.version").text(DISPLAY_VERSION); - - var oldPluginHash = self._pluginHash; - self._pluginHash = data["plugin_hash"]; - - var oldConfigHash = self._configHash; - self._configHash = data["config_hash"]; - - if ($("#offline_overlay").is(":visible")) { - hideOfflineOverlay(); - callViewModels(self.allViewModels, "onDataUpdaterReconnect"); - - if ($('#tabs li[class="active"] a').attr("href") == "#control") { - $("#webcam_image").attr("src", CONFIG_WEBCAM_STREAM + "?" + new Date().getTime()); - } - } - - var versionChanged = oldVersion != VERSION; - var pluginsChanged = oldPluginHash != undefined && oldPluginHash != self._pluginHash; - var configChanged = oldConfigHash != undefined && oldConfigHash != self._configHash; - if (versionChanged || pluginsChanged || configChanged) { - self.reloadOverlay.show(); - } - - break; - } - case "history": { - callViewModels(self.allViewModels, "fromHistoryData", [data]); - break; - } - case "current": { - callViewModels(self.allViewModels, "fromCurrentData", [data]); - break; - } - case "slicingProgress": { - gcodeUploadProgressBar.text(_.sprintf(gettext("Slicing ... (%(percentage)d%%)"), {percentage: Math.round(data["progress"])})); - - callViewModels(self.allViewModels, "onSlicingProgress", [ - data["slicer"], - data["model_path"], - data["machinecode_path"], - data["progress"] - ]); - break; - } - case "event": { - var type = data["type"]; - var payload = data["payload"]; - var html = ""; - var format = {}; - - log.debug("Got event " + type + " with payload: " + JSON.stringify(payload)); - - if (type == "SettingsUpdated") { - if (payload && payload.hasOwnProperty("config_hash")) { - self._configHash = payload.config_hash; - } - } else if (type == "MovieRendering") { - new PNotify({title: gettext("Rendering timelapse"), text: _.sprintf(gettext("Now rendering timelapse %(movie_basename)s"), payload)}); - } else if (type == "MovieDone") { - new PNotify({title: gettext("Timelapse ready"), text: _.sprintf(gettext("New timelapse %(movie_basename)s is done rendering."), payload)}); - } else if (type == "MovieFailed") { - html = "

" + _.sprintf(gettext("Rendering of timelapse %(movie_basename)s failed with return code %(returncode)s"), payload) + "

"; - html += pnotifyAdditionalInfo('
' + payload.error + '
'); - new PNotify({ - title: gettext("Rendering failed"), - text: html, - type: "error", - hide: false - }); - } else if (type == "PostRollStart") { - if (payload.postroll_duration > 60) { - format = {duration: _.sprintf(gettext("%(minutes)d min"), {minutes: payload.postroll_duration / 60})}; - } else { - format = {duration: _.sprintf(gettext("%(seconds)d sec"), {seconds: payload.postroll_duration})}; - } - - new PNotify({ - title: gettext("Capturing timelapse postroll"), - text: _.sprintf(gettext("Now capturing timelapse post roll, this will take approximately %(duration)s..."), format) - }); - } else if (type == "SlicingStarted") { - gcodeUploadProgress.addClass("progress-striped").addClass("active"); - gcodeUploadProgressBar.css("width", "100%"); - if (payload.progressAvailable) { - gcodeUploadProgressBar.text(_.sprintf(gettext("Slicing ... (%(percentage)d%%)"), {percentage: 0})); - } else { - gcodeUploadProgressBar.text(gettext("Slicing ...")); - } - } else if (type == "SlicingDone") { - gcodeUploadProgress.removeClass("progress-striped").removeClass("active"); - gcodeUploadProgressBar.css("width", "0%"); - gcodeUploadProgressBar.text(""); - new PNotify({title: gettext("Slicing done"), text: _.sprintf(gettext("Sliced %(stl)s to %(gcode)s, took %(time).2f seconds"), payload), type: "success"}); - } else if (type == "SlicingCancelled") { - gcodeUploadProgress.removeClass("progress-striped").removeClass("active"); - gcodeUploadProgressBar.css("width", "0%"); - gcodeUploadProgressBar.text(""); - } else if (type == "SlicingFailed") { - gcodeUploadProgress.removeClass("progress-striped").removeClass("active"); - gcodeUploadProgressBar.css("width", "0%"); - gcodeUploadProgressBar.text(""); - - html = _.sprintf(gettext("Could not slice %(stl)s to %(gcode)s: %(reason)s"), payload); - new PNotify({title: gettext("Slicing failed"), text: html, type: "error", hide: false}); - } else if (type == "TransferStarted") { - gcodeUploadProgress.addClass("progress-striped").addClass("active"); - gcodeUploadProgressBar.css("width", "100%"); - gcodeUploadProgressBar.text(gettext("Streaming ...")); - } else if (type == "TransferDone") { - gcodeUploadProgress.removeClass("progress-striped").removeClass("active"); - gcodeUploadProgressBar.css("width", "0%"); - gcodeUploadProgressBar.text(""); - new PNotify({ - title: gettext("Streaming done"), - text: _.sprintf(gettext("Streamed %(local)s to %(remote)s on SD, took %(time).2f seconds"), payload), - type: "success" - }); - gcodeFilesViewModel.requestData(payload.remote, "sdcard"); - } - - var legacyEventHandlers = { - "UpdatedFiles": "onUpdatedFiles", - "MetadataStatisticsUpdated": "onMetadataStatisticsUpdated", - "MetadataAnalysisFinished": "onMetadataAnalysisFinished", - "SlicingDone": "onSlicingDone", - "SlicingCancelled": "onSlicingCancelled", - "SlicingFailed": "onSlicingFailed" - }; - _.each(self.allViewModels, function(viewModel) { - if (viewModel.hasOwnProperty("onEvent" + type)) { - viewModel["onEvent" + type](payload); - } else if (legacyEventHandlers.hasOwnProperty(type) && viewModel.hasOwnProperty(legacyEventHandlers[type])) { - // there might still be code that uses the old callbacks, make sure those still get called - // but log a warning - log.warn("View model " + viewModel.name + " is using legacy event handler " + legacyEventHandlers[type] + ", new handler is called " + legacyEventHandlers[type]); - viewModel[legacyEventHandlers[type]](payload); - } - }); - - break; - } - case "timelapse": { - callViewModels(self.allViewModels, "fromTimelapseData", [data]); - break; - } - case "plugin": { - callViewModels(self.allViewModels, "onDataUpdaterPluginMessage", [data.plugin, data.data]); - break; - } - } + // if the version, the plugin hash or the config hash changed, we + // want the user to reload the UI since it might be stale now + var versionChanged = oldVersion != VERSION; + var pluginsChanged = oldPluginHash != undefined && oldPluginHash != self._pluginHash; + var configChanged = oldConfigHash != undefined && oldConfigHash != self._configHash; + if (versionChanged || pluginsChanged || configChanged) { + self.reloadOverlay.show(); } }; + self._onHistoryData = function(event) { + callViewModels(self.allViewModels, "fromHistoryData", [event.data]); + }; + + self._onCurrentData = function(event) { + callViewModels(self.allViewModels, "fromCurrentData", [event.data]); + }; + + self._onSlicingProgress = function(event) { + $("#gcode_upload_progress").find(".bar").text(_.sprintf(gettext("Slicing ... (%(percentage)d%%)"), {percentage: Math.round(event.data["progress"])})); + + callViewModels(self.allViewModels, "onSlicingProgress", [ + data["slicer"], + data["model_path"], + data["machinecode_path"], + data["progress"] + ]); + }; + + self._onEvent = function(event) { + var gcodeUploadProgress = $("#gcode_upload_progress"); + var gcodeUploadProgressBar = $(".bar", gcodeUploadProgress); + + var type = event.data["type"]; + var payload = event.data["payload"]; + var html = ""; + var format = {}; + + log.debug("Got event " + type + " with payload: " + JSON.stringify(payload)); + + if (type == "SettingsUpdated") { + if (payload && payload.hasOwnProperty("config_hash")) { + self._configHash = payload.config_hash; + } + } else if (type == "MovieRendering") { + new PNotify({title: gettext("Rendering timelapse"), text: _.sprintf(gettext("Now rendering timelapse %(movie_basename)s"), payload)}); + } else if (type == "MovieDone") { + new PNotify({title: gettext("Timelapse ready"), text: _.sprintf(gettext("New timelapse %(movie_basename)s is done rendering."), payload)}); + } else if (type == "MovieFailed") { + html = "

" + _.sprintf(gettext("Rendering of timelapse %(movie_basename)s failed with return code %(returncode)s"), payload) + "

"; + html += pnotifyAdditionalInfo('
' + payload.error + '
'); + new PNotify({ + title: gettext("Rendering failed"), + text: html, + type: "error", + hide: false + }); + } else if (type == "PostRollStart") { + if (payload.postroll_duration > 60) { + format = {duration: _.sprintf(gettext("%(minutes)d min"), {minutes: payload.postroll_duration / 60})}; + } else { + format = {duration: _.sprintf(gettext("%(seconds)d sec"), {seconds: payload.postroll_duration})}; + } + + new PNotify({ + title: gettext("Capturing timelapse postroll"), + text: _.sprintf(gettext("Now capturing timelapse post roll, this will take approximately %(duration)s..."), format) + }); + } else if (type == "SlicingStarted") { + gcodeUploadProgress.addClass("progress-striped").addClass("active"); + gcodeUploadProgressBar.css("width", "100%"); + if (payload.progressAvailable) { + gcodeUploadProgressBar.text(_.sprintf(gettext("Slicing ... (%(percentage)d%%)"), {percentage: 0})); + } else { + gcodeUploadProgressBar.text(gettext("Slicing ...")); + } + } else if (type == "SlicingDone") { + gcodeUploadProgress.removeClass("progress-striped").removeClass("active"); + gcodeUploadProgressBar.css("width", "0%"); + gcodeUploadProgressBar.text(""); + new PNotify({title: gettext("Slicing done"), text: _.sprintf(gettext("Sliced %(stl)s to %(gcode)s, took %(time).2f seconds"), payload), type: "success"}); + } else if (type == "SlicingCancelled") { + gcodeUploadProgress.removeClass("progress-striped").removeClass("active"); + gcodeUploadProgressBar.css("width", "0%"); + gcodeUploadProgressBar.text(""); + } else if (type == "SlicingFailed") { + gcodeUploadProgress.removeClass("progress-striped").removeClass("active"); + gcodeUploadProgressBar.css("width", "0%"); + gcodeUploadProgressBar.text(""); + + html = _.sprintf(gettext("Could not slice %(stl)s to %(gcode)s: %(reason)s"), payload); + new PNotify({title: gettext("Slicing failed"), text: html, type: "error", hide: false}); + } else if (type == "TransferStarted") { + gcodeUploadProgress.addClass("progress-striped").addClass("active"); + gcodeUploadProgressBar.css("width", "100%"); + gcodeUploadProgressBar.text(gettext("Streaming ...")); + } else if (type == "TransferDone") { + gcodeUploadProgress.removeClass("progress-striped").removeClass("active"); + gcodeUploadProgressBar.css("width", "0%"); + gcodeUploadProgressBar.text(""); + new PNotify({ + title: gettext("Streaming done"), + text: _.sprintf(gettext("Streamed %(local)s to %(remote)s on SD, took %(time).2f seconds"), payload), + type: "success" + }); + gcodeFilesViewModel.requestData(payload.remote, "sdcard"); + } + + var legacyEventHandlers = { + "UpdatedFiles": "onUpdatedFiles", + "MetadataStatisticsUpdated": "onMetadataStatisticsUpdated", + "MetadataAnalysisFinished": "onMetadataAnalysisFinished", + "SlicingDone": "onSlicingDone", + "SlicingCancelled": "onSlicingCancelled", + "SlicingFailed": "onSlicingFailed" + }; + _.each(self.allViewModels, function(viewModel) { + if (viewModel.hasOwnProperty("onEvent" + type)) { + viewModel["onEvent" + type](payload); + } else if (legacyEventHandlers.hasOwnProperty(type) && viewModel.hasOwnProperty(legacyEventHandlers[type])) { + // there might still be code that uses the old callbacks, make sure those still get called + // but log a warning + log.warn("View model " + viewModel.name + " is using legacy event handler " + legacyEventHandlers[type] + ", new handler is called " + legacyEventHandlers[type]); + viewModel[legacyEventHandlers[type]](payload); + } + }); + }; + + self._onTimelapse = function(event) { + callViewModels(self.allViewModels, "fromTimelapseData", [event.data]); + }; + + self._onPluginMessage = function(event) { + callViewModels(self.allViewModels, "onDataUpdaterPluginMessage", [event.data.plugin, event.data.data]); + }; + + OctoPrint.socket.onReconnectAttempt = self._onReconnectAttempt; + OctoPrint.socket.onReconnectFailed = self._onReconnectFailed; + OctoPrint.socket + .onMessage("connected", self._onConnected) + .onMessage("history", self._onHistoryData) + .onMessage("current", self._onCurrentData) + .onMessage("slicingProgress", self._onSlicingProgress) + .onMessage("event", self._onEvent) + .onMessage("timelapse", self._onTimelapse) + .onMessage("plugin", self._onPluginMessage); + self.connect(); } diff --git a/src/octoprint/static/js/app/main.js b/src/octoprint/static/js/app/main.js index c1237505..ebbede84 100644 --- a/src/octoprint/static/js/app/main.js +++ b/src/octoprint/static/js/app/main.js @@ -7,6 +7,22 @@ $(function() { log.setLevel(CONFIG_DEBUG ? "debug" : "info"); + //~~ OctoPrint client setup + OctoPrint.options.baseurl = BASEURL; + OctoPrint.options.apikey = UI_API_KEY; + + OctoPrint.socket.onMessage("connected", function(data) { + OctoPrint.options.apikey = data.apikey; + + // update the API key directly in jquery's ajax options too, + // to ensure the fileupload plugin and any plugins still using + // $.ajax directly still work fine too + UI_API_KEY = data["apikey"]; + $.ajaxSetup({ + headers: {"X-Api-Key": UI_API_KEY} + }); + }); + //~~ AJAX setup // work around a stupid iOS6 bug where ajax requests get cached and only work once, as described at diff --git a/src/octoprint/static/js/app/viewmodels/connection.js b/src/octoprint/static/js/app/viewmodels/connection.js index 7f55d607..d501e7ec 100644 --- a/src/octoprint/static/js/app/viewmodels/connection.js +++ b/src/octoprint/static/js/app/viewmodels/connection.js @@ -47,14 +47,8 @@ $(function() { self.previousIsOperational = undefined; self.requestData = function() { - $.ajax({ - url: API_BASEURL + "connection", - method: "GET", - dataType: "json", - success: function(response) { - self.fromResponse(response); - } - }) + OctoPrint.connection.getSettings() + .done(self.fromResponse); }; self.fromResponse = function(response) { @@ -93,7 +87,7 @@ $(function() { } else if (!self.isOperational() && !connectionTab.hasClass("in")) { connectionTab.collapse("show"); } - } + }; self._processStateData = function(data) { self.previousIsOperational = self.isOperational(); @@ -116,7 +110,6 @@ $(function() { self.connect = function() { if (self.isErrorOrClosed()) { var data = { - "command": "connect", "port": self.selectedPort() || "AUTO", "baudrate": self.selectedBaudrate() || 0, "printerProfile": self.selectedPrinter(), @@ -126,26 +119,14 @@ $(function() { if (self.saveSettings()) data["save"] = true; - $.ajax({ - url: API_BASEURL + "connection", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify(data), - success: function(response) { + OctoPrint.connection.connect(data) + .done(function() { self.settings.requestData(); self.settings.printerProfiles.requestData(); - } - }); + }); } else { self.requestData(); - $.ajax({ - url: API_BASEURL + "connection", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify({"command": "disconnect"}) - }) + OctoPrint.connection.disconnect(); } }; diff --git a/src/octoprint/static/js/app/viewmodels/control.js b/src/octoprint/static/js/app/viewmodels/control.js index d8ab3457..a8680e87 100644 --- a/src/octoprint/static/js/app/viewmodels/control.js +++ b/src/octoprint/static/js/app/viewmodels/control.js @@ -108,14 +108,10 @@ $(function() { }; self.requestData = function () { - $.ajax({ - url: API_BASEURL + "printer/command/custom", - method: "GET", - dataType: "json", - success: function (response) { + OctoPrint.control.getCustomControls() + .done(function(response) { self._fromResponse(response); - } - }); + }); }; self._fromResponse = function (response) { @@ -254,26 +250,17 @@ $(function() { multiplier *= -1; } - var data = { - "command": "jog" - }; + var data = {}; data[axis] = distance * multiplier; - - self.sendPrintHeadCommand(data); + OctoPrint.printer.jog(data); }; self.sendHomeCommand = function (axis) { - self.sendPrintHeadCommand({ - "command": "home", - "axes": axis - }); + OctoPrint.printer.home(axis); }; self.sendFeedRateCommand = function () { - self.sendPrintHeadCommand({ - "command": "feedrate", - "factor": self.feedRate() - }); + OctoPrint.printer.setFeedrate(self.feedRate()); }; self.sendExtrudeCommand = function () { @@ -285,90 +272,46 @@ $(function() { }; self.sendFlowRateCommand = function () { - self.sendToolCommand({ - "command": "flowrate", - "factor": self.flowRate() - }); + OctoPrint.printer.setFlowrate(self.flowRate()); }; self._sendECommand = function (dir) { - var length = self.extrusionAmount(); - if (!length) length = self.settings.printer_defaultExtrusionLength(); - - self.sendToolCommand({ - command: "extrude", - amount: length * dir - }); + var length = self.extrusionAmount() || self.settings.printer_defaultExtrusionLength(); + OctoPrint.printer.extrude(length * dir); }; self.sendSelectToolCommand = function (data) { if (!data || !data.key()) return; - self.sendToolCommand({ - command: "select", - tool: data.key() - }); - }; - - self.sendPrintHeadCommand = function (data) { - $.ajax({ - url: API_BASEURL + "printer/printhead", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify(data) - }); - }; - - self.sendToolCommand = function (data) { - $.ajax({ - url: API_BASEURL + "printer/tool", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify(data) - }); + OctoPrint.printer.selectTool(data.key()); }; self.sendCustomCommand = function (command) { if (!command) return; - var data = undefined; - if (command.hasOwnProperty("command")) { - // single command - data = {"command": command.command}; - } else if (command.hasOwnProperty("commands")) { - // multi command - data = {"commands": command.commands}; - } else if (command.hasOwnProperty("script")) { - data = {"script": command.script}; - if (command.hasOwnProperty("context")) { - data["context"] = command.context; + if (command.hasOwnProperty("command") || command.hasOwnProperty("commands")) { + var commands = command.commands || [command.command]; + + if (commands.hasOwnProperty("input")) { + var parameters = {}; + _.each(command.input, function(input) { + if (!input.hasOwnProperty("parameter") || !input.hasOwnProperty("value")) { + return; + } + + parameters[input.parameter] = input.value(); + }); + OctoPrint.control.sendGcodeWithParameters(commands, parameters); + } else { + OctoPrint.control.sendGcode(commands); } - } else { - return; + } else if (command.hasOwnProperty("script")) { + var script = command.script; + var context = command.context || {}; + + OctoPrint.control.sendGcodeScript(script, context); } - - if (command.hasOwnProperty("input")) { - // parametric command(s) - data["parameters"] = {}; - _.each(command.input, function(input) { - if (!input.hasOwnProperty("parameter") || !input.hasOwnProperty("value")) { - return; - } - - data["parameters"][input.parameter] = input.value(); - }); - } - - $.ajax({ - url: API_BASEURL + "printer/command", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify(data) - }) }; self.displayMode = function (customControl) { @@ -414,7 +357,7 @@ $(function() { } else { $("#webcam_rotator").css("height", ""); } - } + }; self.onSettingsBeforeSave = self.updateRotatorWidth; diff --git a/src/octoprint/static/js/app/viewmodels/files.js b/src/octoprint/static/js/app/viewmodels/files.js index 885f5a40..3b752773 100644 --- a/src/octoprint/static/js/app/viewmodels/files.js +++ b/src/octoprint/static/js/app/viewmodels/files.js @@ -146,18 +146,13 @@ $(function() { if (self._otherRequestInProgress) return; self._otherRequestInProgress = true; - $.ajax({ - url: API_BASEURL + "files", - method: "GET", - dataType: "json", - success: function(response) { + OctoPrint.files.list() + .done(function(response) { self.fromResponse(response, filenameToFocus, locationToFocus); + }) + .always(function() { self._otherRequestInProgress = false; - }, - error: function() { - self._otherRequestInProgress = false; - } - }); + }); }; self.fromResponse = function(response, filenameToFocus, locationToFocus) { @@ -192,55 +187,45 @@ $(function() { }; self.loadFile = function(file, printAfterLoad) { - if (!file || !file.refs || !file.refs.hasOwnProperty("resource")) return; - - $.ajax({ - url: file.refs.resource, - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify({command: "select", print: printAfterLoad}) - }); + if (!file) { + return; + } + OctoPrint.files.select(file.origin, file.name) + .done(function() { + if (printAfterLoad) { + OctoPrint.job.start(); + } + }); }; self.removeFile = function(file) { - if (!file || !file.refs || !file.refs.hasOwnProperty("resource")) return; - - $.ajax({ - url: file.refs.resource, - type: "DELETE", - success: function() { + if (!file) { + return; + } + OctoPrint.files.delete(file.origin, file.name) + .done(function() { self.requestData(); - } - }); + }) }; self.sliceFile = function(file) { - if (!file) return; + if (!file) { + return; + } self.slicing.show(file.origin, file.name, true); }; self.initSdCard = function() { - self._sendSdCommand("init"); + OctoPrint.printer.initSd(); }; self.releaseSdCard = function() { - self._sendSdCommand("release"); + OctoPrint.printer.releaseSd(); }; self.refreshSdFiles = function() { - self._sendSdCommand("refresh"); - }; - - self._sendSdCommand = function(command) { - $.ajax({ - url: API_BASEURL + "printer/sd", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify({command: command}) - }); + OctoPrint.printer.refreshSd(); }; self.downloadLink = function(data) { diff --git a/src/octoprint/static/js/app/viewmodels/gcode.js b/src/octoprint/static/js/app/viewmodels/gcode.js index eb8c358d..5b032b3e 100644 --- a/src/octoprint/static/js/app/viewmodels/gcode.js +++ b/src/octoprint/static/js/app/viewmodels/gcode.js @@ -289,11 +289,8 @@ $(function() { self.enableReload(false); if (self.status == "idle" && self.errorCount < 3) { self.status = "request"; - $.ajax({ - url: BASEURL + "downloads/files/local/" + filename, - data: { "ctime": date }, - type: "GET", - success: function(response, rstatus) { + OctoPrint.files.download("local", filename) + .done(function(response, rstatus) { if(rstatus === 'success'){ self.showGCodeViewer(response, rstatus); self.loadedFilename = filename; @@ -301,12 +298,11 @@ $(function() { self.status = "idle"; self.enableReload(true); } - }, - error: function() { + }) + .fail(function() { self.status = "idle"; self.errorCount++; - } - }); + }); } }; diff --git a/src/octoprint/static/js/app/viewmodels/log.js b/src/octoprint/static/js/app/viewmodels/log.js index fa42aeed..872eb288 100644 --- a/src/octoprint/static/js/app/viewmodels/log.js +++ b/src/octoprint/static/js/app/viewmodels/log.js @@ -36,12 +36,8 @@ $(function() { ); self.requestData = function() { - $.ajax({ - url: API_BASEURL + "logs", - type: "GET", - dataType: "json", - success: self.fromResponse - }); + OctoPrint.logs.list() + .done(self.fromResponse); }; self.fromResponse = function(response) { @@ -53,12 +49,8 @@ $(function() { }; self.removeFile = function(filename) { - $.ajax({ - url: API_BASEURL + "logs/" + filename, - type: "DELETE", - dataType: "json", - success: self.requestData - }); + OctoPrint.logs.delete(filename) + .done(self.requestData); }; self.onUserLoggedIn = function(user) { @@ -73,4 +65,4 @@ $(function() { ["loginStateViewModel"], "#logs" ]); -}); \ No newline at end of file +}); diff --git a/src/octoprint/static/js/app/viewmodels/loginstate.js b/src/octoprint/static/js/app/viewmodels/loginstate.js index 661b1549..a5dfaf38 100644 --- a/src/octoprint/static/js/app/viewmodels/loginstate.js +++ b/src/octoprint/static/js/app/viewmodels/loginstate.js @@ -32,20 +32,13 @@ $(function() { return; } - $.ajax({ - url: API_BASEURL + "users/" + self.currentUser().name, - type: "GET", - success: self.fromResponse - }) + OctoPrint.users.get(self.currentUser().name) + .done(self.fromResponse); }; self.requestData = function() { - $.ajax({ - url: API_BASEURL + "login", - type: "POST", - data: {"passive": true}, - success: self.fromResponse - }) + OctoPrint.browser.passiveLogin() + .done(self.fromResponse); }; self.fromResponse = function(response) { @@ -70,7 +63,7 @@ $(function() { } }; - self.login = function(u, p, r, callback) { + self.login = function(u, p, r) { var username = u || self.loginUser(); var password = p || self.loginPass(); var remember = (r != undefined ? r : self.loginRemember()); @@ -79,30 +72,22 @@ $(function() { self.loginPass(""); self.loginRemember(false); - $.ajax({ - url: API_BASEURL + "login", - type: "POST", - data: {"user": username, "pass": password, "remember": remember}, - success: function(response) { + return OctoPrint.browser.login(username, password, remember) + .done(function(response) { new PNotify({title: gettext("Login successful"), text: _.sprintf(gettext('You are now logged in as "%(username)s"'), {username: response.name}), type: "success"}); self.fromResponse(response); - if (callback) callback(response); - }, - error: function(jqXHR, textStatus, errorThrown) { + }) + .fail(function() { new PNotify({title: gettext("Login failed"), text: gettext("User unknown or wrong password"), type: "error"}); - } - }) + }); }; self.logout = function() { - $.ajax({ - url: API_BASEURL + "logout", - type: "POST", - success: function(response) { + OctoPrint.browser.logout() + .done(function(response) { new PNotify({title: gettext("Logout successful"), text: gettext("You are now logged out"), type: "success"}); self.fromResponse(response); - } - }) + }); }; self.onLoginUserKeyup = function(data, event) { diff --git a/src/octoprint/static/js/app/viewmodels/navigation.js b/src/octoprint/static/js/app/viewmodels/navigation.js index 736fc949..1c9851fa 100644 --- a/src/octoprint/static/js/app/viewmodels/navigation.js +++ b/src/octoprint/static/js/app/viewmodels/navigation.js @@ -19,22 +19,17 @@ $(function() { self.triggerAction = function(action) { var callback = function() { - $.ajax({ - url: API_BASEURL + "system", - type: "POST", - dataType: "json", - data: "action=" + action.action, - success: function() { - new PNotify({title: "Success", text: _.sprintf(gettext("The command \"%(command)s\" executed successfully"), {command: action.name}), type: "success"}); - }, - error: function(jqXHR, textStatus, errorThrown) { + OctoPrint.control.executeSystemCommand(action.action) + .done(function() { + new PNotify({title: gettext("Success"), text: _.sprintf(gettext("The command \"%(command)s\" executed successfully"), {command: action.name}), type: "success"}); + }) + .fail(function() { if (!action.hasOwnProperty("ignore") || !action.ignore) { var error = "

" + _.sprintf(gettext("The command \"%(command)s\" could not be executed."), {command: action.name}) + "

"; error += pnotifyAdditionalInfo("
" + jqXHR.responseText + "
"); new PNotify({title: gettext("Error"), text: error, type: "error", hide: false}); } - } - }) + }); }; if (action.confirm) { showConfirmationDialog({ diff --git a/src/octoprint/static/js/app/viewmodels/printerprofiles.js b/src/octoprint/static/js/app/viewmodels/printerprofiles.js index 79612465..922ddd8f 100644 --- a/src/octoprint/static/js/app/viewmodels/printerprofiles.js +++ b/src/octoprint/static/js/app/viewmodels/printerprofiles.js @@ -194,12 +194,8 @@ $(function() { }; self.requestData = function() { - $.ajax({ - url: API_BASEURL + "printerprofiles", - type: "GET", - dataType: "json", - success: self.fromResponse - }) + OctoPrint.printerprofiles.get() + .done(self.fromResponse); }; self.fromResponse = function(data) { @@ -228,43 +224,35 @@ $(function() { self.addProfile = function(callback) { var profile = self._editorData(); self.requestInProgress(true); - $.ajax({ - url: API_BASEURL + "printerprofiles", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify({profile: profile}), - success: function() { - self.requestInProgress(false); + OctoPrint.printerprofiles.add(profile) + .done(function() { if (callback !== undefined) { callback(); } self.requestData(); - }, - error: function() { - self.requestInProgress(false); + }) + .fail(function() { var text = gettext("There was unexpected error while saving the printer profile, please consult the logs."); new PNotify({title: gettext("Saving failed"), text: text, type: "error", hide: false}); - } - }); + }) + .always(function() { + self.requestInProgress(false); + }); }; self.removeProfile = function(data) { self.requestInProgress(true); - $.ajax({ - url: data.resource, - type: "DELETE", - dataType: "json", - success: function() { - self.requestInProgress(false); + OctoPrint.printerprofiles.delete(data.id, {url: data.resource}) + .done(function() { self.requestData(); - }, - error: function() { - self.requestInProgress(false); + }) + .fail(function() { var text = gettext("There was unexpected error while removing the printer profile, please consult the logs."); new PNotify({title: gettext("Saving failed"), text: text, type: "error", hide: false}); - } - }) + }) + .always(function() { + self.requestInProgress(false); + }); }; self.updateProfile = function(profile, callback) { @@ -273,26 +261,20 @@ $(function() { } self.requestInProgress(true); - - $.ajax({ - url: API_BASEURL + "printerprofiles/" + profile.id, - type: "PATCH", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify({profile: profile}), - success: function() { - self.requestInProgress(false); + OctoPrint.printerprofiles.update(profile.key, profile) + .done(function() { if (callback !== undefined) { callback(); } self.requestData(); - }, - error: function() { - self.requestInProgress(false); + }) + .fail(function() { var text = gettext("There was unexpected error while updating the printer profile, please consult the logs."); new PNotify({title: gettext("Saving failed"), text: text, type: "error", hide: false}); - } - }); + }) + .always(function() { + self.requestInProgress(false); + }); }; self.showEditProfileDialog = function(data) { diff --git a/src/octoprint/static/js/app/viewmodels/printerstate.js b/src/octoprint/static/js/app/viewmodels/printerstate.js index e764a003..d1bfa10a 100644 --- a/src/octoprint/static/js/app/viewmodels/printerstate.js +++ b/src/octoprint/static/js/app/viewmodels/printerstate.js @@ -198,45 +198,25 @@ $(function() { }; self.print = function() { - var restartCommand = function() { - self._jobCommand("restart"); - }; - if (self.isPaused()) { showConfirmationDialog({ message: gettext("This will restart the print job from the beginning."), - onproceed: function(e) { - restartCommand(); + onproceed: function() { + OctoPrint.job.restart(); } }); } else { - self._jobCommand("start"); + OctoPrint.job.start(); } - }; self.pause = function() { - self._jobCommand("pause"); + OctoPrint.job.pause(); }; self.cancel = function() { - self._jobCommand("cancel"); + OctoPrint.job.cancel(); }; - - self._jobCommand = function(command, callback) { - $.ajax({ - url: API_BASEURL + "job", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify({command: command}), - success: function(response) { - if (callback != undefined) { - callback(); - } - } - }); - } } OCTOPRINT_VIEWMODELS.push([ diff --git a/src/octoprint/static/js/app/viewmodels/settings.js b/src/octoprint/static/js/app/viewmodels/settings.js index 39b58432..f5c97ea2 100644 --- a/src/octoprint/static/js/app/viewmodels/settings.js +++ b/src/octoprint/static/js/app/viewmodels/settings.js @@ -225,18 +225,14 @@ $(function() { var errorText = gettext("Could not retrieve snapshot URL, please double check the URL"); var errorTitle = gettext("Snapshot test failed"); - $.ajax({ - url: API_BASEURL + "util/test", - type: "POST", - dataType: "json", - data: JSON.stringify({ - command: "url", - url: self.webcam_snapshotUrl(), - method: "GET", - response: true - }), - contentType: "application/json; charset=UTF-8", - success: function(response) { + + var data = { + url: self.webcam_snapshotUrl(), + method: "GET", + response: true + }; + OctoPrint.util.test("url", data) + .done(function(response) { $("i.icon-spinner", target).remove(); if (!response.result) { @@ -260,15 +256,14 @@ $(function() { title: gettext("Snapshot test"), message: $('

' + text + '

') }); - }, - error: function() { + }) + .fail(function() { $("i.icon-spinner", target).remove(); showMessageDialog({ title: errorTitle, message: errorText }); - } - }); + }); }; self.testWebcamFfmpegPath = function() { @@ -293,19 +288,13 @@ $(function() { }; var path = self.webcam_ffmpegPath(); - $.ajax({ - url: API_BASEURL + "util/test", - type: "POST", - dataType: "json", - data: JSON.stringify({ - command: "path", - path: path, - check_type: "file", - check_access: "x" - }), - contentType: "application/json; charset=UTF-8", - success: successCallback - }) + var data = { + path: path, + check_type: "file", + check_access: "x" + }; + OctoPrint.util.test("path", data) + .done(successCallback); }; self.onSettingsShown = function() { @@ -331,6 +320,7 @@ $(function() { dataType: "json", maxNumberOfFiles: 1, autoUpload: false, + headers: OctoPrint.getRequestHeaders(), add: function(e, data) { if (data.files.length == 0) { return false; @@ -418,11 +408,8 @@ $(function() { } self.receiving(true); - $.ajax({ - url: API_BASEURL + "settings", - type: "GET", - dataType: "json", - success: function(response) { + OctoPrint.settings.get() + .done(function(response) { if (callback) { self.callbacks.push(callback); } @@ -443,23 +430,15 @@ $(function() { self.receiving(false); self.callbacks = []; } - }, - error: function(xhr) { + }) + .fail(function() { self.receiving(false); - } - }); + }); }; self.requestTranslationData = function(callback) { - $.ajax({ - url: API_BASEURL + "languages", - type: "GET", - dataType: "json", - success: function(response) { - self.fromTranslationResponse(response); - if (callback) callback(); - } - }) + return OctoPrint.languages.list() + .done(self.fromTranslationResponse); }; self.fromTranslationResponse = function(response) { @@ -509,14 +488,8 @@ $(function() { }); self.deleteLanguagePack = function(locale, pack) { - $.ajax({ - url: API_BASEURL + "languages/" + locale + "/" + pack, - type: "DELETE", - dataType: "json", - success: function(response) { - self.fromTranslationResponse(response); - } - }) + OctoPrint.languages.delete(locale, pack) + .done(self.fromTranslationResponse); }; /** @@ -690,13 +663,8 @@ $(function() { data = getOnlyChangedData(self.getLocalData(), self.lastReceivedSettings); } - $.ajax({ - url: API_BASEURL + "settings", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify(data), - success: function(data, status, xhr) { + OctoPrint.settings.save(data) + .done(function(data, status, xhr) { self.receiving(true); self.sending(false); try { @@ -705,15 +673,14 @@ $(function() { } finally { self.receiving(false); } - }, - error: function(xhr, status, error) { + }) + .fail(function(xhr, status, error) { self.sending(false); if (options.error) options.error(xhr, status, error); - }, - complete: function(xhr, status) { + }) + .always(function(xhr, status) { if (options.complete) options.complete(xhr, status); - } - }); + }); }; self.onEventSettingsUpdated = function() { diff --git a/src/octoprint/static/js/app/viewmodels/slicing.js b/src/octoprint/static/js/app/viewmodels/slicing.js index eba0581a..c361b826 100644 --- a/src/octoprint/static/js/app/viewmodels/slicing.js +++ b/src/octoprint/static/js/app/viewmodels/slicing.js @@ -65,17 +65,13 @@ $(function() { }); self.requestData = function(callback) { - $.ajax({ - url: API_BASEURL + "slicing", - type: "GET", - dataType: "json", - success: function(data) { + OctoPrint.slicing.listAllSlicersAndProfiles() + .done(function(data) { self.fromResponse(data); if (callback !== undefined) { callback(); } - } - }); + }); }; self.fromResponse = function(data) { @@ -150,7 +146,6 @@ $(function() { } var data = { - command: "slice", slicer: self.slicer(), profile: self.profile(), printerProfile: self.printerProfile(), @@ -163,19 +158,14 @@ $(function() { data["select"] = true; } - $.ajax({ - url: API_BASEURL + "files/" + self.target + "/" + self.file, - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify(data) - }); + OctoPrint.files.slice(self.target, self.file, data) + .done(function() { + $("#slicing_configuration_dialog").modal("hide"); - $("#slicing_configuration_dialog").modal("hide"); - - self.gcodeFilename(undefined); - self.slicer(self.defaultSlicer); - self.profile(self.defaultProfile); + self.gcodeFilename(undefined); + self.slicer(self.defaultSlicer); + self.profile(self.defaultProfile); + }); }; self._sanitize = function(name) { @@ -196,4 +186,4 @@ $(function() { ["loginStateViewModel", "printerProfilesViewModel"], "#slicing_configuration_dialog" ]); -}); \ No newline at end of file +}); diff --git a/src/octoprint/static/js/app/viewmodels/temperature.js b/src/octoprint/static/js/app/viewmodels/temperature.js index 9b58d2ec..e9f51ece 100644 --- a/src/octoprint/static/js/app/viewmodels/temperature.js +++ b/src/octoprint/static/js/app/viewmodels/temperature.js @@ -268,87 +268,84 @@ $(function() { var value = item.newTarget(); if (!value) return; - self._sendToolCommand("target", - item.key(), - item.newTarget(), - function() {item.newTarget("");} - ); + var onSuccess = function() { + item.newTarget(""); + }; + + if (item.key() == "bed") { + self._setBedTemperature(value) + .done(onSuccess); + } else { + self._setToolTemperature(item.key(), value) + .done(onSuccess); + } }; self.setTargetFromProfile = function(item, profile) { if (!profile) return; - var value = undefined; - if (item.key() == "bed") { - value = profile.bed; - } else { - value = profile.extruder; - } + var onSuccess = function() { + item.newTarget(""); + }; - self._sendToolCommand("target", - item.key(), - value, - function() {item.newTarget("");} - ); + if (item.key() == "bed") { + self._setBedTemperature(profile.bed) + .done(onSuccess); + } else { + self._setToolTemperature(item.key(), profile.extruder) + .done(onSuccess); + } }; self.setTargetToZero = function(item) { - self._sendToolCommand("target", - item.key(), - 0, - function() {item.newTarget("");} - ); + var onSuccess = function() { + item.newTarget(""); + }; + + if (item.key() == "bed") { + self._setBedTemperature(0) + .done(onSuccess); + } else { + self._setToolTemperature(item.key(), 0) + .done(onSuccess); + } }; self.setOffset = function(item) { - self._sendToolCommand("offset", - item.key(), - item.newOffset(), - function() {item.newOffset("");} - ); - }; + var value = item.newOffset(); + if (!value) return; - self._sendToolCommand = function(command, type, temp, successCb, errorCb) { - var data = { - command: command + var onSuccess = function() { + item.newOffset(""); }; - var endpoint; - if (type == "bed") { - if ("target" == command) { - data["target"] = parseInt(temp); - } else if ("offset" == command) { - data["offset"] = parseInt(temp); - } else { - return; - } - - endpoint = "bed"; + if (item.key() == "bed") { + self._setBedOffset(value) + .done(onSuccess); } else { - var group; - if ("target" == command) { - group = "targets"; - } else if ("offset" == command) { - group = "offsets"; - } else { - return; - } - data[group] = {}; - data[group][type] = parseInt(temp); - - endpoint = "tool"; + self._setToolOffset(item.key(), value) + .done(onSuccess); } + }; - $.ajax({ - url: API_BASEURL + "printer/" + endpoint, - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify(data), - success: function() { if (successCb !== undefined) successCb(); }, - error: function() { if (errorCb !== undefined) errorCb(); } - }); + self._setToolTemperature = function(tool, temperature) { + var data = {}; + data[tool] = parseInt(temperature); + return OctoPrint.printer.setToolTargetTemperatures(data); + }; + self._setToolOffset = function(tool, offset) { + var data = {}; + data[tool] = parseInt(offset); + return OctoPrint.printer.setToolTemperatureOffsets(data); + }; + + self._setBedTemperature = function(temperature) { + return OctoPrint.printer.setBedTargetTemperature(parseInt(temperature)); + }; + + self._setBedOffset = function(offset) { + return OctoPrint.printer.setBedTemperatureOffset(parseInt(offset)); }; self.handleEnter = function(event, type, item) { @@ -375,4 +372,4 @@ $(function() { ["loginStateViewModel", "settingsViewModel"], "#temp" ]); -}); \ No newline at end of file +}); diff --git a/src/octoprint/static/js/app/viewmodels/terminal.js b/src/octoprint/static/js/app/viewmodels/terminal.js index d7ec494d..3da817a0 100644 --- a/src/octoprint/static/js/app/viewmodels/terminal.js +++ b/src/octoprint/static/js/app/viewmodels/terminal.js @@ -158,29 +158,18 @@ $(function() { } if (command) { - $.ajax({ - url: API_BASEURL + "printer/command", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify({"command": command}) - }); - - self.cmdHistory.push(command); - self.cmdHistory.slice(-300); // just to set a sane limit to how many manually entered commands will be saved... - self.cmdHistoryIdx = self.cmdHistory.length; - self.command(""); + OctoPrint.control.sendGcode(command) + .done(function() { + self.cmdHistory.push(command); + self.cmdHistory.slice(-300); // just to set a sane limit to how many manually entered commands will be saved... + self.cmdHistoryIdx = self.cmdHistory.length; + self.command(""); + }); } }; self.fakeAck = function() { - $.ajax({ - url: API_BASEURL + "connection", - type: "POST", - dataType: "json", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify({"command": "fake_ack"}) - }); + OctoPrint.printer.fakeAck(); }; self.handleKeyDown = function(event) { @@ -232,4 +221,4 @@ $(function() { ["loginStateViewModel", "settingsViewModel"], "#term" ]); -}); \ No newline at end of file +}); diff --git a/src/octoprint/static/js/app/viewmodels/timelapse.js b/src/octoprint/static/js/app/viewmodels/timelapse.js index ed4188b5..0b3a0950 100644 --- a/src/octoprint/static/js/app/viewmodels/timelapse.js +++ b/src/octoprint/static/js/app/viewmodels/timelapse.js @@ -34,20 +34,20 @@ $(function() { return self.isDirty() && self.isOperational() && !self.isPrinting() && self.loginState.isUser(); }); - self.isOperational.subscribe(function(newValue) { + self.isOperational.subscribe(function() { self.requestData(); }); - self.timelapseType.subscribe(function(newValue) { + self.timelapseType.subscribe(function() { self.isDirty(true); }); - self.timelapseTimedInterval.subscribe(function(newValue) { + self.timelapseTimedInterval.subscribe(function() { self.isDirty(true); }); - self.timelapsePostRoll.subscribe(function(newValue) { + self.timelapsePostRoll.subscribe(function() { self.isDirty(true); }); - self.timelapseFps.subscribe(function(newValue) { + self.timelapseFps.subscribe(function() { self.isDirty(true); }); @@ -83,12 +83,8 @@ $(function() { ); self.requestData = function() { - $.ajax({ - url: API_BASEURL + "timelapse", - type: "GET", - dataType: "json", - success: self.fromResponse - }); + OctoPrint.timelapse.get() + .done(self.fromResponse); }; self.fromResponse = function(response) { @@ -141,15 +137,11 @@ $(function() { }; self.removeFile = function(filename) { - $.ajax({ - url: API_BASEURL + "timelapse/" + filename, - type: "DELETE", - dataType: "json", - success: self.requestData - }); + OctoPrint.timelapse.delete(filename) + .done(self.requestData); }; - self.save = function(data, event) { + self.save = function() { var payload = { "type": self.timelapseType(), "postRoll": self.timelapsePostRoll(), @@ -161,20 +153,15 @@ $(function() { payload["interval"] = self.timelapseTimedInterval(); } - $.ajax({ - url: API_BASEURL + "timelapse", - type: "POST", - dataType: "json", - data: payload, - success: self.fromResponse - }); + OctoPrint.timelapse.saveConfig(payload) + .done(self.fromResponse); }; self.onDataUpdaterReconnect = function() { self.requestData(); }; - self.onEventMovieDone = function(payload) { + self.onEventMovieDone = function() { self.requestData(); }; diff --git a/src/octoprint/static/js/app/viewmodels/users.js b/src/octoprint/static/js/app/viewmodels/users.js index c341a067..235dd28d 100644 --- a/src/octoprint/static/js/app/viewmodels/users.js +++ b/src/octoprint/static/js/app/viewmodels/users.js @@ -60,12 +60,8 @@ $(function() { self.requestData = function() { if (!CONFIG_ACCESS_CONTROL) return; - $.ajax({ - url: API_BASEURL + "users", - type: "GET", - dataType: "json", - success: self.fromResponse - }); + OctoPrint.users.list() + .done(self.fromResponse); }; self.fromResponse = function(response) { @@ -83,12 +79,19 @@ $(function() { self.confirmAddUser = function() { if (!CONFIG_ACCESS_CONTROL) return; - var user = {name: self.editorUsername(), password: self.editorPassword(), admin: self.editorAdmin(), active: self.editorActive()}; - self.addUser(user, function() { - // close dialog - self.currentUser(undefined); - self.addUserDialog.modal("hide"); - }); + var user = { + name: self.editorUsername(), + password: self.editorPassword(), + admin: self.editorAdmin(), + active: self.editorActive() + }; + + self.addUser(user) + .done(function() { + // close dialog + self.currentUser(undefined); + self.addUserDialog.modal("hide"); + }); }; self.showEditUserDialog = function(user) { @@ -105,12 +108,12 @@ $(function() { user.active = self.editorActive(); user.admin = self.editorAdmin(); - // make AJAX call - self.updateUser(user, function() { - // close dialog - self.currentUser(undefined); - self.editUserDialog.modal("hide"); - }); + self.updateUser(user) + .done(function() { + // close dialog + self.currentUser(undefined); + self.editUserDialog.modal("hide"); + }); }; self.showChangePasswordDialog = function(user) { @@ -123,27 +126,30 @@ $(function() { self.confirmChangePassword = function() { if (!CONFIG_ACCESS_CONTROL) return; - self.updatePassword(self.currentUser().name, self.editorPassword(), function() { - // close dialog - self.currentUser(undefined); - self.changePasswordDialog.modal("hide"); - }); + self.updatePassword(self.currentUser().name, self.editorPassword()) + .done(function() { + // close dialog + self.currentUser(undefined); + self.changePasswordDialog.modal("hide"); + }); }; self.confirmGenerateApikey = function() { if (!CONFIG_ACCESS_CONTROL) return; - self.generateApikey(self.currentUser().name, function(response) { - self._updateApikey(response.apikey); - }) + self.generateApikey(self.currentUser().name) + .done(function(response) { + self._updateApikey(response.apikey); + }); }; self.confirmDeleteApikey = function() { if (!CONFIG_ACCESS_CONTROL) return; - self.deleteApikey(self.currentUser().name, function() { - self._updateApikey(undefined); - }) + self.deleteApikey(self.currentUser().name) + .done(function() { + self._updateApikey(undefined); + }); }; self._updateApikey = function(apikey) { @@ -159,108 +165,55 @@ $(function() { self.changePasswordDialog = $("#settings-usersDialogChangePassword"); }; - //~~ AJAX calls + //~~ API calls - self.addUser = function(user, callback) { - if (!CONFIG_ACCESS_CONTROL) return; - if (user === undefined) return; + self.addUser = function(user) { + if (!user) { + throw OctoPrint.InvalidArgumentError("user must be set"); + } - $.ajax({ - url: API_BASEURL + "users", - type: "POST", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify(user), - success: function(response) { - self.fromResponse(response); - if (callback) { - callback(response); - } - } - }); + return OctoPrint.users.add(user) + .done(self.fromResponse); }; - self.removeUser = function(user, callback) { - if (!CONFIG_ACCESS_CONTROL) return; - if (user === undefined) return; + self.removeUser = function(user) { + if (!user) { + throw OctoPrint.InvalidArgumentError("user must be set"); + } if (user.name == self.loginState.username()) { // we do not allow to delete ourselves - new PNotify({title: "Not possible", text: "You may not delete your own account.", type: "error"}); - return; + new PNotify({ + title: gettext("Not possible"), + text: gettext("You may not delete your own account."), + type: "error" + }); + return $.Deferred().reject("You may not delete your own account").promise(); } - $.ajax({ - url: API_BASEURL + "users/" + user.name, - type: "DELETE", - success: function(response) { - self.fromResponse(response); - if (callback) { - callback(response); - } - } - }); + return OctoPrint.users.delete(user.name) + .done(self.fromResponse); }; - self.updateUser = function(user, callback) { - if (!CONFIG_ACCESS_CONTROL) return; - if (user === undefined) return; + self.updateUser = function(user) { + if (!user) { + throw OctoPrint.InvalidArgumentError("user must be set"); + } - $.ajax({ - url: API_BASEURL + "users/" + user.name, - type: "PUT", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify(user), - success: function(response) { - self.fromResponse(response); - if (callback) { - callback(response); - } - } - }); + return OctoPrint.users.update(user.name, user.active, user.admin) + .done(self.fromResponse); }; - self.updatePassword = function(username, password, callback) { - if (!CONFIG_ACCESS_CONTROL) return; - - $.ajax({ - url: API_BASEURL + "users/" + username + "/password", - type: "PUT", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify({password: password}), - success: function(response) { - if (callback) { - callback(response); - } - } - }); + self.updatePassword = function(username, password) { + return OctoPrint.users.changePassword(username, password); }; - self.generateApikey = function(username, callback) { - if (!CONFIG_ACCESS_CONTROL) return; - - $.ajax({ - url: API_BASEURL + "users/" + username + "/apikey", - type: "POST", - success: function(response) { - if (callback) { - callback(response); - } - } - }); + self.generateApikey = function(username) { + return OctoPrint.users.generateApiKey(username); }; - self.deleteApikey = function(username, callback) { - if (!CONFIG_ACCESS_CONTROL) return; - - $.ajax({ - url: API_BASEURL + "users/" + username + "/apikey", - type: "DELETE", - success: function(response) { - if (callback) { - callback(response); - } - } - }); + self.deleteApikey = function(username) { + return OctoPrint.users.resetApiKey(username); }; self.onUserLoggedIn = function(user) { @@ -275,4 +228,4 @@ $(function() { ["loginStateViewModel"], [] ]); -}); \ No newline at end of file +}); diff --git a/src/octoprint/static/js/app/viewmodels/usersettings.js b/src/octoprint/static/js/app/viewmodels/usersettings.js index ed8d0a6a..99b79631 100644 --- a/src/octoprint/static/js/app/viewmodels/usersettings.js +++ b/src/octoprint/static/js/app/viewmodels/usersettings.js @@ -60,24 +60,17 @@ $(function() { "language": self.interface_language() } }; - self.updateSettings(self.currentUser().name, settings, function() { - // close dialog - self.currentUser(undefined); - self.userSettingsDialog.modal("hide"); - self.loginState.reloadUser(); - }); + self.updateSettings(self.currentUser().name, settings) + .done(function() { + // close dialog + self.currentUser(undefined); + self.userSettingsDialog.modal("hide"); + self.loginState.reloadUser(); + }); }; - self.updateSettings = function(username, settings, callback) { - if (!CONFIG_ACCESS_CONTROL) return; - - $.ajax({ - url: API_BASEURL + "users/" + username + "/settings", - type: "PATCH", - contentType: "application/json; charset=UTF-8", - data: JSON.stringify(settings), - success: callback - }); + self.updateSettings = function(username, settings) { + return OctoPrint.users.saveSettings(username, settings); }; self.saveEnabled = function() { diff --git a/src/octoprint/static/js/app/viewmodels/wizard.js b/src/octoprint/static/js/app/viewmodels/wizard.js index c15b11a3..54ca62e4 100644 --- a/src/octoprint/static/js/app/viewmodels/wizard.js +++ b/src/octoprint/static/js/app/viewmodels/wizard.js @@ -19,18 +19,19 @@ $(function() { self.showDialog = function() { if (!CONFIG_WIZARD || !(CONFIG_FIRST_RUN || self.loginState.isAdmin())) return; - self.getWizardDetails(function(response) { - callViewModels(self.allViewModels, "onWizardDetails", [response]); + self.getWizardDetails() + .done(function(response) { + callViewModels(self.allViewModels, "onWizardDetails", [response]); - if (!self.isDialogActive()) { - self.wizardDialog.modal({ - minHeight: function() { return Math.max($.fn.modal.defaults.maxHeight() - 80, 250); } - }).css({ - width: 'auto', - 'margin-left': function() { return -($(this).width() /2); } - }); - } - }); + if (!self.isDialogActive()) { + self.wizardDialog.modal({ + minHeight: function() { return Math.max($.fn.modal.defaults.maxHeight() - 80, 250); } + }).css({ + width: 'auto', + 'margin-left': function() { return -($(this).width() /2); } + }); + } + }); }; self.closeDialog = function() { @@ -121,53 +122,34 @@ $(function() { // then reload = (method() == "reload") || reload; }); - self.finishWizard(function() { - self.closeDialog(); - if (reload) { - log.info("Wizard requested reloading"); - location.reload(true); - } - }); + self.finishWizard() + .done(function() { + self.closeDialog(); + if (reload) { + log.info("Wizard requested reloading"); + location.reload(true); + } + }); } } }); self.showDialog(); }; - self.getWizardDetails = function(callback) { - if (!callback) return; - - $.ajax({ - url: API_BASEURL + "setup/wizard", - type: "GET", - dataType: "json", - success: function(response) { + self.getWizardDetails = function() { + return OctoPrint.wizard.get() + .done(function(response) { self.wizards = _.filter(_.keys(response), function(key) { return response[key] && response[key]["required"] && !response[key]["ignored"]; }); - if (callback) { - callback(response); - } - } - }); + }); }; - self.finishWizard = function(callback) { + self.finishWizard = function() { self.finishing = true; - self.settingsViewModel.saveData(); - $.ajax({ - url: API_BASEURL + "setup/wizard", - type: "POST", - dataType: "json", - data: JSON.stringify({handled: self.wizards}), - contentType: "application/json; charset=UTF-8", - success: function() { + return OctoPrint.wizard.finish(self.wizards) + .always(function() { self.finishing = false; - callback(); - }, - failure: function() { - self.finishing = false; - } - }) + }); }; self.onSettingsPreventRefresh = function() { diff --git a/src/octoprint/templates/javascripts.jinja2 b/src/octoprint/templates/javascripts.jinja2 index acad1952..f69b158c 100644 --- a/src/octoprint/templates/javascripts.jinja2 +++ b/src/octoprint/templates/javascripts.jinja2 @@ -2,6 +2,10 @@ {% endassets %} +{% assets "js_client" %} + +{% endassets %} + {% assets "js_app" %} {% endassets %} From eafca5d77a1d0e891ab2569f80f5b53d7a777ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Fri, 25 Sep 2015 17:09:07 +0200 Subject: [PATCH 05/25] Some bug fixing of client migration --- .../pluginmanager/static/js/pluginmanager.js | 10 +++++----- src/octoprint/server/__init__.py | 2 +- src/octoprint/server/api/__init__.py | 9 +++++++-- .../js/app/client/{octoprint.js => base.js} | 0 .../static/js/app/client/settings.js | 20 +++++++++++++++++++ 5 files changed, 33 insertions(+), 8 deletions(-) rename src/octoprint/static/js/app/client/{octoprint.js => base.js} (100%) diff --git a/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js b/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js index 476434e6..00ba335d 100644 --- a/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js +++ b/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js @@ -20,7 +20,7 @@ $(function() { url: pluginUrl, dependency_links: !!dependencyLinks }; - return OctoPrint.simpleApiCommand(plugin, "install", data, opts); + return OctoPrint.simpleApiCommand("pluginmanager", "install", data, opts); }; exports.reinstall = function(plugin, pluginUrl, dependencyLinks, opts) { @@ -30,28 +30,28 @@ $(function() { reinstall: plugin, force: true }; - return OctoPrint.simpleApiCommand(plugin, "install", data, opts); + return OctoPrint.simpleApiCommand("pluginmanager", "install", data, opts); }; exports.uninstall = function(plugin, opts) { var data = { plugin: plugin }; - return OctoPrint.simpleApiCommand(plugin, "uninstall", data, opts); + return OctoPrint.simpleApiCommand("pluginmanager", "uninstall", data, opts); }; exports.enable = function(plugin, opts) { var data = { plugin: plugin }; - return OctoPrint.simpleApiCommand(plugin, "enable", data, opts); + return OctoPrint.simpleApiCommand("pluginmanager", "enable", data, opts); }; exports.disable = function(plugin, opts) { var data = { plugin: plugin }; - return OctoPrint.simpleApiCommand(plugin, "disable", data, opts); + return OctoPrint.simpleApiCommand("pluginmanager", "disable", data, opts); }; exports.upload = function(file) { diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index ed303df8..4d1a04b7 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -913,7 +913,7 @@ class Server(object): "js/lib/sockjs-0.3.4.min.js" ] js_client = [ - "js/app/client/octoprint.js", + "js/app/client/base.js", "js/app/client/socket.js", "js/app/client/browser.js", "js/app/client/connection.js", diff --git a/src/octoprint/server/api/__init__.py b/src/octoprint/server/api/__init__.py index 9d953edf..8f6d6db4 100644 --- a/src/octoprint/server/api/__init__.py +++ b/src/octoprint/server/api/__init__.py @@ -185,8 +185,13 @@ def apiVersion(): @admin_permission.require(403) def performSystemAction(): logger = logging.getLogger(__name__) - if "action" in request.values.keys(): - action = request.values["action"] + + data = request.values + if hasattr(request, "json") and request.json: + data = request.json + + if "action" in data: + action = data["action"] available_actions = s().get(["system", "actions"]) for availableAction in available_actions: if availableAction["action"] == action: diff --git a/src/octoprint/static/js/app/client/octoprint.js b/src/octoprint/static/js/app/client/base.js similarity index 100% rename from src/octoprint/static/js/app/client/octoprint.js rename to src/octoprint/static/js/app/client/base.js diff --git a/src/octoprint/static/js/app/client/settings.js b/src/octoprint/static/js/app/client/settings.js index cf701699..b0c2b423 100644 --- a/src/octoprint/static/js/app/client/settings.js +++ b/src/octoprint/static/js/app/client/settings.js @@ -12,5 +12,25 @@ OctoPrint.settings = (function($, _) { return OctoPrint.postJson(url, settings, opts); }; + exports.getPluginSettings = function(plugin, opts) { + return exports.get(opts) + .then(function(settings, statusText, request) { + if (!settings.plugins || !settings.plugins[plugin]) { + return $.Deferred() + .reject(request, "dataerror", "No settings for plugin " + plugin) + .promise(); + } else { + return settings.plugins[plugin]; + } + }); + }; + + exports.savePluginSettings = function(plugin, settings, opts) { + var data = {}; + data["plugins"] = {}; + data["plugins"][plugin] = settings; + return exports.save(data, opts); + }; + return exports; })($, _); From 1a469e1c9747048c9ec41e44384cbba682af25fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 28 Sep 2015 17:06:08 +0200 Subject: [PATCH 06/25] Take login data from data, not request.values That was a left-over from the previous implementation... --- src/octoprint/server/api/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/octoprint/server/api/__init__.py b/src/octoprint/server/api/__init__.py index 8f6d6db4..48e8e36e 100644 --- a/src/octoprint/server/api/__init__.py +++ b/src/octoprint/server/api/__init__.py @@ -227,10 +227,10 @@ def login(): data = request.json if octoprint.server.userManager is not None and "user" in data and "pass" in data: - username = request.values["user"] - password = request.values["pass"] + username = data["user"] + password = data["pass"] - if "remember" in request.values.keys() and request.values["remember"] == "true": + if "remember" in data and data["remember"] in valid_boolean_trues: remember = True else: remember = False From c5f0ccdb941d5f021aed1ec33d53afe15d017a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 28 Sep 2015 17:07:37 +0200 Subject: [PATCH 07/25] Migrated client to module factory pattern This should _hopefully_ also make it compatible to AMD implementations, but I have to admit that I haven't tried that yet... --- .../pluginmanager/static/js/pluginmanager.js | 129 ++++--- .../static/js/softwareupdate.js | 74 ++-- src/octoprint/static/js/app/client/base.js | 96 ++--- src/octoprint/static/js/app/client/browser.js | 47 ++- .../static/js/app/client/connection.js | 44 ++- src/octoprint/static/js/app/client/control.js | 80 ++-- src/octoprint/static/js/app/client/files.js | 115 +++--- src/octoprint/static/js/app/client/job.js | 54 +-- .../static/js/app/client/languages.js | 36 +- src/octoprint/static/js/app/client/logs.js | 38 +- src/octoprint/static/js/app/client/printer.js | 362 +++++++++--------- .../static/js/app/client/printerprofiles.js | 58 +-- .../static/js/app/client/settings.js | 57 +-- src/octoprint/static/js/app/client/slicing.js | 61 +-- src/octoprint/static/js/app/client/socket.js | 12 +- .../static/js/app/client/timelapse.js | 84 ++-- src/octoprint/static/js/app/client/users.js | 158 +++++--- src/octoprint/static/js/app/client/util.js | 50 ++- src/octoprint/static/js/app/client/wizard.js | 27 +- src/octoprint/static/js/app/main.js | 2 + 20 files changed, 878 insertions(+), 706 deletions(-) diff --git a/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js b/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js index 00ba335d..254b29d5 100644 --- a/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js +++ b/src/octoprint/plugins/pluginmanager/static/js/pluginmanager.js @@ -1,66 +1,71 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { + var exports = {}; + + exports.get = function(refresh, opts) { + return OctoPrint.get(OctoPrint.getSimpleApiUrl("pluginmanager") + ((refresh) ? "?refresh_repository=true" : ""), opts); + }; + + exports.getWithRefresh = function(opts) { + return exports.get(true, opts); + }; + + exports.getWithoutRefresh = function(opts) { + return exports.get(false, opts); + }; + + exports.install = function(pluginUrl, dependencyLinks, opts) { + var data = { + url: pluginUrl, + dependency_links: !!dependencyLinks + }; + return OctoPrint.simpleApiCommand("pluginmanager", "install", data, opts); + }; + + exports.reinstall = function(plugin, pluginUrl, dependencyLinks, opts) { + var data = { + url: pluginUrl, + dependency_links: !!dependencyLinks, + reinstall: plugin, + force: true + }; + return OctoPrint.simpleApiCommand("pluginmanager", "install", data, opts); + }; + + exports.uninstall = function(plugin, opts) { + var data = { + plugin: plugin + }; + return OctoPrint.simpleApiCommand("pluginmanager", "uninstall", data, opts); + }; + + exports.enable = function(plugin, opts) { + var data = { + plugin: plugin + }; + return OctoPrint.simpleApiCommand("pluginmanager", "enable", data, opts); + }; + + exports.disable = function(plugin, opts) { + var data = { + plugin: plugin + }; + return OctoPrint.simpleApiCommand("pluginmanager", "disable", data, opts); + }; + + exports.upload = function(file) { + return OctoPrint.upload(OctoPrint.getBlueprintUrl("pluginmanager") + "upload_archive", file); + }; + + OctoPrint.plugins.pluginmanager = exports; +}); + $(function() { - - OctoPrint.plugins.pluginmanager = (function($, _) { - var exports = {}; - - exports.get = function(refresh, opts) { - return OctoPrint.get(OctoPrint.getSimpleApiUrl("pluginmanager") + ((refresh) ? "?refresh_repository=true" : ""), opts); - }; - - exports.getWithRefresh = function(opts) { - return exports.get(true, opts); - }; - - exports.getWithoutRefresh = function(opts) { - return exports.get(false, opts); - }; - - exports.install = function(pluginUrl, dependencyLinks, opts) { - var data = { - url: pluginUrl, - dependency_links: !!dependencyLinks - }; - return OctoPrint.simpleApiCommand("pluginmanager", "install", data, opts); - }; - - exports.reinstall = function(plugin, pluginUrl, dependencyLinks, opts) { - var data = { - url: pluginUrl, - dependency_links: !!dependencyLinks, - reinstall: plugin, - force: true - }; - return OctoPrint.simpleApiCommand("pluginmanager", "install", data, opts); - }; - - exports.uninstall = function(plugin, opts) { - var data = { - plugin: plugin - }; - return OctoPrint.simpleApiCommand("pluginmanager", "uninstall", data, opts); - }; - - exports.enable = function(plugin, opts) { - var data = { - plugin: plugin - }; - return OctoPrint.simpleApiCommand("pluginmanager", "enable", data, opts); - }; - - exports.disable = function(plugin, opts) { - var data = { - plugin: plugin - }; - return OctoPrint.simpleApiCommand("pluginmanager", "disable", data, opts); - }; - - exports.upload = function(file) { - return OctoPrint.upload(OctoPrint.getBlueprintUrl("pluginmanager") + "upload_archive", file); - }; - - return exports; - })($, _); - function PluginManagerViewModel(parameters) { var self = this; diff --git a/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js b/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js index 4be1e147..8747c25e 100644 --- a/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js +++ b/src/octoprint/plugins/softwareupdate/static/js/softwareupdate.js @@ -1,38 +1,44 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { + var exports = {}; + + var url = OctoPrint.getBlueprintUrl("softwareupdate"); + var checkUrl = url + "check"; + var updateUrl = url + "update"; + + exports.check = function(force, opts) { + return OctoPrint.get(checkUrl + ((!!force) ? "?force=true" : ""), opts); + }; + + exports.update = function(entries, force, opts) { + entries = entries || []; + if (typeof entries == "string") { + entries = [entries]; + } + + var data = { + entries: entries, + force: !!force + }; + return OctoPrint.postJson(updateUrl, data, opts); + }; + + exports.updateAll = function(force, opts) { + var data = { + force: !!force + }; + return OctoPrint.postJson(updateUrl, data, opts); + }; + + OctoPrint.plugins.softwareupdate = exports; +}); + $(function() { - OctoPrint.plugins.softwareupdate = (function($, _) { - var exports = {}; - - var url = OctoPrint.getBlueprintUrl("softwareupdate"); - var checkUrl = url + "check"; - var updateUrl = url + "update"; - - exports.check = function(force, opts) { - return OctoPrint.get(checkUrl + ((!!force) ? "?force=true" : ""), opts); - }; - - exports.update = function(entries, force, opts) { - entries = entries || []; - if (typeof entries == "string") { - entries = [entries]; - } - - var data = { - entries: entries, - force: !!force - }; - return OctoPrint.postJson(updateUrl, data, opts); - }; - - exports.updateAll = function(force, opts) { - var data = { - force: !!force - }; - return OctoPrint.postJson(updateUrl, data, opts); - }; - - return exports; - })($, _); - function SoftwareUpdateViewModel(parameters) { var self = this; diff --git a/src/octoprint/static/js/app/client/base.js b/src/octoprint/static/js/app/client/base.js index b2ce0346..1637c0eb 100644 --- a/src/octoprint/static/js/app/client/base.js +++ b/src/octoprint/static/js/app/client/base.js @@ -1,5 +1,11 @@ -var OctoPrint = (function($, _) { - var exports = {}; +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define("OctoPrint", ["jquery", "lodash"], factory); + } else { + global.OctoPrint = factory(window.$, window._); + } +})(window || this, function($, _) { + var OctoPrint = {}; var noCache = function(opts) { opts = opts || {}; @@ -20,31 +26,31 @@ var OctoPrint = (function($, _) { return params; }; - exports.options = { + OctoPrint.options = { "baseurl": undefined, "apikey": undefined }; - exports.plugins = {}; + OctoPrint.plugins = {}; - exports.getBaseUrl = function() { - var url = exports.options.baseurl; + OctoPrint.getBaseUrl = function() { + var url = OctoPrint.options.baseurl; if (!_.endsWith(url, "/")) { url = url + "/"; } return url; }; - exports.getRequestHeaders = function(additional) { + OctoPrint.getRequestHeaders = function(additional) { additional = additional || {}; var headers = $.extend({}, additional); - headers["X-Api-Key"] = exports.options.apikey; + headers["X-Api-Key"] = OctoPrint.options.apikey; return headers; }; - exports.ajax = function(method, url, opts) { + OctoPrint.ajax = function(method, url, opts) { opts = opts || {}; method = opts.method || method || "GET"; @@ -52,10 +58,10 @@ var OctoPrint = (function($, _) { var urlToCall = url; if (!_.startsWith(url, "http://") && !_.startsWith(url, "https://")) { - urlToCall = exports.getBaseUrl() + url; + urlToCall = OctoPrint.getBaseUrl() + url; } - var headers = exports.getRequestHeaders(opts.headers); + var headers = OctoPrint.getRequestHeaders(opts.headers); var params = $.extend({}, opts); params.type = method; @@ -65,54 +71,54 @@ var OctoPrint = (function($, _) { return $.ajax(urlToCall, params); }; - exports.ajaxWithData = function(method, url, data, opts) { + OctoPrint.ajaxWithData = function(method, url, data, opts) { opts = opts || {}; var params = $.extend({}, opts); params.data = data; - return exports.ajax(method, url, params); + return OctoPrint.ajax(method, url, params); }; - exports.get = function(url, opts) { - return exports.ajax("GET", url, opts); + OctoPrint.get = function(url, opts) { + return OctoPrint.ajax("GET", url, opts); }; - exports.post = function(url, data, opts) { - return exports.ajaxWithData("POST", url, data, noCache(opts)); + OctoPrint.post = function(url, data, opts) { + return OctoPrint.ajaxWithData("POST", url, data, noCache(opts)); }; - exports.postJson = function(url, data, opts) { - return exports.post(url, JSON.stringify(data), contentTypeJson(opts)); + OctoPrint.postJson = function(url, data, opts) { + return OctoPrint.post(url, JSON.stringify(data), contentTypeJson(opts)); }; - exports.put = function(url, data, opts) { - return exports.ajaxWithData("PUT", url, data, noCache(opts)); + OctoPrint.put = function(url, data, opts) { + return OctoPrint.ajaxWithData("PUT", url, data, noCache(opts)); }; - exports.putJson = function(url, data, opts) { - return exports.put(url, data, contentTypeJson(opts)); + OctoPrint.putJson = function(url, data, opts) { + return OctoPrint.put(url, data, contentTypeJson(opts)); }; - exports.patch = function(url, data, opts) { - return exports.ajaxWithData("PATCH", url, data, noCache(opts)); + OctoPrint.patch = function(url, data, opts) { + return OctoPrint.ajaxWithData("PATCH", url, data, noCache(opts)); }; - exports.patchJson = function(url, data, opts) { - return exports.patch(url, JSON.stringify(data), contentTypeJson(opts)); + OctoPrint.patchJson = function(url, data, opts) { + return OctoPrint.patch(url, JSON.stringify(data), contentTypeJson(opts)); }; - exports.delete = function(url, opts) { - return exports.ajax("DELETE", url, opts); + OctoPrint.delete = function(url, opts) { + return OctoPrint.ajax("DELETE", url, opts); }; - exports.download = function(url, opts) { + OctoPrint.download = function(url, opts) { var params = $.extend({}, opts || {}); params.dataType = "text"; - return exports.get(url, params); + return OctoPrint.get(url, params); }; - exports.upload = function(url, file, filename, additional) { + OctoPrint.upload = function(url, file, filename, additional) { additional = additional || {}; var fileData; @@ -187,38 +193,38 @@ var OctoPrint = (function($, _) { return deferred.promise(); }; - exports.issueCommand = function(url, command, payload, opts) { + OctoPrint.issueCommand = function(url, command, payload, opts) { payload = payload || {}; var data = $.extend({}, payload); data.command = command; - return exports.postJson(url, data, opts); + return OctoPrint.postJson(url, data, opts); }; - exports.getSimpleApiUrl = function(plugin) { + OctoPrint.getSimpleApiUrl = function(plugin) { return "api/plugin/" + plugin; }; - exports.simpleApiGet = function(plugin, opts) { - return OctoPrint.get(exports.getSimpleApiUrl(plugin), opts); + OctoPrint.simpleApiGet = function(plugin, opts) { + return OctoPrint.get(OctoPrint.getSimpleApiUrl(plugin), opts); }; - exports.simpleApiCommand = function(plugin, command, payload, opts) { - return OctoPrint.issueCommand(exports.getSimpleApiUrl(plugin), command, payload, opts); + OctoPrint.simpleApiCommand = function(plugin, command, payload, opts) { + return OctoPrint.issueCommand(OctoPrint.getSimpleApiUrl(plugin), command, payload, opts); }; - exports.getBlueprintUrl = function(plugin) { + OctoPrint.getBlueprintUrl = function(plugin) { return "plugin/" + plugin + "/"; }; - exports.createRejectedDeferred = function() { + OctoPrint.createRejectedDeferred = function() { var deferred = $.Deferred(); deferred.reject(arguments); return deferred; }; - exports.createCustomException = function(name) { + OctoPrint.createCustomException = function(name) { var constructor; if (_.isFunction(name)) { @@ -237,7 +243,7 @@ var OctoPrint = (function($, _) { return constructor; }; - exports.InvalidArgumentError = exports.createCustomException("InvalidArgumentError"); + OctoPrint.InvalidArgumentError = OctoPrint.createCustomException("InvalidArgumentError"); - return exports; -})($, _); + return OctoPrint; +}); diff --git a/src/octoprint/static/js/app/client/browser.js b/src/octoprint/static/js/app/client/browser.js index bb7b8c5a..ac791b6f 100644 --- a/src/octoprint/static/js/app/client/browser.js +++ b/src/octoprint/static/js/app/client/browser.js @@ -1,22 +1,29 @@ -OctoPrint.browser = (function($, _) { - var exports = {}; +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { + var loginUrl = "api/login"; + var logoutUrl = "api/logout"; - exports.login = function(username, password, remember, opts) { - var data = { - user: username, - pass: password, - remember: !!remember - }; - return OctoPrint.postJson("api/login", data, opts); + OctoPrint.browser = { + login: function(username, password, remember, opts) { + var data = { + user: username, + pass: password, + remember: !!remember + }; + return OctoPrint.postJson(loginUrl, data, opts); + }, + + passiveLogin: function(opts) { + return OctoPrint.postJson(loginUrl, {passive: true}, opts); + }, + + logout: function(opts) { + return OctoPrint.postJson(logoutUrl, {}, opts); + } }; - - exports.passiveLogin = function(opts) { - return OctoPrint.postJson("api/login", {passive: true}, opts); - }; - - exports.logout = function(opts) { - return OctoPrint.postJson("api/logout", {}, opts); - }; - - return exports; -})($, _); +}); diff --git a/src/octoprint/static/js/app/client/connection.js b/src/octoprint/static/js/app/client/connection.js index 197c1c2e..98ca4c67 100644 --- a/src/octoprint/static/js/app/client/connection.js +++ b/src/octoprint/static/js/app/client/connection.js @@ -1,25 +1,27 @@ -OctoPrint.connection = (function() { - var exports = {}; +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { + var url = "api/connection"; - exports.getSettings = function(opts) { - return OctoPrint.get("api/connection", opts); - }; + OctoPrint.connection = { + getSettings: function(opts) { + return OctoPrint.get(url, opts); + }, - exports.connect = function(data, opts) { - return exports.issueCommand("connect", data || {}, opts); - }; + connect: function(data, opts) { + return OctoPrint.issueCommand(url, "connect", data || {}, opts); + }, - exports.disconnect = function(opts) { - return exports.issueCommand("disconnect", {}, opts); - }; + disconnect: function(opts) { + return OctoPrint.issueCommand(url, "disconnect", {}, opts); + }, - exports.fakeAck = function(opts) { - return exports.issueCommand("fake_ack", {}, opts); - }; - - exports.issueCommand = function(command, data, opts) { - return OctoPrint.issueCommand("api/connection", command, data, opts); - }; - - return exports; -})($, _); + fakeAck: function(opts) { + return OctoPrint.issueCommand(url, "fake_ack", {}, opts); + } + } +}); diff --git a/src/octoprint/static/js/app/client/control.js b/src/octoprint/static/js/app/client/control.js index 4b9e9872..e724b51c 100644 --- a/src/octoprint/static/js/app/client/control.js +++ b/src/octoprint/static/js/app/client/control.js @@ -1,44 +1,48 @@ -OctoPrint.control = (function($, _) { - var exports = {}; - +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { var customUrl = "api/printer/command/custom"; var commandUrl = "api/printer/command"; - exports.getCustomControls = function(opts) { - return OctoPrint.get(customUrl, opts); - }; + OctoPrint.control = { + getCustomControls: function (opts) { + return OctoPrint.get(customUrl, opts); + }, - exports.sendGcode = function(commands, opts) { - commands = commands || []; + sendGcode: function (commands, opts) { + return exports.sendGcodeWithParameters(commands, undefined, opts); + }, - if (typeof commands === "string") { - commands = [commands]; + sendGcodeWithParameters: function (commands, parameters, opts) { + commands = commands || []; + parameters = parameters || {}; + + if (typeof commands === "string") { + commands = [commands]; + } + + return OctoPrint.postJson(commandUrl, { + commands: commands, + parameters: parameters + }, opts); + }, + + sendGcodeScript: function (script, context, opts) { + script = script || ""; + context = context || {}; + + return OctoPrint.postJson(commandUrl, { + script: script, + context: context + }, opts); + }, + + executeSystemCommand: function (action, opts) { + return OctoPrint.postJson("api/system", {action: action}, opts); } - - return OctoPrint.postJson(commandUrl, {commands: commands}, opts); - }; - - exports.sendGcodeWithParameters = function(commands, parameters, opts) { - commands = commands || []; - parameters = parameters || {}; - - if (typeof commands === "string") { - commands = [commands]; - } - - return OctoPrint.postJson(commandUrl, {commands: commands, parameters: parameters}, opts); - }; - - exports.sendGcodeScript = function(script, context, opts) { - script = script || ""; - context = context || {}; - - return OctoPrint.postJson(commandUrl, {script: script, context: context}, opts); - }; - - exports.executeSystemCommand = function(action, opts) { - return OctoPrint.postJson("api/system", {action: action}, opts); - }; - - return exports; -})($, _); + } +}); diff --git a/src/octoprint/static/js/app/client/files.js b/src/octoprint/static/js/app/client/files.js index bb0d6c0f..2e76f5f4 100644 --- a/src/octoprint/static/js/app/client/files.js +++ b/src/octoprint/static/js/app/client/files.js @@ -1,8 +1,21 @@ -OctoPrint.files = (function($, _) { - var exports = {}; +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define(["OctoPrint", "jquery"], factory); + } else { + // Browser globals: + factory(window.OctoPrint, window.jQuery); + } +})(function(OctoPrint, $) { + var url = "api/files"; + + var resourceForLocation = function(location) { + return url + "/" + location; + }; var resourceForFile = function(location, filename) { - return "api/files/" + location + "/" + filename; + return resourceForLocation(location) + "/" + filename; }; var issueFileCommand = function(location, filename, command, data, opts) { @@ -10,61 +23,61 @@ OctoPrint.files = (function($, _) { return OctoPrint.issueCommand(url, command, data, opts); }; - exports.list = function(opts) { - return OctoPrint.get("api/files", opts); - }; + OctoPrint.files = { + list: function (opts) { + return OctoPrint.get(url, opts); + }, - exports.listForLocation = function(location, opts) { - return OctoPrint.get("api/files/" + location, opts); - }; + listForLocation: function (location, opts) { + return OctoPrint.get(resourceForLocation(location), opts); + }, - exports.get = function(location, filename, opts) { - return OctoPrint.get(resourceForFile(location, filename), opts); - }; + get: function (location, filename, opts) { + return OctoPrint.get(resourceForFile(location, filename), opts); + }, - exports.select = function(location, filename, print, opts) { - print = print || false; + select: function (location, filename, print, opts) { + print = print || false; - var data = { - print: print - }; + var data = { + print: print + }; - return issueFileCommand(location, filename, "select", data, opts); - }; + return issueFileCommand(location, filename, "select", data, opts); + }, - exports.slice = function(location, filename, parameters, opts) { - return issueFileCommand(location, filename, "slice", - parameters || {}, opts); - }; + slice: function (location, filename, parameters, opts) { + return issueFileCommand(location, filename, "slice", + parameters || {}, opts); + }, - exports.delete = function(location, filename, opts) { - return OctoPrint.delete(resourceForFile(location, filename), opts); - }; + delete: function (location, filename, opts) { + return OctoPrint.delete(resourceForFile(location, filename), opts); + }, - exports.upload = function(location, file, data) { - data = data || {}; + upload: function (location, file, data) { + data = data || {}; - var filename = data.filename || undefined; - return OctoPrint.upload("api/files/" + location, file, filename, data); - }; + var filename = data.filename || undefined; + return OctoPrint.upload(resourceForLocation(location), file, filename, data); + }, - exports.download = function(location, filename, opts) { - var deferred = $.Deferred(); - exports.get(location, filename, opts) - .done(function(response) { - OctoPrint.download(response.refs.download, opts) - .done(function() { - deferred.resolve.apply(null, arguments); - }) - .fail(function() { - deferred.reject.apply(null, arguments); - }); - }) - .fail(function() { - deferred.reject.apply(null, arguments); - }); - return deferred.promise(); - }; - - return exports; -})($, _); + download: function (location, filename, opts) { + var deferred = $.Deferred(); + exports.get(location, filename, opts) + .done(function (response) { + OctoPrint.download(response.refs.download, opts) + .done(function () { + deferred.resolve.apply(null, arguments); + }) + .fail(function () { + deferred.reject.apply(null, arguments); + }); + }) + .fail(function () { + deferred.reject.apply(null, arguments); + }); + return deferred.promise(); + } + } +}); diff --git a/src/octoprint/static/js/app/client/job.js b/src/octoprint/static/js/app/client/job.js index 84497dec..133058cb 100644 --- a/src/octoprint/static/js/app/client/job.js +++ b/src/octoprint/static/js/app/client/job.js @@ -1,31 +1,31 @@ -OctoPrint.job = (function($, _) { - var exports = {}; - +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { var url = "api/job"; - var issueCommand = function(command, data, opts) { - return OctoPrint.issueCommand(url, command, data, opts); + var issueCommand = function(command, opts) { + return OctoPrint.issueCommand(url, command, {}, opts); }; - exports.get = function(opts) { - return OctoPrint.get(url, opts); - }; - - exports.start = function(opts) { - return issueCommand("start", {}, opts); - }; - - exports.restart = function(opts) { - return issueCommand("restart", {}, opts); - }; - - exports.pause = function(opts) { - return issueCommand("pause", {}, opts); - }; - - exports.cancel = function(opts) { - return issueCommand("cancel", {}, opts); - }; - - return exports; -})($, _); + OctoPrint.job = { + get: function(opts) { + return OctoPrint.get(url, opts); + }, + start: function(opts) { + return issueCommand("start", opts); + }, + restart: function(opts) { + return issueCommand("restart", opts); + }, + pause: function(opts) { + return issueCommand("pause", opts); + }, + cancel: function(opts) { + return issueCommand("cancel", opts); + } + } +}); diff --git a/src/octoprint/static/js/app/client/languages.js b/src/octoprint/static/js/app/client/languages.js index d9bc3ac6..2ebec0d5 100644 --- a/src/octoprint/static/js/app/client/languages.js +++ b/src/octoprint/static/js/app/client/languages.js @@ -1,20 +1,22 @@ -OctoPrint.languages = (function($, _) { - var exports = {}; - +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { var url = "api/languages"; - exports.list = function(opt) { - return OctoPrint.get(url, opt); + OctoPrint.languages = { + list: function(opts) { + return OctoPrint.get(url, opts); + }, + upload: function(file) { + return OctoPrint.upload(url, file); + }, + delete: function(locale, pack, opts) { + var packUrl = url + "/" + locale + "/" + pack; + return OctoPrint.delete(packUrl, opts); + } }; - - exports.upload = function(file) { - return OctoPrint.upload(url, file); - }; - - exports.delete = function(locale, pack, opts) { - var packUrl = url + "/" + locale + "/" + pack; - return OctoPrint.delete(packUrl, opts); - }; - - return exports; -})($, _); +}); diff --git a/src/octoprint/static/js/app/client/logs.js b/src/octoprint/static/js/app/client/logs.js index 609ca246..a1e652e4 100644 --- a/src/octoprint/static/js/app/client/logs.js +++ b/src/octoprint/static/js/app/client/logs.js @@ -1,21 +1,25 @@ -OctoPrint.logs = (function($, _) { - var exports = {}; - +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { var url = "api/logs"; - exports.list = function(opts) { - return OctoPrint.get(url, opts); - }; + OctoPrint.logs = { + list: function(opts) { + return OctoPrint.get(url, opts); + }, - exports.delete = function(file, opts) { - var fileUrl = url + "/" + file; - return OctoPrint.delete(fileUrl, opts); - }; + delete: function(file, opts) { + var fileUrl = url + "/" + file; + return OctoPrint.delete(fileUrl, opts); + }, - exports.download = function(file, opts) { - var fileUrl = url + "/" + file; - return OctoPrint.download(fileUrl, opts); - }; - - return exports; -})($, _); + download: function(file, opts) { + var fileUrl = url + "/" + file; + return OctoPrint.download(fileUrl, opts); + } + } +}); diff --git a/src/octoprint/static/js/app/client/printer.js b/src/octoprint/static/js/app/client/printer.js index 96217dde..844a438a 100644 --- a/src/octoprint/static/js/app/client/printer.js +++ b/src/octoprint/static/js/app/client/printer.js @@ -1,197 +1,207 @@ -OctoPrint.printer = (function($, _) { - var exports = {}; +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { + var url = "api/printer"; + var printheadUrl = url + "/printhead"; + var toolUrl = url + "/tool"; + var bedUrl = url + "/bed"; + var sdUrl = url + "/sd"; - var issuePrintheadCommand = function(command, payload, opts) { - return OctoPrint.issueCommand("api/printer/printhead", command, payload, opts); + var issuePrintheadCommand = function (command, payload, opts) { + return OctoPrint.issueCommand(printheadUrl, command, payload, opts); }; - var issueToolCommand = function(command, payload, opts) { - return OctoPrint.issueCommand("api/printer/tool", command, payload, opts); + var issueToolCommand = function (command, payload, opts) { + return OctoPrint.issueCommand(toolUrl, command, payload, opts); }; - var issueBedCommand = function(command, payload, opts) { - return OctoPrint.issueCommand("api/printer/bed", command, payload, opts); + var issueBedCommand = function (command, payload, opts) { + return OctoPrint.issueCommand(bedUrl, command, payload, opts); }; - var issueSdCommand = function(command, payload, opts) { - return OctoPrint.issueCommand("api/printer/sd", command, payload, opts); + var issueSdCommand = function (command, payload, opts) { + return OctoPrint.issueCommand(sdUrl, command, payload, opts); }; - exports.getFullState = function(data, opts) { - data = data || {}; + OctoPrint.printer = { + getFullState: function (data, opts) { + data = data || {}; - var history = data.history || undefined; - var limit = data.limit || undefined; - var exclude = data.exclude || undefined; + var history = data.history || undefined; + var limit = data.limit || undefined; + var exclude = data.exclude || undefined; - var url = "api/printer"; - if (history || exclude) { - url += "?"; - if (history) { - url += "history=true&"; - if (limit) { - url += "limit=" + limit + "&"; + var getUrl = url; + if (history || exclude) { + getUrl += "?"; + if (history) { + getUrl += "history=true&"; + if (limit) { + getUrl += "limit=" + limit + "&"; + } + } + + if (exclude) { + getUrl += "exclude=" + exclude.join(",") + "&"; } } - if (exclude) { - url += "exclude=" + exclude.join(",") + "&"; + return OctoPrint.get(getUrl, opts); + }, + + getToolState: function (data, opts) { + data = data || {}; + + var history = data.history || undefined; + var limit = data.limit || undefined; + + var getUrl = toolUrl; + if (history) { + getUrl += "?history=true"; + if (limit) { + getUrl += "&limit=" + limit; + } } - } - return OctoPrint.get(url, opts); - }; + return OctoPrint.get(getUrl, opts); + }, - exports.getToolState = function(data, opts) { - data = data || {}; + getBedState: function (data, opts) { + data = data || {}; - var history = data.history || undefined; - var limit = data.limit || undefined; + var history = data.history || undefined; + var limit = data.limit || undefined; - var url = "api/printer/tool"; - if (history) { - url += "?history=true"; - if (limit) { - url += "&limit=" + limit; + var getUrl = bedUrl; + if (history) { + getUrl += "?history=true"; + if (limit) { + getUrl += "&limit=" + limit; + } } + + return OctoPrint.get(getUrl, opts); + }, + + getSdState: function (opts) { + return OctoPrint.get(sdUrl, opts); + }, + + jog: function (data, opts) { + data = data || {}; + + var payload = {}; + if (data.x) payload.x = data.x; + if (data.y) payload.y = data.y; + if (data.z) payload.z = data.z; + + return issuePrintheadCommand("jog", payload, opts); + }, + + home: function (axes, opts) { + axes = axes || []; + + var payload = { + axes: axes + }; + + return issuePrintheadCommand("home", payload, opts); + }, + + setFeedrate: function (factor, opts) { + factor = factor || 100; + + var payload = { + factor: factor + }; + + return issuePrintheadCommand("feedrate", payload, opts); + }, + + setToolTargetTemperatures: function (targets, opts) { + targets = targets || {}; + + var payload = { + targets: targets + }; + + return issueToolCommand("target", payload, opts); + }, + + setToolTemperatureOffsets: function (offsets, opts) { + offsets = offsets || {}; + + var payload = { + offsets: offsets + }; + + return issueToolCommand("offset", payload, opts); + }, + + selectTool: function (tool, opts) { + tool = tool || undefined; + + var payload = { + tool: tool + }; + + return issueToolCommand("select", payload, opts); + }, + + extrude: function (amount, opts) { + amount = amount || undefined; + + var payload = { + amount: amount + }; + + return issueToolCommand("extrude", payload, opts); + }, + + setFlowrate: function (factor, opts) { + factor = factor || 100; + + var payload = { + factor: factor + }; + + return issueToolCommand("flowrate", payload, opts); + }, + + setBedTargetTemperature: function (temperature, opts) { + temperature = temperature || 0; + + var payload = { + target: temperature + }; + + return issueBedCommand("target", payload, opts); + }, + + setBedTemperatureOffset: function (offset, opts) { + offset = offset || 0; + + var payload = { + offset: offset + }; + + return issueBedCommand("offset", payload, opts); + }, + + initSd: function (opts) { + return issueSdCommand("init", {}, opts); + }, + + refreshSd: function (opts) { + return issueSdCommand("refresh", {}, opts); + }, + + releaseSd: function (opts) { + return issueSdCommand("release", {}, opts); } - - return OctoPrint.get(url, opts); - }; - - exports.getBedState = function(data, opts) { - data = data || {}; - - var history = data.history || undefined; - var limit = data.limit || undefined; - - var url = "api/printer/bed"; - if (history) { - url += "?history=true"; - if (limit) { - url += "&limit=" + limit; - } - } - - return OctoPrint.get(url, opts); - }; - - exports.getSdState = function(opts) { - return OctoPrint.get("api/printer/sd", opts); - }; - - exports.jog = function(data, opts) { - data = data || {}; - - var payload = {}; - if (data.x) payload.x = data.x; - if (data.y) payload.y = data.y; - if (data.z) payload.z = data.z; - - return issuePrintheadCommand("jog", payload, opts); - }; - - exports.home = function(axes, opts) { - axes = axes || []; - - var payload = { - axes: axes - }; - - return issuePrintheadCommand("home", payload, opts); - }; - - exports.setFeedrate = function(factor, opts) { - factor = factor || 100; - - var payload = { - factor: factor - }; - - return issuePrintheadCommand("feedrate", payload, opts); - }; - - exports.setToolTargetTemperatures = function(targets, opts) { - targets = targets || {}; - - var payload = { - targets: targets - }; - - return issueToolCommand("target", payload, opts); - }; - - exports.setToolTemperatureOffsets = function(offsets, opts) { - offsets = offsets || {}; - - var payload = { - offsets: offsets - }; - - return issueToolCommand("offset", payload, opts); - }; - - exports.selectTool = function(tool, opts) { - tool = tool || undefined; - - var payload = { - tool: tool - }; - - return issueToolCommand("select", payload, opts); - }; - - exports.extrude = function(amount, opts) { - amount = amount || undefined; - - var payload = { - amount: amount - }; - - return issueToolCommand("extrude", payload, opts); - }; - - exports.setFlowrate = function(factor, opts) { - factor = factor || 100; - - var payload = { - factor: factor - }; - - return issueToolCommand("flowrate", payload, opts); - }; - - exports.setBedTargetTemperature = function(temperature, opts) { - temperature = temperature || 0; - - var payload = { - target: temperature - }; - - return issueBedCommand("target", payload, opts); - }; - - exports.setBedTemperatureOffset = function(offset, opts) { - offset = offset || 0; - - var payload = { - offset: offset - }; - - return issueBedCommand("offset", payload, opts); - }; - - exports.initSd = function(opts) { - return issueSdCommand("init", {}, opts); - }; - - exports.refreshSd = function(opts) { - return issueSdCommand("refresh", {}, opts); - }; - - exports.releaseSd = function(opts) { - return issueSdCommand("release", {}, opts); - }; - - return exports; -})($, _); + } +}); diff --git a/src/octoprint/static/js/app/client/printerprofiles.js b/src/octoprint/static/js/app/client/printerprofiles.js index 5f4c49c7..d03efb3e 100644 --- a/src/octoprint/static/js/app/client/printerprofiles.js +++ b/src/octoprint/static/js/app/client/printerprofiles.js @@ -1,37 +1,43 @@ -OctoPrint.printerprofiles = (function($, _) { - var exports = {}; - +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint", "jquery"], factory); + } else { + factory(window.OctoPrint, window.$); + } +})(window || this, function(OctoPrint, $) { var url = "api/printerprofiles"; - exports.get = function(opts) { - return OctoPrint.get(url, opts); + var profileUrl = function(profile) { + return url + "/" + profile; }; - exports.add = function(profile, additional, opts) { - profile = profile || {}; - additional = additional || {}; + OctoPrint.printerprofiles = { + get: function (opts) { + return OctoPrint.get(url, opts); + }, - var data = $.extend({}, additional); - data.profile = profile; + add: function (profile, additional, opts) { + profile = profile || {}; + additional = additional || {}; - return OctoPrint.postJson(url, data, opts); - }; + var data = $.extend({}, additional); + data.profile = profile; - exports.update = function(id, profile, additional, opts) { - profile = profile || {}; - additional = addtional || {}; + return OctoPrint.postJson(url, data, opts); + }, - var data = $.extend({}, additional); - data.profile = profile; + update: function (id, profile, additional, opts) { + profile = profile || {}; + additional = addtional || {}; - var profileUrl = url + "/" + id; - return OctoPrint.patchJson(profileUrl, data, opts); - }; + var data = $.extend({}, additional); + data.profile = profile; - exports.delete = function(id, opts) { - var profileUrl = url + "/" + id; - return OctoPrint.delete(profileUrl, opts); - }; + return OctoPrint.patchJson(profileUrl(id), data, opts); + }, - return exports; -})($, _); + delete: function (id, opts) { + return OctoPrint.delete(profileUrl(id), opts); + } + } +}); diff --git a/src/octoprint/static/js/app/client/settings.js b/src/octoprint/static/js/app/client/settings.js index b0c2b423..d8d15fe2 100644 --- a/src/octoprint/static/js/app/client/settings.js +++ b/src/octoprint/static/js/app/client/settings.js @@ -1,36 +1,43 @@ -OctoPrint.settings = (function($, _) { - var exports = {}; - +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint", "jquery"], factory); + } else { + factory(window.OctoPrint, window.$); + } +})(window || this, function(OctoPrint, $) { var url = "api/settings"; - exports.get = function(opts) { + var get = function(opts) { return OctoPrint.get(url, opts); }; - exports.save = function(settings, opts) { + var save = function(settings, opts) { settings = settings || {}; return OctoPrint.postJson(url, settings, opts); }; - exports.getPluginSettings = function(plugin, opts) { - return exports.get(opts) - .then(function(settings, statusText, request) { - if (!settings.plugins || !settings.plugins[plugin]) { - return $.Deferred() - .reject(request, "dataerror", "No settings for plugin " + plugin) - .promise(); - } else { - return settings.plugins[plugin]; - } - }); - }; + OctoPrint.settings = { + get: get, + save: save, - exports.savePluginSettings = function(plugin, settings, opts) { - var data = {}; - data["plugins"] = {}; - data["plugins"][plugin] = settings; - return exports.save(data, opts); - }; + getPluginSettings: function (plugin, opts) { + return get(opts) + .then(function (settings, statusText, request) { + if (!settings.plugins || !settings.plugins[plugin]) { + return $.Deferred() + .reject(request, "dataerror", "No settings for plugin " + plugin) + .promise(); + } else { + return settings.plugins[plugin]; + } + }); + }, - return exports; -})($, _); + savePluginSettings: function (plugin, settings, opts) { + var data = {}; + data["plugins"] = {}; + data["plugins"][plugin] = settings; + return save(data, opts); + } + } +}); diff --git a/src/octoprint/static/js/app/client/slicing.js b/src/octoprint/static/js/app/client/slicing.js index 33c6294f..268ca361 100644 --- a/src/octoprint/static/js/app/client/slicing.js +++ b/src/octoprint/static/js/app/client/slicing.js @@ -1,38 +1,45 @@ -OctoPrint.slicing = (function($, _) { - var exports = {}; - +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { var url = "api/slicing"; - var getProfileUrl = function(slicer, profileId) { - return url + "/" + slicer + "/profiles/" + profileId; + var slicerUrl = function(slicer) { + return url + "/" + slicer; }; - exports.listAllSlicersAndProfiles = function(opts) { - return OctoPrint.get(url, opts); + var profileUrl = function(slicer, profileId) { + return slicerUrl(slicer) + "/profiles/" + profileId; }; - exports.listProfilesForSlicer = function(slicer, opts) { - var slicerUrl = url + "/" + slicer + "/profiles"; - return OctoPrint.get(slicerUrl, opts); - }; + OctoPrint.slicing = { + listAllSlicersAndProfiles: function(opts) { + return OctoPrint.get(url, opts); + }, - exports.getProfileForSlicer = function(slicer, profileId, opts) { - return OctoPrint.get(getProfileUrl(slicer, profileId), opts); - }; + listProfilesForSlicer: function(slicer, opts) { + return OctoPrint.get(slicerUrl(slicer) + "/profiles", opts); + }, - exports.addProfileForSlicer = function(slicer, profileId, profile, opts) { - profile = profile || {}; - return OctoPrint.putJson(getProfileUrl(slicer, profileId), profile, opts); - }; + getProfileForSlicer: function(slicer, profileId, opts) { + return OctoPrint.get(profileUrl(slicer, profileId), opts); + }, - exports.updateProfileForSlicer = function(slicer, profileId, profile, opts) { - profile = profile || {}; - return OctoPrint.patchJson(getProfileUrl(slicer, profileId), profile, opts); - }; + addProfileForSlicer: function(slicer, profileId, profile, opts) { + profile = profile || {}; + return OctoPrint.putJson(profileUrl(slicer, profileId), profile, opts); + }, - exports.deleteProfileForSlicer = function(slicer, profileId, opts) { - return OctoPrint.delete(getProfileUrl(slicer, profileId), opts); - }; + updateProfileForSlicer: function(slicer, profileId, profile, opts) { + profile = profile || {}; + return OctoPrint.patchJson(profileUrl(slicer, profileId), profile, opts); + }, - return exports; -})($, _); + deleteProfileForSlicer: function(slicer, profileId, opts) { + return OctoPrint.delete(profileUrl(slicer, profileId), opts); + } + } +}); diff --git a/src/octoprint/static/js/app/client/socket.js b/src/octoprint/static/js/app/client/socket.js index e511d24e..9777777f 100644 --- a/src/octoprint/static/js/app/client/socket.js +++ b/src/octoprint/static/js/app/client/socket.js @@ -1,4 +1,10 @@ -OctoPrint.socket = (function($, _, SockJS) { +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint", "jquery", "lodash", "sockjs"], factory); + } else { + factory(window.OctoPrint, window.$, window._, window.SockJS); + } +})(window || this, function(OctoPrint, $, _, SockJS) { var exports = {}; exports.options = { @@ -102,5 +108,5 @@ OctoPrint.socket = (function($, _, SockJS) { exports.onReconnectAttempt = function(trial) {}; exports.onReconnectFailed = function() {}; - return exports; -})($, _, SockJS); + OctoPrint.socket = exports; +}); diff --git a/src/octoprint/static/js/app/client/timelapse.js b/src/octoprint/static/js/app/client/timelapse.js index 21824ca3..6ecf8e96 100644 --- a/src/octoprint/static/js/app/client/timelapse.js +++ b/src/octoprint/static/js/app/client/timelapse.js @@ -1,50 +1,60 @@ -OctoPrint.timelapse = (function($, _) { +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint", "jquery"], factory); + } else { + factory(window.OctoPrint, window.$); + } +})(window || this, function(OctoPrint, $) { var exports = {}; var url = "api/timelapse"; - exports.get = function(opts) { - return OctoPrint.get(url, opts); + var timelapseUrl = function(filename) { + return url + "/" + filename; }; - exports.list = function(opts) { - var deferred = $.Deferred(); + OctoPrint.timelapse = { + get: function (opts) { + return OctoPrint.get(url, opts); + }, - exports.get(opts) - .done(function(response, status, request) { - deferred.resolve(response.files, status, request); - }) - .fail(function() { - deferred.reject.apply(null, arguments); - }); + list: function (opts) { + var deferred = $.Deferred(); - return deferred.promise(); - }; + exports.get(opts) + .done(function (response, status, request) { + deferred.resolve(response.files, status, request); + }) + .fail(function () { + deferred.reject.apply(null, arguments); + }); - exports.download = function(filename, opts) { - return OctoPrint.download(url + "/" + filename, opts); - }; + return deferred.promise(); + }, - exports.delete = function(filename, opts) { - return OctoPrint.delete(url + "/" + filename, opts); - }; + download: function (filename, opts) { + return OctoPrint.download(timelapseUrl(filename), opts); + }, - exports.getConfig = function(opts) { - var deferred = $.Deferred(); - exports.get(opts) - .done(function(response, status, request) { - deferred.resolve(response.config, status, request); - }) - .fail(function() { - deferred.reject.apply(null, arguments); - }); - return deferred.promise(); - }; + delete: function (filename, opts) { + return OctoPrint.delete(timelapseUrl(filename), opts); + }, - exports.saveConfig = function(config, opts) { - config = config || {}; - return OctoPrint.postJson(url, config, opts); - }; + getConfig: function (opts) { + var deferred = $.Deferred(); + exports.get(opts) + .done(function (response, status, request) { + deferred.resolve(response.config, status, request); + }) + .fail(function () { + deferred.reject.apply(null, arguments); + }); + return deferred.promise(); + }, - return exports; -})($, _); + saveConfig: function (config, opts) { + config = config || {}; + return OctoPrint.postJson(url, config, opts); + } + } +}); diff --git a/src/octoprint/static/js/app/client/users.js b/src/octoprint/static/js/app/client/users.js index f5572b33..4c715839 100644 --- a/src/octoprint/static/js/app/client/users.js +++ b/src/octoprint/static/js/app/client/users.js @@ -1,6 +1,10 @@ -OctoPrint.users = (function($, _) { - var exports = {}; - +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { var baseUrl = "api/users"; var url = function() { @@ -11,64 +15,96 @@ OctoPrint.users = (function($, _) { } }; - exports.list = function(opts) { - return OctoPrint.get(url(), opts); - }; + OctoPrint.users = { + list: function (opts) { + return OctoPrint.get(url(), opts); + }, - exports.add = function(user, opts) { - if (!user.name || !user.password) { - throw new OctoPrint.InvalidArgumentError("Both user's name and password need to be set"); + add: function (user, opts) { + if (!user.name || !user.password) { + throw new OctoPrint.InvalidArgumentError("Both user's name and password need to be set"); + } + + var data = { + name: user.name, + password: user.password, + active: user.hasOwnProperty("active") ? !!user.active : true, + admin: user.hasOwnProperty("admin") ? !!user.admin : false + }; + + return OctoPrint.postJson(url(), data, opts); + }, + + get: function (name, opts) { + if (!name) { + throw new OctoPrint.InvalidArgumentError("user name must be set"); + } + + return OctoPrint.get(url(name), opts); + }, + + update: function (name, active, admin, opts) { + if (!name) { + throw new OctoPrint.InvalidArgumentError("user name must be set"); + } + + var data = { + active: !!active, + admin: !!admin + }; + return OctoPrint.putJson(url(name), data, opts); + }, + + delete: function (name, opts) { + if (!name) { + throw new OctoPrint.InvalidArgumentError("user name must be set"); + } + + return OctoPrint.delete(url(name), opts); + }, + + changePassword: function (name, password, opts) { + if (!name || !password) { + throw new OctoPrint.InvalidArgumentError("user name and password must be set"); + } + + var data = { + password: password + }; + return OctoPrint.putJson(url(name, "password"), data, opts); + }, + + generateApiKey: function (name, opts) { + if (!name) { + throw new OctoPrint.InvalidArgumentError("user name must be set"); + } + + return OctoPrint.postJson(url(name, "apikey"), opts); + }, + + resetApiKey: function (name, opts) { + if (!name) { + throw new OctoPrint.InvalidArgumentError("user name must be set"); + } + + return OctoPrint.delete(url(name, "apikey"), opts); + }, + + getSettings: function (name, opts) { + if (!name) { + throw new OctoPrint.InvalidArgumentError("user name must be set"); + } + + return OctoPrint.get(url(name, "settings"), opts); + }, + + saveSettings: function (name, settings, opts) { + if (!name) { + throw new OctoPrint.InvalidArgumentError("user name must be set"); + } + + settings = settings || {}; + return OctoPrint.patchJson(url(name, "settings"), settings, opts); } - - var data = { - name: user.name, - password: user.password, - active: user.hasOwnProperty("active") ? !!user.active : true, - admin: user.hasOwnProperty("admin") ? !!user.admin : false - }; - - return OctoPrint.postJson(url(), data, opts); }; - - exports.get = function(name, opts) { - return OctoPrint.get(url(name), opts); - }; - - exports.update = function(name, active, admin, opts) { - var data = { - active: !!active, - admin: !!admin - }; - return OctoPrint.putJson(url(name), data, opts); - }; - - exports.delete = function(name, opts) { - return OctoPrint.delete(url(name), opts); - }; - - exports.changePassword = function(name, password, opts) { - var data = { - password: password - }; - return OctoPrint.putJson(url(name, "password"), data, opts); - }; - - exports.generateApiKey = function(name, opts) { - return OctoPrint.postJson(url(name, "apikey"), opts); - }; - - exports.resetApiKey = function(name, opts) { - return OctoPrint.delete(url(name, "apikey"), opts); - }; - - exports.getSettings = function(name, opts) { - return OctoPrint.get(url(name, "settings"), opts); - }; - - exports.saveSettings = function(name, settings, opts) { - settings = settings || {}; - return OctoPrint.patchJson(url(name, "settings"), settings, opts); - }; - - return exports; -})($, _); +}); diff --git a/src/octoprint/static/js/app/client/util.js b/src/octoprint/static/js/app/client/util.js index 5f22356c..b06259fc 100644 --- a/src/octoprint/static/js/app/client/util.js +++ b/src/octoprint/static/js/app/client/util.js @@ -1,11 +1,47 @@ -OctoPrint.util = (function($, _) { - var exports = {}; - +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint", "jquery"], factory); + } else { + factory(window.OctoPrint, window.$); + } +})(window || this, function(OctoPrint, $) { var url = "api/util"; + var testUrl = url + "/test"; - exports.test = function(command, data, opts) { - return OctoPrint.issueCommand(url + "/test", command, data, opts); + var test = function(command, data, opts) { + return OctoPrint.issueCommand(testUrl, command, data, opts); }; - return exports; -})($, _); + OctoPrint.util = { + test: test, + + testPath: function(path, additional, opts) { + additional = additional || {}; + + var data = $.extend({}, additional); + data.path = path; + + return test("path", data, opts); + }, + + testExecutable: function(path, additional, opts) { + additional = additional || {}; + + var data = $.extend({}, additional); + data.path = path; + data.check_type = "file"; + data.check_access = "x"; + + return test("path", data, opts); + }, + + testUrl: function(url, additional, opts) { + additional = additional || {}; + + var data = $.extend({}, additional); + data.url = url; + + return test("url", data, opts); + } + }; +}); diff --git a/src/octoprint/static/js/app/client/wizard.js b/src/octoprint/static/js/app/client/wizard.js index 70182dba..e848e511 100644 --- a/src/octoprint/static/js/app/client/wizard.js +++ b/src/octoprint/static/js/app/client/wizard.js @@ -1,15 +1,18 @@ -OctoPrint.wizard = (function($, _) { - var exports = {}; - +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["OctoPrint"], factory); + } else { + factory(window.OctoPrint); + } +})(window || this, function(OctoPrint) { var url = "api/setup/wizard"; - exports.get = function(opts) { - return OctoPrint.get(url, opts); + OctoPrint.wizard = { + get: function(opts) { + return OctoPrint.get(url, opts); + }, + finish: function(handled, opts) { + return OctoPrint.postJson(url, {handled: handled || []}, opts); + } }; - - exports.finish = function(handled, opts) { - return OctoPrint.postJson(url, {handled: handled || []}, opts); - }; - - return exports; -})($, _); +}); diff --git a/src/octoprint/static/js/app/main.js b/src/octoprint/static/js/app/main.js index c4971b3c..4caa5aa9 100644 --- a/src/octoprint/static/js/app/main.js +++ b/src/octoprint/static/js/app/main.js @@ -1,4 +1,6 @@ $(function() { + OctoPrint = window.OctoPrint; + //~~ Lodash setup _.mixin({"sprintf": sprintf, "vsprintf": vsprintf}); From 7b7f21d12602fba2e5486e59d9fa761e056597df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 28 Sep 2015 17:08:25 +0200 Subject: [PATCH 08/25] Migrate to new utility methods for testing URLs & executable paths --- src/octoprint/plugins/cura/static/js/cura.js | 16 ++----- .../static/js/app/viewmodels/settings.js | 45 +++++++------------ 2 files changed, 20 insertions(+), 41 deletions(-) diff --git a/src/octoprint/plugins/cura/static/js/cura.js b/src/octoprint/plugins/cura/static/js/cura.js index fb8fb62a..d99db545 100644 --- a/src/octoprint/plugins/cura/static/js/cura.js +++ b/src/octoprint/plugins/cura/static/js/cura.js @@ -168,13 +168,9 @@ $(function() { $("#settings_plugin_cura_import").modal("show"); }; - self.testEnginePath = function(successCallback) { - self.sendTestRequest(self.settings.plugins.cura.cura_engine()); - }; - - self.sendTestRequest = function(enginePath, successCallback) { - if (successCallback == undefined) { - successCallback = function(response) { + self.testEnginePath = function() { + OctoPrint.util.testExecutable(self.settings.plugins.cura.cura_engine()) + .done(function(response) { if (!response.result) { if (!response.exists) { self.pathText(gettext("The path doesn't exist")); @@ -188,11 +184,7 @@ $(function() { } self.pathOk(response.result); self.pathBroken(!response.result); - } - } - - OctoPrint.util.test("path", {path: enginePath, check_type: "file", check_access: "x"}) - .done(successCallback); + }); }; self.requestData = function() { diff --git a/src/octoprint/static/js/app/viewmodels/settings.js b/src/octoprint/static/js/app/viewmodels/settings.js index d70d07c5..b827edd9 100644 --- a/src/octoprint/static/js/app/viewmodels/settings.js +++ b/src/octoprint/static/js/app/viewmodels/settings.js @@ -226,12 +226,7 @@ $(function() { var errorText = gettext("Could not retrieve snapshot URL, please double check the URL"); var errorTitle = gettext("Snapshot test failed"); - var data = { - url: self.webcam_snapshotUrl(), - method: "GET", - response: true - }; - OctoPrint.util.test("url", data) + OctoPrint.util.testUrl(self.webcam_snapshotUrl(), {method: "GET", response: true}) .done(function(response) { $("i.icon-spinner", target).remove(); @@ -271,30 +266,22 @@ $(function() { return; } - var successCallback = function(response) { - if (!response.result) { - if (!response.exists) { - self.webcam_ffmpegPathText(gettext("The path doesn't exist")); - } else if (!response.typeok) { - self.webcam_ffmpegPathText(gettext("The path is not a file")); - } else if (!response.access) { - self.webcam_ffmpegPathText(gettext("The path is not an executable")); + OctoPrint.util.testExecutable(self.webcam_ffmpegPath()) + .done(function(response) { + if (!response.result) { + if (!response.exists) { + self.webcam_ffmpegPathText(gettext("The path doesn't exist")); + } else if (!response.typeok) { + self.webcam_ffmpegPathText(gettext("The path is not a file")); + } else if (!response.access) { + self.webcam_ffmpegPathText(gettext("The path is not an executable")); + } + } else { + self.webcam_ffmpegPathText(gettext("The path is valid")); } - } else { - self.webcam_ffmpegPathText(gettext("The path is valid")); - } - self.webcam_ffmpegPathOk(response.result); - self.webcam_ffmpegPathBroken(!response.result); - }; - - var path = self.webcam_ffmpegPath(); - var data = { - path: path, - check_type: "file", - check_access: "x" - }; - OctoPrint.util.test("path", data) - .done(successCallback); + self.webcam_ffmpegPathOk(response.result); + self.webcam_ffmpegPathBroken(!response.result); + }); }; self.onSettingsShown = function() { From 7a06f496de07b5931271b45e622f556b3d6e5784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 28 Sep 2015 17:08:40 +0200 Subject: [PATCH 09/25] Let's get rid of another callback --- src/octoprint/static/js/app/viewmodels/slicing.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/octoprint/static/js/app/viewmodels/slicing.js b/src/octoprint/static/js/app/viewmodels/slicing.js index c361b826..ffbb21f9 100644 --- a/src/octoprint/static/js/app/viewmodels/slicing.js +++ b/src/octoprint/static/js/app/viewmodels/slicing.js @@ -64,13 +64,10 @@ $(function() { && self.profile() != undefined; }); - self.requestData = function(callback) { - OctoPrint.slicing.listAllSlicersAndProfiles() + self.requestData = function() { + return OctoPrint.slicing.listAllSlicersAndProfiles() .done(function(data) { self.fromResponse(data); - if (callback !== undefined) { - callback(); - } }); }; From 73c235d67f6aa8ee446c1b5826090a90f77ec840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 28 Sep 2015 18:17:43 +0200 Subject: [PATCH 10/25] Migrate SettingsViewModel.requestData to using promises Fallback implementation for old callback parameter is still present, logs warning about deprecation. --- src/octoprint/static/js/app/main.js | 3 +- .../static/js/app/viewmodels/gcode.js | 25 +++--- .../static/js/app/viewmodels/settings.js | 86 +++++++++++++------ 3 files changed, 75 insertions(+), 39 deletions(-) diff --git a/src/octoprint/static/js/app/main.js b/src/octoprint/static/js/app/main.js index 4caa5aa9..5f301582 100644 --- a/src/octoprint/static/js/app/main.js +++ b/src/octoprint/static/js/app/main.js @@ -501,7 +501,8 @@ $(function() { if (!_.has(viewModelMap, "settingsViewModel")) { throw new Error("settingsViewModel is missing, can't run UI") } - viewModelMap["settingsViewModel"].requestData(bindViewModels); + viewModelMap["settingsViewModel"].requestData() + .done(bindViewModels); } ); diff --git a/src/octoprint/static/js/app/viewmodels/gcode.js b/src/octoprint/static/js/app/viewmodels/gcode.js index 5b032b3e..ae37cf9a 100644 --- a/src/octoprint/static/js/app/viewmodels/gcode.js +++ b/src/octoprint/static/js/app/viewmodels/gcode.js @@ -231,19 +231,20 @@ $(function() { self._configureLayerSlider(layerSliderElement); self._configureLayerCommandSlider(commandSliderElement); - self.settings.requestData(function() { - GCODE.ui.init({ - container: "#gcode_canvas", - onProgress: self._onProgress, - onModelLoaded: self._onModelLoaded, - onLayerSelected: self._onLayerSelected, - bed: self._retrieveBedDimensions(), - toolOffsets: self._retrieveToolOffsets(), - invertAxes: self._retrieveAxesConfiguration() + self.settings.requestData() + .done(function() { + GCODE.ui.init({ + container: "#gcode_canvas", + onProgress: self._onProgress, + onModelLoaded: self._onModelLoaded, + onLayerSelected: self._onLayerSelected, + bed: self._retrieveBedDimensions(), + toolOffsets: self._retrieveToolOffsets(), + invertAxes: self._retrieveAxesConfiguration() + }); + self.synchronizeOptions(); + self.enabled = true; }); - self.synchronizeOptions(); - self.enabled = true; - }); }; self.reset = function() { diff --git a/src/octoprint/static/js/app/viewmodels/settings.js b/src/octoprint/static/js/app/viewmodels/settings.js index b827edd9..1d78c355 100644 --- a/src/octoprint/static/js/app/viewmodels/settings.js +++ b/src/octoprint/static/js/app/viewmodels/settings.js @@ -10,7 +10,7 @@ $(function() { self.receiving = ko.observable(false); self.sending = ko.observable(false); - self.callbacks = []; + self.outstanding = []; self.settingsDialog = undefined; self.settings_dialog_update_detected = undefined; @@ -386,44 +386,78 @@ $(function() { return false; }; - self.requestData = function(callback, local) { - if (self.receiving()) { - if (callback) { - self.callbacks.push(callback); - } - return; + self.requestData = function(local) { + // handle old parameter format + var callback = undefined; + if (_.isFunction(local)) { + log.warn("The callback parameter of SettingsViewModel.requestData is deprecated, the method now returns a promise, please use that instead."); + callback = local; + local = false; + } else if (arguments.length == 2) { + log.warn("The callback parameter of SettingsViewModel.requestData is deprecated, the method now returns a promise, please use that instead."); + callback = arguments[0]; + local = arguments[1]; } + // handler for any explicitely provided callbacks + var callbackHandler = function() { + if (!callback) return; + try { + callback(); + } catch (exc) { + log.error("Error calling settings callback", callback, ":", (exc.stack || exc)); + } + }; + + // if a request is already active, create a new deferred and return + // its promise, it will be resolved in the response handler of the + // current request + if (self.receiving()) { + var deferred = $.Deferred(); + self.outstanding.push(deferred); + + if (callback) { + // if we have a callback, we need to make sure it will + // get called when the deferred is resolved + deferred.done(callbackHandler); + } + + return deferred.promise(); + } + + // perform the request self.receiving(true); - OctoPrint.settings.get() + return OctoPrint.settings.get() .done(function(response) { + self.fromResponse(response, local); + if (callback) { - self.callbacks.push(callback); + var deferred = $.Deferred(); + deferred.done(callbackHandler); + self.outstanding.push(deferred); } - try { - self.fromResponse(response, local); - - var cb; - while (self.callbacks.length) { - cb = self.callbacks.shift(); - try { - cb(); - } catch(exc) { - log.error("Error calling settings callback", cb, ":", (exc.stack || exc)); - } - } - } finally { - self.receiving(false); - self.callbacks = []; - } + // resolve all promises + var args = arguments; + _.each(self.outstanding, function(deferred) { + deferred.resolve(args); + }); + self.outstanding = []; }) .fail(function() { + // reject all promises + var args = arguments; + _.each(self.outstanding, function(deferred) { + deferred.reject(args); + }); + self.outstanding = []; + }) + .always(function() { self.receiving(false); }); }; - self.requestTranslationData = function(callback) { + self.requestTranslationData = function() { return OctoPrint.languages.list() .done(self.fromTranslationResponse); }; From e57ed922949f4c357e6792df1e1d906cc72b963e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 28 Sep 2015 18:24:56 +0200 Subject: [PATCH 11/25] Less repetitious code --- .../static/js/app/viewmodels/settings.js | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/octoprint/static/js/app/viewmodels/settings.js b/src/octoprint/static/js/app/viewmodels/settings.js index 1d78c355..99a65c4e 100644 --- a/src/octoprint/static/js/app/viewmodels/settings.js +++ b/src/octoprint/static/js/app/viewmodels/settings.js @@ -389,14 +389,17 @@ $(function() { self.requestData = function(local) { // handle old parameter format var callback = undefined; - if (_.isFunction(local)) { - log.warn("The callback parameter of SettingsViewModel.requestData is deprecated, the method now returns a promise, please use that instead."); - callback = local; - local = false; - } else if (arguments.length == 2) { - log.warn("The callback parameter of SettingsViewModel.requestData is deprecated, the method now returns a promise, please use that instead."); - callback = arguments[0]; - local = arguments[1]; + if (arguments.length == 2 || _.isFunction(local)) { + var exc = new Error(); + log.warn("The callback parameter of SettingsViewModel.requestData is deprecated, the method now returns a promise, please use that instead. Stacktrace:", (exc.stack || exc.stacktrace || "")); + + if (arguments.length == 2) { + callback = arguments[0]; + local = arguments[1]; + } else { + callback = local; + local = false; + } } // handler for any explicitely provided callbacks @@ -405,7 +408,7 @@ $(function() { try { callback(); } catch (exc) { - log.error("Error calling settings callback", callback, ":", (exc.stack || exc)); + log.error("Error calling settings callback", callback, ":", (exc.stack || exc.stacktrace || exc)); } }; From bdc5d72613c9d1af6648e88ab80dde9ffb285575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 28 Sep 2015 18:41:40 +0200 Subject: [PATCH 12/25] Fixes OctoPrint.files.download method --- src/octoprint/static/js/app/client/files.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/octoprint/static/js/app/client/files.js b/src/octoprint/static/js/app/client/files.js index 2e76f5f4..84d26f17 100644 --- a/src/octoprint/static/js/app/client/files.js +++ b/src/octoprint/static/js/app/client/files.js @@ -23,7 +23,13 @@ return OctoPrint.issueCommand(url, command, data, opts); }; + var getFile = function(location, filename, opts) { + return OctoPrint.get(resourceForFile(location, filename), opts); + }; + OctoPrint.files = { + get: getFile, + list: function (opts) { return OctoPrint.get(url, opts); }, @@ -32,10 +38,6 @@ return OctoPrint.get(resourceForLocation(location), opts); }, - get: function (location, filename, opts) { - return OctoPrint.get(resourceForFile(location, filename), opts); - }, - select: function (location, filename, print, opts) { print = print || false; @@ -64,7 +66,7 @@ download: function (location, filename, opts) { var deferred = $.Deferred(); - exports.get(location, filename, opts) + getFile(location, filename, opts) .done(function (response) { OctoPrint.download(response.refs.download, opts) .done(function () { From 31bc7c1f3e543a6a765d96662311696ab62c4ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 1 Oct 2015 10:08:24 +0200 Subject: [PATCH 13/25] Helper method for creating notifications with only one confirm button PNotify always merges the default buttons and the ones provided. Just settings the default to containing no buttons was no option since plugins might already depend on the so far obligatory Cancel button being present. The helper allows to create one buttoned notifications without touching the defaults. --- src/octoprint/static/js/app/main.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/octoprint/static/js/app/main.js b/src/octoprint/static/js/app/main.js index f2a7b11d..30b3d5d1 100644 --- a/src/octoprint/static/js/app/main.js +++ b/src/octoprint/static/js/app/main.js @@ -62,6 +62,22 @@ $(function() { PNotify.prototype.options.styling = "bootstrap2"; PNotify.prototype.options.mouse_reset = false; + PNotify.singleButtonNotify = function(options) { + var autoDisplay = options.auto_display != false; + + var params = $.extend(true, {}, options); + params.auto_display = false; + + var notify = new PNotify(params); + notify.options.confirm.buttons = [notify.options.confirm.buttons[0]]; + notify.modules.confirm.makeDialog(notify, notify.options.confirm); + + if (autoDisplay) { + notify.open(); + } + return notify; + }; + //~~ Initialize view models // the view model map is our basic look up table for dependencies that may be injected into other view models From 6ab44849cdf2161c2a6dd6b7a83ce34457b6bdd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 1 Oct 2015 14:05:23 +0200 Subject: [PATCH 14/25] Extracted system commands into their own proper API & ViewModel --- src/octoprint/server/api/__init__.py | 35 +--- src/octoprint/server/api/system.py | 176 ++++++++++++++++++ src/octoprint/server/util/flask.py | 1 + .../static/js/app/viewmodels/navigation.js | 35 +--- .../static/js/app/viewmodels/system.js | 96 ++++++++++ .../templates/navbar/systemmenu.jinja2 | 4 +- 6 files changed, 278 insertions(+), 69 deletions(-) create mode 100644 src/octoprint/server/api/system.py create mode 100644 src/octoprint/static/js/app/viewmodels/system.js diff --git a/src/octoprint/server/api/__init__.py b/src/octoprint/server/api/__init__.py index 7bb87bc4..6b924236 100644 --- a/src/octoprint/server/api/__init__.py +++ b/src/octoprint/server/api/__init__.py @@ -38,6 +38,7 @@ from . import log as api_logs from . import slicing as api_slicing from . import printer_profiles as api_printer_profiles from . import languages as api_languages +from . import system as api_system VERSION = "0.1" @@ -177,40 +178,6 @@ def apiVersion(): "api": VERSION }) -#~~ system control - - -@api.route("/system", methods=["POST"]) -@restricted_access -@admin_permission.require(403) -def performSystemAction(): - logger = logging.getLogger(__name__) - if "action" in request.values.keys(): - action = request.values["action"] - available_actions = s().get(["system", "actions"]) - for availableAction in available_actions: - if availableAction["action"] == action: - async = availableAction["async"] if "async" in availableAction else False - ignore = availableAction["ignore"] if "ignore" in availableAction else False - logger.info("Performing command: %s" % availableAction["command"]) - try: - # we run this with shell=True since we have to trust whatever - # our admin configured as command and since we want to allow - # shell-alike handling here... - p = sarge.run(availableAction["command"], stderr=sarge.Capture(), shell=True, async=async) - if not async: - if not ignore and p.returncode != 0: - returncode = p.returncode - stderr_text = p.stderr.text - logger.warn("Command failed with return code %i: %s" % (returncode, stderr_text)) - return make_response(("Command failed with return code %i: %s" % (returncode, stderr_text), 500, [])) - except Exception, e: - if not ignore: - logger.warn("Command failed: %s" % e) - return make_response(("Command failed: %s" % e, 500, [])) - break - return NO_CONTENT - #~~ Login/user handling diff --git a/src/octoprint/server/api/system.py b/src/octoprint/server/api/system.py new file mode 100644 index 00000000..fba71f43 --- /dev/null +++ b/src/octoprint/server/api/system.py @@ -0,0 +1,176 @@ +# coding=utf-8 +from __future__ import absolute_import + +__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html' +__copyright__ = "Copyright (C) 2015 The OctoPrint Project - Released under terms of the AGPLv3 License" + +import collections +import logging +import sarge + +from flask import request, make_response, jsonify, url_for +from flask.ext.babel import gettext + +from octoprint.settings import settings as s + +from octoprint.server import admin_permission, NO_CONTENT +from octoprint.server.api import api +from octoprint.server.util.flask import restricted_access, get_remote_address + + +@api.route("/system", methods=["POST"]) +@restricted_access +@admin_permission.require(403) +def performSystemAction(): + logging.getLogger(__name__).warn("Deprecated API call to /api/system made by {}, should be migrated to use /system/commands/custom/".format(get_remote_address(request))) + + data = request.values + if hasattr(request, "json") and request.json: + data = request.json + + if not "action" in data: + return make_response("action for perform is not defined", 400) + + return executeSystemCommand("custom", data["action"]) + + +@api.route("/system/commands", methods=["GET"]) +@restricted_access +@admin_permission.require(403) +def retrieveSystemCommands(): + return jsonify(core=_to_client_specs(_get_core_command_specs()), + custom=_to_client_specs(_get_custom_command_specs())) + + +@api.route("/system/commands/", methods=["GET"]) +@restricted_access +@admin_permission.require(403) +def retrieveSystemCommandsForSource(source): + if source == "core": + specs = _get_core_command_specs() + elif source == "custom": + specs = _get_custom_command_specs() + else: + return make_response("Unknown system command source: {}".format(source), 400) + + return jsonify(_to_client_specs(specs)) + + +@api.route("/system/commands//", methods=["POST"]) +@restricted_access +@admin_permission.require(403) +def executeSystemCommand(source, command): + logger = logging.getLogger(__name__) + + command_spec = _get_command_spec(source, command) + if not command_spec: + return make_response("Command {}:{} not found".format(source, command), 404) + + if not "command" in command_spec: + return make_response("Command {}:{} does not define a command to execute, can't proceed".format(source, command), 500) + + async = command_spec["async"] if "async" in command_spec else False + ignore = command_spec["ignore"] if "ignore" in command_spec else False + logger.info("Performing command for {}:{}: {}".format(source, command, command_spec["command"])) + try: + # we run this with shell=True since we have to trust whatever + # our admin configured as command and since we want to allow + # shell-alike handling here... + p = sarge.run(command_spec["command"], + stdout=sarge.Capture(), + stderr=sarge.Capture(), + shell=True, + async=async) + if not async: + if not ignore and p.returncode != 0: + returncode = p.returncode + stdout_text = p.stdout.text + stderr_text = p.stderr.text + + error = "Command failed with return code {}:\nSTDOUT: {}\nSTDERR: {}".format(returncode, stdout_text, stderr_text) + logger.warn(error) + return make_response(error, 500) + except Exception, e: + if not ignore: + error = "Command failed: {}".format(str(e)) + logger.warn(error) + return make_response(error, 500) + + return NO_CONTENT + + +def _to_client_specs(specs): + result = list() + for spec in specs.values(): + if not "action" in spec or not "source" in spec: + continue + copied = dict((k, v) for k, v in spec.items() if k in ("source", "action", "name", "confirm")) + copied["resource"] = url_for(".executeSystemCommand", + source=spec["source"], + command=spec["action"], + _external=True) + result.append(copied) + return result + + +def _get_command_spec(source, action): + if source == "core": + return _get_core_command_spec(action) + elif source == "custom": + return _get_custom_command_spec(action) + else: + return None + + +def _get_core_command_specs(): + commands = collections.OrderedDict( + shutdown=dict( + command=s().get(["server", "commands", "systemShutdownCommand"]), + name=gettext("Shutdown"), + confirm=gettext("You are about to shutdown the system.")), + reboot=dict( + command=s().get(["server", "commands", "systemRestartCommand"]), + name=gettext("Reboot"), + confirm=gettext("You are about to reboot the system.")), + restart=dict( + command=s().get(["server", "commands", "serverRestartCommand"]), + name="Restart OctoPrint", + confirm="You are about to restart the OctoPrint server.") + ) + + available_commands = dict() + for action, spec in commands.items(): + if not spec["command"]: + continue + spec.update(dict(action=action, source="core", async=True, ignore=True)) + available_commands[action] = spec + return available_commands + + +def _get_core_command_spec(action): + available_actions = _get_core_command_specs() + if not action in available_actions: + logging.getLogger(__name__).warn("Command for core action {} is not configured, you need to configure the command before it can be used".format(action)) + return None + + return available_actions[action] + + +def _get_custom_command_specs(): + specs = collections.OrderedDict() + for spec in s().get(["system", "actions"]): + if not "action" in spec: + continue + copied = dict(spec) + copied["source"] = "custom" + specs[spec["action"]] = copied + return specs + + +def _get_custom_command_spec(action): + available_actions = _get_custom_command_specs() + if not action in available_actions: + return None + + return available_actions[action] + diff --git a/src/octoprint/server/util/flask.py b/src/octoprint/server/util/flask.py index 4fb4d6cb..b1c386af 100644 --- a/src/octoprint/server/util/flask.py +++ b/src/octoprint/server/util/flask.py @@ -631,6 +631,7 @@ def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"): 'js/app/viewmodels/printerprofiles.js', 'js/app/viewmodels/settings.js', 'js/app/viewmodels/slicing.js', + 'js/app/viewmodels/system.js', 'js/app/viewmodels/temperature.js', 'js/app/viewmodels/terminal.js', 'js/app/viewmodels/timelapse.js', diff --git a/src/octoprint/static/js/app/viewmodels/navigation.js b/src/octoprint/static/js/app/viewmodels/navigation.js index 736fc949..37bebbe8 100644 --- a/src/octoprint/static/js/app/viewmodels/navigation.js +++ b/src/octoprint/static/js/app/viewmodels/navigation.js @@ -6,8 +6,7 @@ $(function() { self.appearance = parameters[1]; self.settings = parameters[2]; self.usersettings = parameters[3]; - - self.systemActions = self.settings.system_actions; + self.system = parameters[4]; self.appearanceClasses = ko.computed(function() { var classes = self.appearance.color(); @@ -17,41 +16,11 @@ $(function() { return classes; }); - self.triggerAction = function(action) { - var callback = function() { - $.ajax({ - url: API_BASEURL + "system", - type: "POST", - dataType: "json", - data: "action=" + action.action, - success: function() { - new PNotify({title: "Success", text: _.sprintf(gettext("The command \"%(command)s\" executed successfully"), {command: action.name}), type: "success"}); - }, - error: function(jqXHR, textStatus, errorThrown) { - if (!action.hasOwnProperty("ignore") || !action.ignore) { - var error = "

" + _.sprintf(gettext("The command \"%(command)s\" could not be executed."), {command: action.name}) + "

"; - error += pnotifyAdditionalInfo("
" + jqXHR.responseText + "
"); - new PNotify({title: gettext("Error"), text: error, type: "error", hide: false}); - } - } - }) - }; - if (action.confirm) { - showConfirmationDialog({ - message: action.confirm, - onproceed: function(e) { - callback(); - } - }); - } else { - callback(); - } - } } OCTOPRINT_VIEWMODELS.push([ NavigationViewModel, - ["loginStateViewModel", "appearanceViewModel", "settingsViewModel", "userSettingsViewModel"], + ["loginStateViewModel", "appearanceViewModel", "settingsViewModel", "userSettingsViewModel", "systemViewModel"], "#navbar" ]); }); diff --git a/src/octoprint/static/js/app/viewmodels/system.js b/src/octoprint/static/js/app/viewmodels/system.js new file mode 100644 index 00000000..fd2307e0 --- /dev/null +++ b/src/octoprint/static/js/app/viewmodels/system.js @@ -0,0 +1,96 @@ +$(function() { + function SystemViewModel(parameters) { + var self = this; + + self.loginState = parameters[0]; + + self.lastCommandResponse = undefined; + self.systemActions = ko.observableArray([]); + + self.requestData = function() { + self.requestCommandData(); + }; + + self.requestCommandData = function() { + if (!self.loginState.isAdmin()) { + return; + } + + $.ajax({ + url: API_BASEURL + "system/commands", + type: "GET", + dataType: "json", + success: self.fromCommandResponse + }); + }; + + self.fromCommandResponse = function(response) { + var actions = []; + _.each(response.core, function(data) { + var action = _.extend({}, data); + action.actionSource = "core"; + actions.push(action); + }); + actions.push({action: "divider"}); + _.each(response.custom, function(data) { + var action = _.extend({}, data); + action.actionSource = "custom"; + actions.push(action); + }); + self.lastCommandResponse = response; + self.systemActions(actions); + }; + + self.triggerCommand = function(commandSpec) { + var callback = function() { + $.ajax({ + url: commandSpec.resource, + type: "POST", + dataType: "json", + data: "{}", + contentType: "application/json; charset=UTF-8", + success: function() { + new PNotify({title: "Success", text: _.sprintf(gettext("The command \"%(command)s\" executed successfully"), {command: commandSpec.name}), type: "success"}); + }, + error: function(jqXHR, textStatus, errorThrown) { + if (!commandSpec.hasOwnProperty("ignore") || !commandSpec.ignore) { + var error = "

" + _.sprintf(gettext("The command \"%(command)s\" could not be executed."), {command: commandSpec.name}) + "

"; + error += pnotifyAdditionalInfo("
" + jqXHR.responseText + "
"); + new PNotify({title: gettext("Error"), text: error, type: "error", hide: false}); + } + } + }) + }; + if (commandSpec.confirm) { + showConfirmationDialog({ + message: commandSpec.confirm, + onproceed: function(e) { + callback(); + } + }); + } else { + callback(); + } + }; + + self.onUserLoggedIn = function(user) { + if (user.admin) { + self.requestData(); + } else { + self.onUserLoggedOut(); + } + }; + + self.onUserLoggedOut = function() { + self.lastCommandResponse = undefined; + self.systemActions([]); + } + } + + // view model class, parameters for constructor, container to bind to + ADDITIONAL_VIEWMODELS.push([ + SystemViewModel, + ["loginStateViewModel"], + [] + ]); +}); diff --git a/src/octoprint/templates/navbar/systemmenu.jinja2 b/src/octoprint/templates/navbar/systemmenu.jinja2 index a2ee3f3b..603d2a09 100644 --- a/src/octoprint/templates/navbar/systemmenu.jinja2 +++ b/src/octoprint/templates/navbar/systemmenu.jinja2 @@ -2,11 +2,11 @@ {{ _('System') }} -