/* Interface logic for the Duet Web Control v1.11 * * written by Christian Hammacher * * licensed under the terms of the GPL v2 * see http://www.gnu.org/licenses/gpl-2.0.html */ var maxTemperatureSamples = 1000; var probeSlowDownColor = "#FFFFE0", probeTriggerColor = "#FFF0F0"; var tempChart; var tempChartOptions = { colors: ["#0000FF", "#FF0000", "#00DD00", "#FFA000", "#FF00FF", "#337AB7", "#00FFFF", "#000000"], grid: { borderWidth: 0 }, xaxis: { show: false }, yaxis: { min: 0, max: 280 } }; var tempChartPadding = 15; var printChart; var printChartOptions = { colors: ["#EDC240"], grid: { borderWidth: 0, hoverable: true, clickable: true }, pan: { interactive: true }, series: { lines: { show: true }, points: { show: true } }, xaxis: { min: 1, tickDecimals: 0, }, yaxis: { min: 0, max: 30, ticks: 5, tickDecimals: 0, tickFormatter: function(val) { if (!val) { return ""; } else { return val + "s"; } } }, zoom: { interactive: true } }; var webcamUpdating = false; var notificationOptions = { animate: { enter: 'animated fadeInDown', exit: 'animated fadeOutDown' }, placement: { from: "bottom", align: "center" }, template: '' }; $(document).ready(function() { disableControls(); resetGuiData(); updateGui(); $("#web_version").append(", JS: " + jsVersion); $("#text_config").textareaAutoSize(); $.notifyDefaults(notificationOptions); loadSettings(false); }); function settingsLoaded() { applySettings(); $.ajax("language.xml", { type: "GET", dataType: "xml", global: false, error: function() { pageLoadComplete(); }, success: function(response) { translationData = response; if (translationData.children == undefined) { // Internet Explorer and Edge cannot deal with XML files in the way we want. // Disable translations for those browsers. translationData = undefined; $("#dropdown_language, #label_language").addClass("hidden"); } else { $("#dropdown_language ul > li:not(:first-child)").remove(); for(var i=0; i' + name + ''); if (settings.language == id) { $("#btn_language > span:first-child").text(name); } } translatePage(); } pageLoadComplete(); } }); } function pageLoadComplete() { log("info", "" + T("Page Load complete!") + ""); if (settings.autoConnect) { // Users might want to connect automatically once the page has loaded connect(sessionPassword, true); } } function enableControls() { $("nav input, #div_heaters input, #main_content input").prop("disabled", false); // Generic inputs $("#page_tools label").removeClass("disabled"); // and on Settings page $(".btn-emergency-stop, .gcode-input button[type=submit], .gcode").removeClass("disabled"); // Navbar $(".bed-temp, .gcode, .heater-temp, .btn-upload").removeClass("disabled"); // List items and Upload buttons $("#mobile_home_buttons button, #btn_homeall, #table_move_head a").removeClass("disabled"); // Move buttons $("#panel_extrude label.btn, #panel_extrude button").removeClass("disabled"); // Extruder Control $("#panel_control_misc label.btn").removeClass("disabled"); // ATX Power $("#slider_fan_control").slider("enable"); // Fan Control $("#page_print .checkbox").removeClass("disabled"); // Print Control $("#slider_fan_print").slider("enable"); // Fan Control $("#slider_speed").slider("enable"); // Speed Factor for(var extr=1; extr<=6; extr++) { $("#slider_extr_" + extr).slider("enable"); // Extrusion Factors } $(".online-control").removeClass("hidden"); // G-Code/Macro Files } function disableControls() { $("nav input, #div_heaters input, #main_content input").prop("disabled", true); // Generic inputs $("#page_general input, #page_listitems input").prop("disabled", false); // ... except ... $("#page_tools label").addClass("disabled"); // ... for Settings $(".btn-emergency-stop, .gcode-input button[type=submit], .gcode").addClass("disabled"); // Navbar $("#extruder_drives").addClass("disabled"); // Info Panels $(".bed-temp, .gcode, .heater-temp, .btn-upload").addClass("disabled"); // List items and Upload buttons $("#mobile_home_buttons button, #btn_homeall, #table_move_head a").addClass("disabled"); // Move buttons $("#panel_extrude label.btn, #panel_extrude button").addClass("disabled"); // Extruder Control $("#panel_control_misc label.btn").addClass("disabled"); // ATX Power $("#slider_fan_control").slider("disable"); // Fan Control $("#btn_pause, #page_print .checkbox").addClass("disabled"); // Print Control $("#slider_fan_print").slider("disable"); // Fan Control $("#slider_speed").slider("disable"); // Speed Factor for(var extr=1; extr<=6; extr++) { $("#slider_extr_" + extr).slider("disable"); // Extrusion Factors } $(".online-control").addClass("hidden"); // G-Code/Macro Files } function updateGui() { // Visibility for Heater Temperatures if (heatedBed) { // Heated Bed $("#tr_bed").removeClass("hidden"); } else { $("#tr_bed").addClass("hidden"); } if (chamber) { // Chamber $("#tr_chamber").removeClass("hidden"); } else { $("#tr_chamber").addClass("hidden"); } for(var i=1; i<=6; i++) { // Heads (Heaters) if (i <= numHeads) { $("#tr_head_" + i).removeClass("hidden"); } else { $("#tr_head_" + i).addClass("hidden"); } } // Visibility for Extruder Drive columns for(var i=1; i<=6; i++) { if (i <= numExtruderDrives) { $(".extr-" + i).removeClass("hidden").css("border-right", ""); $("#slider_extr_" + i).slider("relayout"); } else { $(".extr-" + i).addClass("hidden").css("border-right", ""); } } if (numExtruderDrives > 0) { $(".extr-" + numExtruderDrives).css("border-right", "0px"); $("#row_status_2").removeClass("hidden"); } else { $("#row_status_2").addClass("hidden"); } // Add Zero Extruder Drive buttons if (isConnected) { $("#extruder_drives").removeClass("disabled"); $("#ul_extruder_dropdown").html('
  • ' + T("Zero All Drives") + '
  • '); for(var i=1; i<= numExtruderDrives; i++) { $("#ul_extruder_dropdown").append('
  • ' + T("Zero Extruder Drive {0}", i) + '
  • '); } $(".zero-extruder").off("click").click(function(e) { if (lastStatusResponse != undefined) { var gcode = "G92 E", target = $(this).data("target"); for(var i=1; i<=numExtruderDrives; i++) { if (target != "all" && target != i) { gcode += lastStatusResponse.coords.extr[i - 1]; } else { gcode += "0"; } if (i < numExtruderDrives) { gcode += ":"; } } sendGCode(gcode); } e.preventDefault(); }); } // Do some rearrangement for the panels if we have less than or exactly three extruder drives if (numExtruderDrives <= 3) { $(".div-head-temp").removeClass("hidden-sm"); $("#col_extr_totals, #td_extr_total").addClass("hidden"); for(var i=1; i<=3; i++) { $("th.extr-" + i).html(T("Drive " + i)); $("#row_status_2 .extr-" + i).removeClass("hidden-md"); } $("#div_heaters").removeClass("col-sm-5").addClass("col-sm-6"); $("#div_temp_chart").removeClass("col-lg-3").addClass("col-lg-5"); $("#div_status").removeClass("col-sm-7 col-lg-5").addClass("col-sm-6 col-lg-3"); } else { $(".div-head-temp").addClass("hidden-sm"); $("#col_extr_totals, #td_extr_total").removeClass("hidden"); for(var i=1; i<=3; i++) { $("th.extr-" + i).html(T("D" + i)); $("#row_status_2 .extr-" + i).addClass("hidden-md"); } $("#div_heaters").removeClass("col-sm-6").addClass("col-sm-5"); $("#div_temp_chart").removeClass("col-lg-5").addClass("col-lg-3"); $("#div_status").removeClass("col-sm-6 col-lg-3").addClass("col-sm-7 col-lg-5"); } // Charts resizeCharts(); drawTemperatureChart(); drawPrintChart(); } function resetGui() { // Charts drawTemperatureChart(); drawPrintChart(); // Navbar setTitle("Duet Web Control"); setStatusLabel("Disconnected", "default"); // Heater Temperatures $("#table_heaters tr > th:first-child > span").text(""); setCurrentTemperature("bed", undefined); setTemperatureInput("bed", 0, 1); setCurrentTemperature("chamber", undefined); setTemperatureInput("chamber", 0, 1); for(var i=1; i<=6; i++) { setCurrentTemperature(i, undefined); setTemperatureInput(i, 0, 1); setTemperatureInput(i, 0, 0); } // Status fields $("#td_x, #td_y, #td_z").text("n/a"); for(var i=1; i<=numExtruderDrives; i++) { $("#td_extr_" + i).text("n/a"); } $("#td_extr_total").text("n/a"); setProbeValue(-1, undefined); $("#td_fanrpm, #td_cputemp").text("n/a"); $(".cpu-temp").addClass("hidden"); // Control page setAxesHomed([1,1,1]); setATXPower(false); $('#slider_fan_control').slider("setValue", 35); // Print Status $(".row-progress").addClass("hidden"); setProgress(100, "", ""); $("#override_fan, #auto_sleep").prop("checked", false); $('#slider_fan_print').slider("setValue", 35); $("#page_print dd, #panel_print_info table td, #table_estimations td").html("n/a"); $('#slider_speed').slider("setValue", 100); for(var extr=1; extr<=6; extr++) { $("#slider_extr_" + extr).slider("setValue", 100); } // G-Code Console is not cleared automatically // G-Code Files updateGCodeFiles(); // Macro Files updateMacroFiles(); // Settings $("#firmware_name, #firmware_version").html("n/a"); $("#page_machine td:not(:first-child), #page_machine dd").html("n/a"); $("#div_config > h1").removeClass("hidden").html(T("Connect to your Duet to display the configuration file")); $("#text_config").addClass("hidden"); // Modal dialogs $("#modal_upload").modal("hide"); } function updateWebcam(externalTrigger) { if (externalTrigger && webcamUpdating) { // When the settings are applied, make sure this only runs once return; } if (settings.webcamURL == "") { webcamUpdating = false; } else { var newURL = settings.webcamURL; if (newURL.indexOf("?") == -1) { newURL += "?dummy=" + Math.random(); } else { newURL += "&dummy=" + Math.random(); } $("#img_webcam").attr("src", newURL); webcamUpdating = true; setTimeout(function() { updateWebcam(false); }, settings.webcamInterval); } } /* Dynamic GUI Events */ $("body").on("click", ".bed-temp", function(e) { if ($(this).parents("#tr_bed").length > 0) { sendGCode("M140 S" + $(this).data("temp")); } else { sendGCode("M141 S" + $(this).data("temp")); } e.preventDefault(); }); $("body").on("click", ".btn-macro", function(e) { var directory = $(this).data("directory"); if (directory != undefined) { var dropdown = $(this).parent().children("ul"); dropdown.css("width", $(this).outerWidth()); loadMacroDropdown(directory, dropdown); dropdown.dropdown(); } else { sendGCode("M98 P" + $(this).data("macro")); } e.preventDefault(); }); $("body").on("click", ".btn-print-file, .gcode-file", function(e) { var file = $(this).parents("tr").data("file"); showConfirmationDialog(T("Start Print"), T("Do you want to print {0}?", file), function() { waitingForPrintStart = true; if (currentGCodeDirectory == "/gcodes") { sendGCode("M32 " + file); } else { sendGCode("M32 " + currentGCodeDirectory.substring(8) + "/" + file); } }); e.preventDefault(); }); $("body").on("click", ".btn-delete-file", function(e) { var row = $(this).parents("tr"); var file = row.data("file"); showConfirmationDialog(T("Delete File"), T("Are you sure you want to delete {0}?", file), function() { $.ajax("rr_delete?name=" + encodeURIComponent(currentGCodeDirectory + "/" + file), { dataType: "json", row: row, file: file, success: function(response) { if (response.err == 0) { this.row.remove(); if ($("#table_gcode_files tbody").children().length == 0) { gcodeUpdateIndex = -1; updateGCodeFiles(); } } else { showMessage("warning", T("Deletion failed"), T("Warning: Could not delete file {0}!", this.file)); } } }); }); e.preventDefault(); }); $("body").on("click", ".btn-delete-gcode-directory", function(e) { var row = $(this).parents("tr"); var directory = row.data("directory"); $.ajax("rr_delete?name=" + encodeURIComponent(currentGCodeDirectory + "/" + directory), { dataType: "json", row: row, directory: directory, success: function(response) { if (response.err == 0) { this.row.remove(); if ($("#table_gcode_files tbody").children().length == 0) { gcodeUpdateIndex = -1; updateGCodeFiles(); } } else { showMessage("warning", T("Deletion failed"), T("Warning: Could not delete directory {0}!

    Perhaps it isn't empty?", this.directory)); } } }); e.preventDefault(); }); $("body").on("click", ".btn-delete-parent", function(e) { $(this).parents("tr, li").remove(); e.preventDefault(); }); $("body").on("click", ".btn-delete-macro-directory", function(e) { var row = $(this).parents("tr"); var directory = row.data("directory"); $.ajax("rr_delete?name=" + encodeURIComponent(currentMacroDirectory + "/" + directory), { dataType: "json", row: row, directory: directory, success: function(response) { if (response.err == 0) { if (currentMacroDirectory == "/macros") { var button = $("#panel_macro_buttons button[data-macro='" + currentMacroDirectory + "/" + this.directory + "']"); button.remove(); } this.row.remove(); if ($("#table_macro_files tbody").children().length == 0) { macroUpdateIndex = -1; updateMacroFiles(); } } else { showMessage("warning", T("Deletion failed"), T("Warning: Could not delete directory {0}!

    Perhaps it isn't empty?", this.directory)); } } }); e.preventDefault(); }); $("body").on("click", ".btn-delete-macro", function(e) { var macroFile = $(this).parents("tr").data("file"); showConfirmationDialog("Delete File", "Are you sure you want to delete " + macroFile + "?", function() { $.ajax("rr_delete?name=" + encodeURIComponent(currentMacroDirectory + "/" + macroFile), { dataType: "json", macro: macroFile, success: function(response) { if (response.err == 0) { $("#table_macro_files tr[data-item='" + macroFile + "'], #panel_macro_buttons button[data-macro='" + currentMacroDirectory + "/" + macroFile + "']").remove(); if ($("#table_macro_files tbody").children().length == 0) { macroUpdateIndex = -1; updateMacroFiles(); } } else { showMessage("warning", T("Deletion failed"), T("Warning: Could not delete macro {0}!", this.macro)); } } }); }); e.preventDefault(); }); $("body").on("click", ".btn-remove-tool", function(e) { var tool = $(this).parents("div.panel-body").data("tool"); showConfirmationDialog(T("Delete Tool"), T("Are you sure you wish to remove tool {0}?", tool), function() { sendGCode("M563 P" + tool + " D-1 H-1"); extendedStatusCounter = settings.extendedStatusInterval; }); e.preventDefault(); }); $("body").on("click", ".btn-run-macro", function(e) { sendGCode("M98 P" + currentMacroDirectory + "/" + $(this).parents("tr").data("file")); e.preventDefault(); }); $("body").on("click", ".btn-select-tool", function(e) { var tool = $(this).parents("div.panel-body").data("tool"); if (lastStatusResponse != undefined && lastStatusResponse.currentTool == tool) { changeTool(-1); } else { changeTool(tool); } e.preventDefault(); }); $("body").on("click", "#dropdown_language a", function(e) { $("#btn_language > span:first-child").text($(this).text()); $("#btn_language").data("language", $(this).data("language")); e.preventDefault(); }); $("body").on("click", ".filament-usage", function(e) { if (window.matchMedia('(max-width: 991px)').matches) { // Display filament usage for small devices on click showMessage("info", T("Filament usage"), $(this).attr("title")); } e.preventDefault(); }); $("body").on("click", ".gcode", function(e) { if (isConnected) { // If this G-Code isn't performed by a button, treat it as a manual input sendGCode($(this).data("gcode"), !($(this).is(".btn"))); } e.preventDefault(); }); $("body").on("click", ".gcode-directory", function(e) { setGCodeDirectory(currentGCodeDirectory + "/" + $(this).parents("tr").data("directory")); gcodeUpdateIndex = -1; updateGCodeFiles(); e.preventDefault(); }); $("body").on("click", ".heater-temp", function(e) { var inputElement = $(this).parents("div.input-group").find("input"); var activeOrStandby = (inputElement.prop("id").match("active$")) ? "S" : "R"; var temperature = $(this).data("temp"); if (inputElement.prop("id").indexOf("all") == -1) { var heater = inputElement.prop("id").match("_h(.)_")[1]; var gcode = ""; getToolsByHeater(heater).forEach(function(tool) { gcode += "G10 P" + tool + " " + activeOrStandby + temperature + "\n"; }); sendGCode(gcode); } else { if (toolMapping != undefined) { var gcode = ""; for(var i=0; i tbody"); } else { targetPath = targetDir + "/" + sourcePath; sourcePath = currentMacroDirectory + "/" + sourcePath; fileTable = $("#table_macro_files > tbody"); } $.ajax("rr_move?old=" + encodeURIComponent(sourcePath) + "&new=" + encodeURIComponent(targetPath), { dataType: "json", row: draggingObject, table: fileTable, success: function(response) { if (response.err == 0) { this.row.remove(); if (this.table.children().length == 0) { if (currentPage == "files") { gcodeUpdateIndex = -1; updateGCodeFiles(); } else { macroUpdateIndex = -1; updateMacroFiles(); } } } } }); e.stopPropagation(); e.preventDefault(); } }); $("body").on("click", ".tool", function(e) { changeTool($(this).data("tool")); e.preventDefault(); }); $("body").on("hidden.bs.popover", function() { $(this).popover("destroy"); }); /* Static GUI Events */ $("#a_heaters_off").click(function(e) { if (isConnected) { var gcode = ""; // Turn off nozzle heaters if (toolMapping != undefined) { for(var i=0; i' + $("#input_gcode_description").val().trim() + ''; item += ''; $("#table_gcodes").append(item); e.preventDefault(); }); $("#btn_add_head_temp").click(function(e) { var temperature = checkBoundaries($("#input_add_head_temp").val(), 0, -273.15, 300); var type = $('input[name="temp_selection"]:checked').val(); var item = '
  • ' + temperature + ' °C'; item += '
  • '; $("#ul_" + type + "_temps").append(item); e.preventDefault(); }); $("#btn_add_bed_temp").click(function(e) { var temperature = checkBoundaries($("#input_add_bed_temp").val(), 0, -273.15, 180); var item = '
  • ' + temperature + ' °C'; item += '
  • '; $("#ul_bed_temps").append(item); e.preventDefault(); }); $("#btn_add_tool").click(function(e) { var gcode = "M563 P" + $("#input_tool_number").val(); var drives = $("input[name='tool_drives']:checked"); if (drives != undefined) { var driveList = []; drives.each(function() { driveList.push($(this).val()); }); gcode += " D" + driveList.reduce(function(a, b) { return a + ":" + b; }); } var heaters = $("input[name='tool_heaters']:checked"); if (heaters != undefined) { var heaterList = []; heaters.each(function() { heaterList.push($(this).val()); }); gcode += " H" + heaterList.reduce(function(a, b) { return a + ":" + b; }); } sendGCode(gcode); extendedStatusCounter = settings.extendedStatusInterval; e.preventDefault(); }); $("#btn_cancel").click(function() { sendGCode("M0 H1"); // Stop / Cancel Print, but leave all the heaters on $(this).addClass("disabled"); }); $("#btn_cancel_upload").click(function() { cancelUpload(); }); $(".btn-connect").click(function() { if (!isConnected) { // Attempt to connect with the last-known password first connect(sessionPassword, true); } else { disconnect(); } }); $(".btn-emergency-stop").click(function() { if (settings.confirmStop) { showConfirmationDialog(T("Emergency STOP"), T("This will turn off everything and perform a software reset.

    Are you REALLY sure you want to do this?"), function() { sendGCode("M112\nM999"); }); } else { sendGCode("M112\nM999"); } }); $("#btn_fw_diagnostics").click(function() { if (isConnected) { sendGCode("M122"); showPage("console"); } }); $("#btn_clear_log").click(function(e) { $("#console_log").html(""); log("info", "" + T("Message Log cleared!") + ""); e.preventDefault(); }); // TODO: deal with mixing drives $("#btn_extrude").click(function(e) { var feedrate = $("#panel_extrude input[name=feedrate]:checked").val() * 60; var amount = $("#panel_extrude input[name=feed]:checked").val(); sendGCode("M120\nM83\nG1 E" + amount + " F" + feedrate + "\nM121"); }); $("#btn_retract").click(function(e) { var feedrate = $("#panel_extrude input[name=feedrate]:checked").val() * 60; var amount = $("#panel_extrude input[name=feed]:checked").val(); sendGCode("M120\nM83\nG1 E-" + amount + " F" + feedrate + "\nM121"); }); $(".btn-hide-info").click(function() { if ($(this).hasClass("active")) { $("#row_info").addClass("hidden-xs hidden-sm"); $("#main_content").addClass("content-collapsed-padding"); setTimeout(function() { $(".btn-hide-info").removeClass("active"); }, 100); } else { $("#row_info").removeClass("hidden-xs hidden-sm"); $("#main_content").removeClass("content-collapsed-padding"); setTimeout(function() { $(".btn-hide-info").addClass("active"); }, 100); } $(this).blur(); }); $(".btn-home-x").resize(function() { if (geometry != "delta") { var width = $(this).parent().width(); if (width > 0) { $("#btn_homeall").css("min-width", width); } } }).resize(); $("#mobile_home_buttons button, #btn_homeall, #table_move_head a").click(function(e) { $this = $(this); if ($this.data("home") != undefined) { if ($this.data("home") == "all") { sendGCode("G28"); } else { sendGCode("G28 " + $this.data("home")); } } else { var moveString = "M120\nG91\nG1"; if ($this.data("x") != undefined) { moveString += " X" + $this.data("x"); } if ($this.data("y") != undefined) { moveString += " Y" + $this.data("y"); } if ($this.data("z") != undefined) { moveString += " Z" + $this.data("z"); } moveString += " F" + settings.moveFeedrate + "\nM121"; sendGCode(moveString); } e.preventDefault(); }); $("#btn_new_gcode_directory").click(function() { showTextInput(T("New directory"), T("Please enter a name:"), function(value) { $.ajax("rr_mkdir?dir=" + currentGCodeDirectory + "/" + value, { dataType: "json", success: function(response) { if (response.err == 0) { gcodeUpdateIndex = -1; updateGCodeFiles(); } else { showMessage("warning", T("Error"), T("Could not create this directory!")); } } }); }); }); $("#btn_new_macro_directory").click(function() { showTextInput(T("New directory"), T("Please enter a name:"), function(value) { $.ajax("rr_mkdir?dir=" + currentMacroDirectory + "/" + value, { dataType: "json", success: function(response) { if (response.err == 0) { macroUpdateIndex = -1; updateMacroFiles(); } else { showMessage("warning", T("Error"), T("Could not create this directory!")); } } }); }); }); $("#btn_pause").click(function() { if (isPaused) { sendGCode("M24"); // Resume } else if (isPrinting) { sendGCode("M25"); // Pause } $(this).addClass("disabled"); }); $(".btn-upload").click(function(e) { if (!$(this).is(".disabled")) { $("#input_file_upload").data("type", $(this).data("type")).click(); } e.preventDefault(); }); $("#btn_reset_settings").click(function(e) { showConfirmationDialog(T("Reset Settings"), T("Are you sure you want to revert to Factory Settings?"), function() { if (defaultSettings.language != settings.language) { showMessage("info", T("Language has changed"), T("You have changed the current language. Please reload the web interface to apply this change."), 0); } settings = jQuery.extend(true, {}, defaultSettings); $("#btn_language").data("language", "en").children("span:first-child").text("English"); saveSettings(); applySettings(); }); e.preventDefault(); }); ["print", "gcode", "macro", "generic"].forEach(function(type) { var child = $(".btn-upload[data-type='" + type + "']"); // Drag Enter child.on("dragover", function(e) { $(this).removeClass($(this).data("style")).addClass("btn-success"); e.preventDefault(); e.stopPropagation(); }); // Drag Leave child.on("dragleave", function(e) { $(this).removeClass("btn-success").addClass($(this).data("style")); e.preventDefault(); e.stopPropagation(); }); // Drop child.on("drop", function(e) { $(this).removeClass("btn-success").addClass($(this).data("style")); e.preventDefault(); e.stopPropagation(); var files = e.originalEvent.dataTransfer.files; if (!$(this).is(".disabled") && files != null && files.length > 0) { // Start new file upload startUpload($(this).data("type"), files, false); } }); }); $(".gcode-input").submit(function(e) { if (isConnected) { var gcode = $(this).find("input").val(); if (settings.uppercaseGCode) { gcode = gcode.toUpperCase(); } sendGCode(gcode, true); $(this).find("input").select(); } e.preventDefault(); }); // Make the auto-complete dropdown items look proper. // This should be replaced by proper CSS someday, but // for now we only check which elements may float around. $(".div-gcodes").bind("shown.bs.dropdown", function() { var maxWidth = 0; $(this).find("ul > li > a").each(function() { var rowWidth = 0; $(this).find("span").each(function() { rowWidth += $(this).width(); }); if (rowWidth > maxWidth) { maxWidth = rowWidth; } }); if (maxWidth > 0) { $(this).find("ul > li > a").each(function() { var rowWidth = 0; $(this).find("span").each(function() { rowWidth += $(this).width(); }); if (rowWidth < maxWidth) { $(this).addClass("gcode-float"); } }); } }); $("#frm_settings").submit(function(e) { saveSettings(); applySettings(); e.preventDefault(); }); $("#frm_settings > ul > li a").on("shown.bs.tab", function(e) { $("#frm_settings > ul li").removeClass("active"); var links = $('#frm_settings > ul > li a[href="' + $(this).attr("href") + '"]'); $.each(links, function() { $(this).parent().addClass("active"); }); }); $("input[type='number']").focus(function() { var input = $(this); setTimeout(function() { input.select(); }, 10); }); $("input[name='temp_selection']:radio").change(function() { if ($(this).val() == "active") { $("#ul_active_temps").removeClass("hidden"); $("#ul_standby_temps").addClass("hidden"); } else { $("#ul_standby_temps").removeClass("hidden"); $("#ul_active_temps").addClass("hidden"); } }); $("#input_file_upload").change(function(e) { if (this.files.length > 0) { // For POST uploads, we need file blobs startUpload($(this).data("type"), this.files, false); } }); $("#input_temp_bed").keydown(function(e) { var enterKeyPressed = (e.which == 13); enterKeyPressed |= (e.which == 9 && window.matchMedia('(max-width: 991px)').matches); // need this for Android if (isConnected && enterKeyPressed) { sendGCode("M140 S" + $(this).val()); $(this).select(); e.preventDefault(); } }); $("#input_temp_chamber").keydown(function(e) { var enterKeyPressed = (e.which == 13); enterKeyPressed |= (e.which == 9 && window.matchMedia('(max-width: 991px)').matches); // need this for Android if (isConnected && enterKeyPressed) { sendGCode("M141 S" + $(this).val()); $(this).select(); e.preventDefault(); } }); $("input[id^='input_temp_h']").keydown(function(e) { var enterKeyPressed = (e.which == 13); enterKeyPressed |= (e.which == 9 && window.matchMedia('(max-width: 991px)').matches); // need this for Android if (isConnected && enterKeyPressed) { var activeOrStandby = ($(this).prop("id").match("active$")) ? "S" : "R"; var heater = $(this).prop("id").match("_h(.)_")[1]; var temperature = $(this).val(); var gcode = ""; getToolsByHeater(heater).forEach(function(toolNumber) { gcode += "G10 P" + toolNumber + " " + activeOrStandby + temperature + "\n"; }); sendGCode(gcode); $(this).select(); e.preventDefault(); } }); $("#input_temp_all_active, #input_temp_all_standby").keydown(function(e) { if (isConnected && e.which == 13) { if (toolMapping != undefined) { var activeOrStandby = ($(this).prop("id").match("active$")) ? "S" : "R"; var temperature = $(this).val(); var gcode = ""; for(var i=0; i abbr").click(function(e) { showMessage("warning", T("Warning"), T("Some axes are not homed")); e.preventDefault(); }); $(".navlink").click(function(e) { $(this).blur(); showPage($(this).data("target")); e.preventDefault(); }); $("#page_listitems input").on("input", function() { // Validate form controls $("#btn_add_gcode").toggleClass("disabled", $("#input_gcode").val().trim() == "" || $("#input_gcode_description").val().trim() == ""); $("#btn_add_head_temp").toggleClass("disabled", isNaN(parseFloat($("#input_add_head_temp").val()))); $("#btn_add_bed_temp").toggleClass("disabled", isNaN(parseFloat($("#input_add_bed_temp").val()))); }); $("#page_listitems input").keydown(function(e) { if (e.which == 13) { var button = $(this).parents("div:not(.input-group):eq(0)").find("button"); if (!button.hasClass("disabled")) { button.click(); } e.preventDefault(); } }); $("#panel_control_misc label.btn").click(function() { if ($(this).find("input").val() == 1) { // ATX on sendGCode("M80"); } else { // ATX off showConfirmationDialog(T("ATX Power"), T("Do you really want to turn off ATX power?

    This will turn off all drives, heaters and fans."), function() { sendGCode("M81"); }); } }); $("#panel_extrude label.btn").click(function() { $(this).parent().find("label.btn").removeClass("btn-primary").addClass("btn-default"); $(this).removeClass("btn-default").addClass("btn-primary"); }); $(".span-refresh-files").click(function() { gcodeUpdateIndex = -1; updateGCodeFiles(); $(".span-refresh-files").addClass("hidden"); }); $(".span-refresh-macros").click(function() { macroUpdateIndex = -1; updateMacroFiles(); $(".span-refresh-macros").addClass("hidden"); }); $(document).delegate('#text_config', 'keydown', function(e) { var keyCode = e.keyCode || e.which; if (keyCode == 9) { e.preventDefault(); var start = $(this).get(0).selectionStart; var end = $(this).get(0).selectionEnd; // set textarea value to: text before caret + tab + text after caret $(this).val($(this).val().substring(0, start) + "\t" + $(this).val().substring(end)); // put caret at right position again $(this).get(0).selectionStart = $(this).get(0).selectionEnd = start + 1; } }); $(".panel-chart").resize(function() { resizeCharts(); }); $('a[href="#page_general"], a[href="#page_listitems"]').on('shown.bs.tab', function () { $("#row_save_settings, #btn_reset_settings").removeClass("hidden"); }); $('a[href="#page_config"]').on('shown.bs.tab', function() { $("#row_save_settings, #btn_reset_settings").addClass("hidden"); $("#text_config").trigger("input"); getConfigFile(); }); $('a[href="#page_machine"], a[href="#page_tools"]').on('shown.bs.tab', function () { $("#row_save_settings").addClass("hidden"); }); $("#table_heaters a").click(function(e) { if (isConnected && lastStatusResponse != undefined) { if ($(this).parents("#tr_bed").length > 0) { var bedState = lastStatusResponse.temps.bed.state; if (bedState == 3) { showMessage("danger", T("Heater Fault"), T("Error: A heater fault has occured on this particular heater.

    Please turn off your machine and check your wiring for loose connections.")); } else if (bedState == 2) { // Put bed into standby mode sendGCode("M144"); } else { // Bed is either off or in standby mode, send M140 to turn it back on sendGCode("M140 S" + $("#input_temp_bed").val()); } } else { var heater = $(this).parents("tr").index(); var heaterState = lastStatusResponse.temps.heads.state[heater - 1]; if (heaterState == 3) { showMessage("danger", T("Heater Fault"), T("Error: A heater fault has occured on this particular heater.

    Please turn off your machine and check your wiring for loose connections.")); } else { var tools = getToolsByHeater(heater), hasToolSelected = false; tools.forEach(function(tool) { if (tool == lastStatusResponse.currentTool) { hasToolSelected = true; } }); if (hasToolSelected) { changeTool(-1); $(this).blur(); } else if (tools.length == 1) { changeTool(tools[0]); $(this).blur(); } else if (tools.length > 0) { var popover = $(this).parent().children("div.popover"); if (popover.length) { $(this).popover("hide"); $(this).blur(); } else { var content = '
    '; tools.forEach(function(toolNumber) { content += ''; }); content += '
    '; $(this).popover({ content: content, html: true, title: T("Select Tool"), trigger: "manual", placement: "bottom", }).popover("show"); } } } } } e.preventDefault(); }); $("#table_define_tool input[type='checkbox']").change(function() { var isChecked = $(this).is(":checked"); $(this).parents("label").toggleClass("btn-primary", isChecked).toggleClass("btn-default", !isChecked); validateAddTool(); }); $("#table_define_tool input[type='number']").on("input", function() { validateAddTool(); }); function validateAddTool() { var toolNumber = parseInt($("#input_tool_number").val()); var disableButton = (!isConnected) || (isNaN(toolNumber) || toolNumber < 0 || toolNumber > 255) || (toolMapping != undefined && getTool(toolNumber) != undefined) || ($("input[name='tool_heaters']:checked").length + $("input[name='tool_drives']:checked").length == 0); $("#btn_add_tool").toggleClass("disabled", disableButton); } $("#table_define_tool input[type='number']").keydown(function(e) { if (e.which == 13) { if (!$("#btn_add_tool").hasClass("disabled")) { $("#btn_add_tool").click(); } e.preventDefault(); } }); $("#table_heaters tr > th:first-child > a").blur(function() { $(this).popover("hide"); }); $("#ul_control_dropdown").click(function(e) { $(this).find(".dropdown").removeClass("open"); if ($(e.target).is("a")) { $(this).parents(".dropdown").removeClass("open"); } else { e.stopPropagation(); } }); $("#ul_control_dropdown .btn-active-temp, #ul_control_dropdown .btn-standby-temp").click(function(e) { $(this).parent().toggleClass("open"); e.stopPropagation(); }); /* Temperature charts */ function addLayerData(lastLayerTime, updateGui) { layerData.push([layerData.length + 1, lastLayerTime]); if (lastLayerTime > maxLayerTime) { maxLayerTime = lastLayerTime; } if (updateGui) { $("#td_last_layertime").html(convertSeconds(lastLayerTime)).addClass("layer-done-animation"); setTimeout(function() { $("#td_last_layertime").removeClass("layer-done-animation"); }, 2000); drawPrintChart(); } } function drawTemperatureChart() { // Only draw the chart if it's possible if ($("#chart_temp").width() === 0) { refreshTempChart = true; return; } // Prepare the data var preparedBedTemps = []; for(var i=0; i 2) { for(var i=(layerData.length > 26) ? layerData.length - 25 : 1; i < layerData.length; i++) { if (maxY < layerData[i][1] * 1.1) { maxY = layerData[i][1] * 1.1; } } } else if (layerData.length > 0) { maxY = layerData[0][1] * 1.1; } printChartOptions.yaxis.max = maxY; printChartOptions.yaxis.panRange = [0, (maxLayerTime < maxY) ? maxY : maxLayerTime]; printChartOptions.yaxis.zoomRange = [30, (maxLayerTime < maxY) ? maxY : maxLayerTime]; // Update chart and pan to the right printChart = $.plot("#chart_print", [layerData], printChartOptions); printChart.pan({ left: 99999 }); refreshPrintChart = false; // Add hover events to chart $("#chart_print").unbind("plothover").bind("plothover", function (event, pos, item) { if (item) { var layer = item.datapoint[0]; if (layer == 0) { layer = 1; } $("#layer_tooltip").html(T("Layer {0}: {1}", layer, convertSeconds(item.datapoint[1]))) .css({top: item.pageY + 5, left: item.pageX + 5}) .fadeIn(200); } else { $("#layer_tooltip").hide(); } }); } function resizeCharts() { var headsHeight = $("#table_heaters").height(); var statusHeight = 0; $("#div_status table").each(function() { statusHeight += $(this).outerHeight(); }); var max = (headsHeight > statusHeight) ? headsHeight : statusHeight; max -= tempChartPadding; if (max > 0) { $("#chart_temp").css("height", max); } if (refreshTempChart) { drawTemperatureChart(); } if (refreshPrintChart) { drawPrintChart(); } } /* Sliders */ $('#slider_fan_control').slider({ enabled: false, id: "fan_control", min: 0, max: 100, step: 1, value: 35, tooltip: "always", formatter: function(value) { return value + " %"; } }).on("slideStart", function() { fanSliderActive = true; }).on("slideStop", function(slideEvt) { if (isConnected && !isNaN(slideEvt.value)) { sendGCode("M106 S" + (slideEvt.value / 100.0)); $("#slider_fan_print").slider("setValue", slideEvt.value); } fanSliderActive = false; }); $('#slider_fan_print').slider({ enabled: false, id: "fan_print", min: 0, max: 100, step: 1, value: 35, tooltip: "always", formatter: function(value) { return value + " %"; } }).on("slideStart", function() { fanSliderActive = true; }).on("slideStop", function(slideEvt) { if (isConnected && !isNaN(slideEvt.value)) { sendGCode("M106 S" + (slideEvt.value / 100.0)); $("#slider_fan_control").slider("setValue", slideEvt.value); } fanSliderActive = false; }); for(var extr=1; extr<=6; extr++) { $('#slider_extr_' + extr).slider({ enabled: false, id: "extr-" + extr, min: 50, max: 150, step: 1, value: 100, tooltip: "always", formatter: function(value) { return value + " %"; } }).on("slideStart", function() { extrSliderActive = true; }).on("slideStop", function(slideEvt) { if (isConnected && !isNaN(slideEvt.value)) { sendGCode("M221 D" + $(this).data("drive") + " S" + slideEvt.value); } extrSliderActive = false; }); } $('#slider_speed').slider({ enabled: false, id: "speed", min: 20, max: 200, step: 1, value: 100, tooltip: "always", formatter: function(value) { return value + " %"; } }).on("slideStart", function() { speedSliderActive = true; }).on("slideStop", function(slideEvt) { if (isConnected && !isNaN(slideEvt.value)) { sendGCode("M220 S" + slideEvt.value); } speedSliderActive = false; }); /* Modals */ function showConfirmationDialog(title, message, action) { $("#modal_confirmation h4").html(' ' + title); $("#modal_confirmation p").html(message); $("#modal_confirmation button:first-child").off().one("click", action); $("#modal_confirmation").modal("show"); $("#modal_confirmation .btn-success").focus(); } function showTextInput(title, message, action) { $("#modal_textinput h4").html(title); $("#modal_textinput p").html(message); $("#modal_textinput input").val(""); $("#modal_textinput form").off().submit(function(e) { $("#modal_textinput").modal("hide"); var value = $("#modal_textinput input").val(); if (value.trim() != "") { action(value); } e.preventDefault(); }); $("#modal_textinput").modal("show"); } function showMessage(type, title, message, timeout, allowDismiss) { // Find a suitable icon var icon = "glyphicon glyphicon-info-sign"; if (type == "warning") { icon = "glyphicon glyphicon-warning-sign"; } else if (type == "danger") { icon = "glyphicon glyphicon-exclamation-sign"; } // Check if the title can be displayed as bold text if (title != "") { if (title.indexOf("") == -1) { title = "" + title + ""; } title += "

    "; } // Show the notification var notifySettings = { icon: "glyphicon glyphicon-" + icon, title: title, message: message}; var options = { type: type, allow_dismiss: (allowDismiss == undefined) ? true : allowDismiss, delay: (timeout == undefined) ? settings.notificationTimeout : timeout }; return $.notify(notifySettings, options); } function showPasswordPrompt() { $('#input_password').val(""); $("#modal_pass_input").modal("show"); $("#modal_pass_input").one("hide.bs.modal", function() { // The network request will take a few ms anyway, so no matter if the user has // cancelled the password input, we can reset the Connect button here... $(".btn-connect").removeClass("btn-warning disabled").addClass("btn-info").find("span:not(.glyphicon)").text(T("Connect")); }); } function showUpdateMessage() { var notifySettings = { icon: "glyphicon glyphicon-time", title: "" + T("Updating Firmware...") + "

    ", message: T("Please wait while the firmware is being updated..."), progress: settings.updateReconnectDelay / 100, }; var options = { type: "success", allow_dismiss: false, delay: settings.updateReconnectDelay, timeout: 1000, showProgressbar: true }; return $.notify(notifySettings, options); } $("#modal_pass_input, #modal_textinput").on('shown.bs.modal', function() { $(this).find("input").focus() }); $(".modal").on("hidden.bs.modal", function() { // Bootstrap bug: Padding is added to the right, but never cleaned $("body").css("padding-right", ""); }); $("#form_password").submit(function(e) { $("#modal_pass_input").off("hide.bs.modal").modal("hide"); connect($("#input_password").val(), false); e.preventDefault(); }); /* GUI Helpers */ function addBedTemperature(temperature) { // Drop-Down item $(".ul-bed-temp").append('
  • ' + temperature + ' °C
  • '); $(".btn-bed-temp").removeClass("disabled"); // Entry on Settings page var item = '
  • ' + temperature + ' °C'; item += '
  • '; $("#ul_bed_temps").append(item); } function addDefaultGCode(label, gcode) { // Drop-Down item var item = '
  • '; item += '' + label + ''; item += '' + gcode + ''; item += '
  • '; $(".ul-gcodes").append(item); $(".btn-gcodes").removeClass("disabled"); // Entry on Settings page item = '' + label + ''; item += ''; $("#table_gcodes").append(item); } function addGCodeFile(filename) { $("#page_files h1").addClass("hidden"); var row = ''; row += '' + filename + ''; row += '' + T("loading") + ''; row += 'loading'; row += 'loading'; row += 'loading'; row += '' + T("loading") + ''; $("#table_gcode_files").removeClass("hidden"); return $(row).appendTo("#table_gcode_files"); } function addMacroFile(filename) { // Control Page if (currentMacroDirectory == "/macros") { var label = stripMacroFilename(filename); var macroButton = '
    '; macroButton += ''; macroButton += '
    '; $("#panel_macro_buttons h4").addClass("hidden"); $("#panel_macro_buttons .btn-group-vertical").append(macroButton); } // Macro Page var row = ''; row += '' + filename + ''; row += '' + T("loading") + ''; $("#page_macros h1").addClass("hidden"); $("#table_macro_files").removeClass("hidden"); return $(row).appendTo("#table_macro_files"); } var audioContext = new (window.AudioContext || window.webkitAudioContext); function beep(frequency, duration) { var oscillator = audioContext.createOscillator(); oscillator.type = 'sine'; oscillator.frequency.value = frequency; oscillator.connect(audioContext.destination); oscillator.start(); setTimeout(function() { oscillator.disconnect(); }, duration); } function addHeadTemperature(temperature, type) { // Drop-Down item $(".ul-" + type + "-temp").append('
  • ' + temperature + ' °C
  • '); $(".btn-" + type + "-temp").removeClass("disabled"); // Entry on Settings page var item = '
  • ' + temperature + ' °C'; item += '
  • '; $("#ul_" + type + "_temps").append(item); } function changeTool(tool) { if (tool >= 0) { if (getTool(tool).heaters.length > 0) { // Tool macros are likely to block the HTTP G-Code processor, so we first turn off // the appropriate heater, change the tool and then turn it back on. var firstToolHeater = getTool(tool).heaters; var gcode = "G10 P" + tool + " S-273\n" + "T" + tool + "\n" + "G10 P" + tool + " S" + $("#input_temp_h" + firstToolHeater + "_active").val(); sendGCode(gcode); } else { sendGCode("T" + tool); } } else { sendGCode("T-1"); } } function clearBedTemperatures() { $(".ul-bed-temp, #ul_bed_temps").html(""); $(".btn-bed-temp").addClass("disabled"); } function clearGCodeDirectory() { $("#ol_gcode_directory").children(":not(:last-child)").remove(); $("#ol_gcode_directory").prepend('
  • ' + T("G-Codes Directory") + '
  • '); } function clearGCodeFiles() { $("#table_gcode_files > tbody").remove(); $("#table_gcode_files").addClass("hidden"); $("#page_files h1").removeClass("hidden"); if (isConnected) { $("#page_files h1").text(T("No Files or Directories found")); } else { $("#page_files h1").text(T("Connect to your Duet to display G-Code files")); } } function clearDefaultGCodes() { $(".ul-gcodes").html(""); $("#table_gcodes > tbody").remove(); $(".btn-gcodes").addClass("disabled"); } function clearHeadTemperatures() { $(".ul-active-temp, .ul-standby-temp, #ul_active_temps, #ul_standby_temps").html(""); $(".btn-active-temp, .btn-standby-temp").addClass("disabled"); } function clearMacroDirectory() { $("#ol_macro_directory").children(":not(:last-child)").remove(); $("#ol_macro_directory").prepend('
  • ' + T("Macros Directory") + '
  • '); } function clearMacroFiles() { // Control Page if (currentMacroDirectory == "/macros") { $("#panel_macro_buttons .btn-group-vertical").html(""); $("#panel_macro_buttons h4").removeClass("hidden"); } // Macros Page $("#table_macro_files > tbody").remove(); $("#table_macro_files").addClass("hidden"); $("#page_macros h1").removeClass("hidden"); if (isConnected) { $("#page_macros h1").text(T("No Macro Files found")); } else { $("#page_macros h1").text(T("Connect to your Duet to display Macro files")); } } function convertSeconds(value) { value = Math.round(value); if (value < 0) { value = 0; } var timeLeft = [], temp; if (value >= 3600) { temp = Math.floor(value / 3600); if (temp > 0) { timeLeft.push(temp + "h"); value = value % 3600; } } if (value >= 60) { temp = Math.floor(value / 60); if (temp > 0) { timeLeft.push((temp > 9 ? temp : "0" + temp) + "m"); value = value % 60; } } value = value.toFixed(0); timeLeft.push((value > 9 ? value : "0" + value) + "s"); return timeLeft.reduce(function(a, b) { return a + " " + b; }); } function formatSize(bytes) { if (settings.useKiB) { if (bytes > 1073741824) { // GiB return (bytes / 1073741824).toFixed(1) + " GiB"; } if (bytes > 1048576) { // MiB return (bytes / 1048576).toFixed(1) + " MiB"; } if (bytes > 1024) { // KiB return (bytes / 1024).toFixed(1) + " KiB"; } } else { if (bytes > 1000000000) { // GB return (bytes / 1000000000).toFixed(1) + " GB"; } if (bytes > 1000000) { // MB return (bytes / 1000000).toFixed(1) + " MB"; } if (bytes > 1000) { // KB return (bytes / 1000).toFixed(1) + " KB"; } } return bytes + " B"; } function loadMacroDropdown(directory, dropdown) { $.ajax("rr_files?dir=" + encodeURIComponent(directory), { dataType: "json", directory: directory, dropdown: dropdown, success: function(response) { if (response.files.length == 0) { dropdown.html('
  • ' + T("No files found!") + '
  • '); } else { dropdown.html('
  • ' + directory + '
  • '); var files = response.files.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); }); files.forEach(function(filename) { $.ajax("rr_fileinfo?name=" + encodeURIComponent(directory + "/" + filename), { dataType: "json", directory: directory, dropdown: dropdown, filename: filename, success: function(fileinfo) { var label = stripMacroFilename(filename); if (fileinfo.err == 0) { dropdown.append('
  • ' + label + '
  • '); } else { dropdown.append('
  • ' + label + '
  • '); } $(".macro-file-entry").off("click").click(function(e) { sendGCode("M98 P" + $(this).data("macro")); e.preventDefault(); }); $(".macro-dir-entry").off("click").click(function(e) { var dropdown = $(this).parents("ul"); loadMacroDropdown($(this).data("directory"), dropdown); e.stopPropagation(); e.preventDefault(); }); } }); }); } } }); } function log(style, message) { var entry = '
    '; entry += '
    ' + (new Date()).toLocaleTimeString() + '
    '; entry += '
    ' + message + '
    '; $("#console_log").prepend(entry); } function recordHeaterTemperatures(bedTemp, chamberTemp, headTemps) { // Add bed temperature if (heatedBed) { recordedBedTemperatures.push(bedTemp); } else { recordedBedTemperatures = []; } if (recordedBedTemperatures.length > maxTemperatureSamples) { recordedBedTemperatures.shift(); } // Add chamber temperature if (chamber) { recordedChamberTemperatures.push(chamberTemp); } else { recordedChamberTemperatures = []; } if (recordedChamberTemperatures.length > maxTemperatureSamples) { recordedChamberTemperatures.shift(); } // Add heater temperatures for(var i=0; i maxTemperatureSamples) { recordedHeadTemperatures[i].shift(); } } // Remove invalid data (in case the number of heads has changed) for(var i=headTemps.length; i<6; i++) { recordedHeadTemperatures[i] = []; } } function setAxesHomed(axes) { // Set button colors var unhomedAxes = ""; if (axes[0]) { $(".btn-home-x").removeClass("btn-warning").addClass("btn-primary"); } else { unhomedAxes = (geometry == "delta") ? ", A" : ", X"; $(".btn-home-x").removeClass("btn-primary").addClass("btn-warning"); } if (axes[1]) { $(".btn-home-y").removeClass("btn-warning").addClass("btn-primary"); } else { unhomedAxes += (geometry == "delta") ? ", B" : ", Y"; $(".btn-home-y").removeClass("btn-primary").addClass("btn-warning"); } if (axes[2]) { $(".btn-home-z").removeClass("btn-warning").addClass("btn-primary"); } else { unhomedAxes += (geometry == "delta") ? ", C" : ", Z"; $(".btn-home-z").removeClass("btn-primary").addClass("btn-warning"); } // Set home alert visibility if (unhomedAxes == "") { $(".home-warning").addClass("hidden"); } else { if (unhomedAxes.length > 3) { $("#unhomed_warning").html(T("The following axes are not homed: {0}", unhomedAxes.substring(2))); } else { $("#unhomed_warning").html(T("The following axis is not homed: {0}", unhomedAxes.substring(2))); } $(".home-warning").removeClass("hidden"); } } function setATXPower(value) { $("input[name='atxPower']").prop("checked", false).parent().removeClass("active"); $("input[name='atxPower'][value='" + (value ? "1" : "0") + "']").prop("checked", true).parent().addClass("active"); } function setCurrentTemperature(heater, temperature) { var field = "#tr_head_" + heater + " td"; if (heater == "bed") { field = "#tr_bed td"; } else if (heater == "chamber") { field = "#tr_chamber td"; } if (temperature == undefined) { $(field).first().html("n/a"); } else if (temperature < -270) { $(field).first().html("error"); } else { $(field).first().html(temperature.toFixed(1) + " °C"); } if (heater != "bed" && heater != "chamber" && lastStatusResponse != undefined) { if (lastStatusResponse.currentTool != -1) { var isActiveHead = false; getToolsByHeater(heater).forEach(function(tool) { if (tool == lastStatusResponse.currentTool) { isActiveHead = true; } }); if (isActiveHead) { if (temperature >= coldRetractTemp) { $(".btn-retract").removeClass("disabled"); } else { $(".btn-retract").addClass("disabled"); } if (temperature >= coldExtrudeTemp) { $(".btn-extrude").removeClass("disabled"); } else { $(".btn-extrude").addClass("disabled"); } } } else { $(".btn-retract, .btn-extrude").addClass("disabled"); } } } function setGeometry(g) { // The following may be extended in future versions if (g == "delta") { $("#btn_bed_compensation").text(T("Auto Delta Calibration")); $(".home-buttons div, div.home-buttons").addClass("hidden"); $("td.home-buttons").css("padding-right", "0px"); $("#btn_homeall").css("min-width", ""); } else { $("#btn_bed_compensation").text(T("Auto Bed Compensation")); $(".home-buttons div, div.home-buttons").removeClass("hidden"); $("td.home-buttons").css("padding-right", ""); $("#btn_homeall").resize(); } $("#dd_geometry").text(T(g.charAt(0).toUpperCase() + g.slice(1))); geometry = g; } function setGCodeFileItem(row, size, height, firstLayerHeight, layerHeight, filamentUsage, generatedBy) { row.data("file", row.data("item")); row.children().eq(0).html('').attr("colspan", ""); row.children().eq(1).html(''); var linkCell = row.children().eq(2); linkCell.find("span").removeClass("glyphicon-asterisk").addClass("glyphicon-file"); linkCell.html('' + linkCell.html() + ''); linkCell.find("a")[0].addEventListener("dragstart", fileDragStart, false); linkCell.find("a")[0].addEventListener("dragend", fileDragEnd, false); row.children().eq(3).html(formatSize(size)); if (height > 0) { row.children().eq(4).html(height + " mm"); } else { row.children().eq(4).html("n/a"); } if (layerHeight > 0) { if (firstLayerHeight == undefined) { row.children().eq(5).html(layerHeight + " mm"); } else { row.children().eq(5).html(firstLayerHeight + " / " + layerHeight + " mm"); } } else { row.children().eq(5).html("n/a"); } if (filamentUsage.length > 0) { var totalUsage = filamentUsage.reduce(function(a, b) { return a + b; }).toFixed(1) + " mm"; if (filamentUsage.length == 1) { row.children().eq(6).html(totalUsage); } else { var individualUsage = filamentUsage.reduce(function(a, b) { return a + " mm, " + b; }) + " mm"; var filaUsage = "" + totalUsage + ""; row.children().eq(6).html(filaUsage); } } else { row.children().eq(6).html("n/a"); } if (generatedBy != "") { row.children().eq(7).html(generatedBy); } else { row.children().eq(7).html("n/a"); } } function setGCodeDirectoryItem(row) { row.data("directory", row.data("item")); row.children().eq(1).html(''); var linkCell = row.children().eq(2); linkCell.find("span").removeClass("glyphicon-asterisk").addClass("glyphicon-folder-open"); linkCell.html('' + linkCell.html() + '').prop("colspan", 6); linkCell.find("a")[0].addEventListener("dragstart", fileDragStart, false); linkCell.find("a")[0].addEventListener("dragend", fileDragEnd, false); for(var i=8; i>=3; i--) { row.children().eq(i).remove(); } if (gcodeLastDirectory == undefined) { var firstRow = $("#table_gcode_files tbody > tr:first-child"); if (firstRow != row) { row.insertBefore(firstRow); } } else { row.insertAfter(gcodeLastDirectory); } gcodeLastDirectory = row; } function setGCodeDirectory(directory) { currentGCodeDirectory = directory; $("#ol_gcode_directory").children(":not(:last-child)").remove(); if (directory == "/gcodes") { $("#ol_gcode_directory").prepend('
  • ' + T("G-Codes Directory") + '
  • '); $("#ol_gcode_directory li:last-child").html(' ' + T("Go Up")); } else { var listContent = '
  • ' + T("G-Codes Directory") + '
  • '; var directoryItems = directory.split("/"), directoryPath = "/gcodes"; for(var i=2; i' + directoryItems[i] + ''; } listContent += '
  • ' + directoryItems[directoryItems.length -1] + '
  • '; $("#ol_gcode_directory").prepend(listContent); $("#ol_gcode_directory li:last-child").html(' ' + T("Go Up") + ''); } } function setHeaterState(heater, status, currentTool) { var statusText = "n/a"; switch (status) { case 0: statusText = T("off"); break; case 1: statusText = T("standby"); break; case 2: statusText = T("active"); break; case 3: statusText = T("fault"); break; } if (heater == "bed") { $("#tr_bed > th:first-child > span").text(statusText); } else if (heater == "chamber") { $("#tr_chamber > th:first-child > span").text(statusText); } else { var tools = getToolsByHeater(heater); if (tools.length != 0) { statusText += " (T" + tools.reduce(function(a, b) { return a + ", T" + b; }) + ")"; statusText = statusText.replace("T" + currentTool, "T" + currentTool + ""); if (tools.length > 1) { $("#table_heaters tr > th:first-child").eq(heater).find(".caret").removeClass("hidden"); } else { $("#table_heaters tr > th:first-child").eq(heater).find(".caret").addClass("hidden"); } } else { $("#table_heaters tr > th:first-child").eq(heater).find(".caret").addClass("hidden"); } $("#table_heaters tr > th:first-child").eq(heater).children("span").html(statusText); } } function setMacroFileItem(row, size) { row.data("file", row.data("item")); row.children().eq(0).html(''); row.children().eq(1).html(''); var linkCell = row.children().eq(2); linkCell.find("span").removeClass("glyphicon-asterisk").addClass("glyphicon-file"); linkCell.html('' + linkCell.html() + ''); linkCell.find("a")[0].addEventListener("dragstart", fileDragStart, false); linkCell.find("a")[0].addEventListener("dragend", fileDragEnd, false); row.children().eq(3).html(formatSize(size)); } function setMacroDirectoryItem(row) { if (currentMacroDirectory == "/macros") { var button = $("#panel_macro_buttons button[data-macro='" + currentMacroDirectory + "/" + row.data("item") + "']"); button.html(button.html() + ' '); button.data("directory", button.data("macro")).attr("data-toggle", "dropdown"); button.removeData("macro"); button.parent().append(''); } row.data("directory", row.data("item")); row.children().eq(1).html(''); var linkCell = row.children().eq(2); linkCell.find("span").removeClass("glyphicon-asterisk").addClass("glyphicon-folder-open"); linkCell.html('' + linkCell.html() + '').prop("colspan", 2); linkCell.find("a")[0].addEventListener("dragstart", fileDragStart, false); linkCell.find("a")[0].addEventListener("dragend", fileDragEnd, false); row.children().eq(3).remove(); if (macroLastDirectory == undefined) { var firstRow = $("#table_macro_files tbody > tr:first-child"); if (firstRow != row) { row.insertBefore(firstRow); } } else { row.insertAfter(macroLastDirectory); } macroLastDirectory = row; } function setMacroDirectory(directory) { currentMacroDirectory = directory; $("#ol_macro_directory").children(":not(:last-child)").remove(); if (directory == "/macros") { $("#ol_macro_directory").prepend('
  • ' + T("Macros Directory") + '
  • '); $("#ol_macro_directory li:last-child").html(' ' + T("Go Up")); } else { var listContent = '
  • ' + T("Macros Directory") + '
  • '; var directoryItems = directory.split("/"), directoryPath = "/macros"; for(var i=2; i' + directoryItems[i] + ''; } listContent += '
  • ' + directoryItems[directoryItems.length -1] + '
  • '; $("#ol_macro_directory").prepend(listContent); $("#ol_macro_directory li:last-child").html(' ' + T("Go Up") + ''); } } function setPauseStatus(paused) { if (paused == isPaused) { return; } if (paused) { $("#btn_cancel").removeClass("disabled").parents("div.btn-group").removeClass("hidden"); $("#btn_pause").removeClass("btn-warning disabled").addClass("btn-success").text(T("Resume")).attr("title", T("Resume paused print (M24)")); } else { $("#btn_cancel").parents("div.btn-group").addClass("hidden"); $("#btn_pause").removeClass("btn-success").addClass("btn-warning").text(T("Pause Print")).attr("title", T("Pause current print (M25)")); if (isPrinting) { $("#btn_pause").removeClass("disabled"); } } isPaused = paused; } function setPrintStatus(printing) { if (printing == isPrinting) { return; } if (printing) { if (justConnected) { showPage("print"); } layerData = []; currentLayerTime = maxLayerTime = lastLayerPrintDuration = 0; drawPrintChart(); printHasFinished = false; $(".btn-upload").addClass("disabled"); $("#page_general .btn-upload").removeClass("disabled"); $("#btn_pause").removeClass("disabled"); $(".row-progress").removeClass("hidden"); $("#td_last_layertime").html("n/a"); requestFileInfo(); } else { $("#btn_pause").addClass("disabled"); $(".btn-upload").removeClass("disabled"); if (!isConnected || fileInfo == undefined) { $(".row-progress").addClass("hidden"); } if (isConnected) { if ($("#auto_sleep").is(":checked")) { sendGCode("M1"); $("#auto_sleep").prop("checked", false); } if (!printHasFinished && currentLayerTime > 0) { addLayerData(currentLayerTime, true); $("#td_layertime").html("n/a"); } printHasFinished = true; if (fileInfo != undefined) { setProgress(100, T("Printed {0}, 100% Complete", fileInfo.fileName), undefined); } else { setProgress(100, T("Print Complete!"), undefined); } ["filament", "layer", "file"].forEach(function(id) { if ($("#tl_" + id).html() != "n/a") { $("#tl_" + id).html("00s"); $("#et_" + id).html((new Date()).toLocaleTimeString()); } }); } fileInfo = undefined; } isPrinting = printing; if (waitingForPrintStart && printing) { $("#modal_upload").modal("hide"); showPage("print"); waitingForPrintStart = false; } } function setProbeValue(value, secondaryValue) { if (value < 0) { $("#td_probe").html("n/a"); } else if (secondaryValue == undefined) { $("#td_probe").html(value); } else { $("#td_probe").html(value + " (" + secondaryValue.reduce(function(a, b) { return a + b; }) + ")"); } if (probeTriggerValue != undefined && value > probeTriggerValue && !isPrinting) { $("#td_probe").css("background-color", probeTriggerColor); } else if (probeSlowDownValue != undefined && value > probeSlowDownValue && !isPrinting) { $("#td_probe").css("background-color", probeSlowDownColor); } else { $("#td_probe").css("background-color", ""); } } function setProgress(progress, labelLeft, labelRight) { if (labelLeft != undefined) { $("#span_progress_left").text(labelLeft); } if (labelRight != undefined) { $("#span_progress_right").text(labelRight); } $("#progress").css("width", progress + "%"); } function setStatusLabel(text, style) { text = T(text); $(".label-status").removeClass("label-default label-danger label-info label-warning label-success").addClass("label-" + style).text(text); } function setTemperatureInput(head, value, active) { var tempInputId; if (head == "bed") { tempInputId = "#input_temp_bed"; } else if (head == "chamber") { tempInputId = "#input_temp_chamber"; } else { tempInputId = "#input_temp_h" + head + "_"; tempInputId += (active) ? "active": "standby"; } if (!$(tempInputId).is(":focus")) { $(tempInputId).val((value < 0) ? 0 : value); } } function setTimeLeft(field, value) { if (value == undefined || (value == 0 && isPrinting)) { $("#et_" + field + ", #tl_" + field).html("n/a"); } else { // Estimate end time var now = new Date(); var estEndTime = new Date(now.getTime() + value * 1000); // Date uses ms $("#et_" + field).html(estEndTime.toLocaleTimeString()); // Estimate time left $("#tl_" + field).html(convertSeconds(value)); } } function setTitle(title) { $(".machine-name").html(title); $("head > title").text(title); } function showPage(name) { $(".navitem, .page").removeClass("active"); $(".navitem-" + name + ", #page_" + name).addClass("active"); if (name != currentPage) { if (name == "control") { $("#slider_fan_control").slider("relayout"); if (macroUpdateIndex != knownMacroFiles.length) { updateMacroFiles(); } } if (name == "print") { $("#slider_speed").slider("relayout"); $("#slider_fan_print").slider("relayout"); for(var extr=1; extr<=6; extr++) { $("#slider_extr_" + extr).slider("relayout"); } if (refreshPrintChart) { drawPrintChart(); } waitingForPrintStart = false; } if (name == "console") { currentPage = "console"; if (window.matchMedia('(min-width: 992px)').matches) { $("#page_console input").focus(); } } if (name == "files") { if (gcodeUpdateIndex == knownGCodeFiles.length) { $(".span-refresh-files").removeClass("hidden"); } else { updateGCodeFiles(); } } else { $(".span-refresh-files").addClass("hidden"); } if (name == "macros") { if (macroUpdateIndex == knownMacroFiles.length) { $(".span-refresh-macros").removeClass("hidden"); } else { updateMacroFiles(); } } else { $(".span-refresh-macros").addClass("hidden"); } if (name == "settings" && isConnected) { getConfigResponse(); if ($("#page_config").is(".active")) { getConfigFile(); } } } // Scroll to top of the main content on small devices if (window.matchMedia('(max-width: 991px)').matches) { var offset = (name != "control") ? -9 : 0; $('html, body').animate({ scrollTop: ($('#main_content').offset().top + offset) }, 500); } currentPage = name; } function stripMacroFilename(filename) { var match = filename.match(/(.*)\.\w+/); if (match == null) { label = filename; } else { label = match[1]; } match = label.match(/\d+_(.*)/); if (match != null) { label = match[1]; } return label; } /* Other */ function applyThemeColors(themeActive) { // Update temp chart colors and repaint it tempChartOptions.colors[0] = $("#tr_bed a").css("color"); tempChartOptions.colors[1] = $("#tr_head_1 a").css("color"); tempChartOptions.colors[2] = $("#tr_head_2 a").css("color"); tempChartOptions.colors[3] = $("#tr_head_3 a").css("color"); tempChartOptions.colors[4] = $("#tr_head_4 a").css("color"); tempChartOptions.colors[5] = $("#tr_head_5 a").css("color"); tempChartOptions.colors[6] = $("#tr_chamber th").css("color"); if (tempChart != undefined) { tempChart.destroy(); tempChart = undefined; drawTemperatureChart(); } // Update layer times chart printChartOptions.colors[0] = getColorFromCSS("chart-print-line"); if (printChart != undefined) { printChart.destroy(); printChart = undefined; drawPrintChart(); } if (themeActive) { $("#layer_tooltip").css("background-color", $("#panel_print_info").css("background-color")); } else { $("#layer_tooltip").css("background-color", ""); } // Update Z-probe colors probeSlowDownColor = getColorFromCSS("probe-slow-down"); probeTriggerColor = getColorFromCSS("probe-trigger"); } function getColorFromCSS(classname) { var ghostSpan = $(''); ghostSpan.appendTo("body"); var color = ghostSpan.css("color"); ghostSpan.remove(); return color; } // vim: ts=4:sw=4