├── MultiDuetWebControl-All-2.01.zip ├── MultiDuetWebControl-Duet-2.01.zip ├── README.md ├── buildAll.sh ├── buildDuet.sh └── core ├── Multi.htm ├── MultiLanguage.xml ├── fonts ├── Homenaje-Regular.ttf ├── glyphicons.eot ├── glyphicons.ttf ├── glyphicons.woff └── glyphicons.woff2 └── js ├── MultiDWMC.comm.js ├── MultiDWMC.interface.js └── MultiDWMC.settings.js /MultiDuetWebControl-All-2.01.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanalEstes/MultiDuetWebMonitor/c2532ff9f27465a422f635b7be8310e6adc54e13/MultiDuetWebControl-All-2.01.zip -------------------------------------------------------------------------------- /MultiDuetWebControl-Duet-2.01.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanalEstes/MultiDuetWebMonitor/c2532ff9f27465a422f635b7be8310e6adc54e13/MultiDuetWebControl-Duet-2.01.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MultiDuetWebMonitorControl 2 | 3 | Multi Duet Web Monitoring and Control is a fully-responsive HTML5-based web interface intended to provide "One Pane of Glass" monitoring, and some limited control, of multiple instances of Duet hardware running reprap firmware. 4 | 5 | Design goals: 6 | * Reuse as much code from Duet Web Control as resonably possible. 7 | * Specifically, use the css, fonts, languages translation xml, without changes. 8 | * Use some of the javascript modules without changes. 9 | * Communicate with RepRapFirmware using HTTP GET requests. 10 | * Provide "Arms length" status through color coding of large areas of the screen. 11 | * Be as "Self Operating" as resonably possible, such as auto-connect, auto-retry, auto status update, and similar. 12 | * Duet Multi is specifically NOT intended to replicate all function of "Duet Web Control". 13 | 14 | Multi Duet Web Monitoring and Control is free software; it is licensed under the terms of the GNU Public License v2. 15 | 16 | ## Supported electronics 17 | 18 | At this time the following platforms are supported: 19 | 20 | * Duet 0.6 21 | * Duet 0.8.5 22 | * Duet WiFi 23 | * Duet Ethernet 24 | 25 | 26 | ## Building Multi Duet Web Monitoring and Control 27 | 28 | Pre-built zips are included. See "Installation" below. 29 | 30 | Multi Duet Web Monitoring and Control can be served from three places: 31 | 32 | 1) Public internet "http://danalspub.com/MultiDWMC/" 33 | 2) Any local file system or web server on your network. 34 | 3) Any Duet on your network, after you upload it (see below) via "http://your-printer/multi.htm" 35 | 36 | Because Multi Duet Web Monitoring and Control uses .css, font, language.xml, and other files from DWC, and these other files will only be present on a Duet, there are two different build scripts provided. 37 | 38 | ./buildAll.sh creates a zip with a directory structure and the required extra files making it suitable for (1) and (2) above, that is "served by a file system or web server". 39 | 40 | ./buildDuet.sh creates a zip with a directory structure and files that will work only when uploaded to a Duet that alread has DWC installed, that is "served by a duet". 41 | 42 | To run either script, open a terminal in the github downloaded root directory and run the desired script. Refer to the build script header to see which other tools you will need. These build scripts should run on OS X or Linux. They will not run on windows. 43 | 44 | Once the script has completed, the resulting .zip file, MultiDuetWebControl-$VERSION.zip can be uploaded with the normal DWC upload process. Just upload the whole zip. 45 | 46 | Once uploaded, invoke it via "http://name-or-ip-of-duet/Multi". It need only be loaded on one Duet to monitor any number of duets. 47 | 48 | These packages can be uploaded via Duet Web Control to update the web interface. Due to the extra compression on the Duet WiFi, it is recommended to test new features on first-generation Duets first. 49 | 50 | ## Internationalization 51 | 52 | Multi Duet Web Control uses the same internationalization as Duet Web Control. See details in the Duet Web Control github project on how to enhance or contribute enhancements to the translations. 53 | 54 | ## Installation 55 | 56 | 1) To install on a stand-alone web server, download the "MultiDuetWebControl-All-$VERSION.zip", unzip the entire directory structure to the location of your choice on the web server, and invoke via a URL that opens page "Multi.htm", such as "http://mywebserver/somedir/multi.htm" 57 | 58 | 2) To install on a local PC file system, download the "MultiDuetWebControl-All-$VERSION.zip", unzip the entire directory structure to the location of your choice on the file system, server, and invoke via a URL that opens page "Multi.htm", such as "file:///C:/Users/Joe/MultiDuet/multi.htm" 59 | 60 | 3) To install on a Duet, download the "MultiDuetWebControl-Duet-$VERSION.zip", uplod to the Duet via normal DWC 'Settings' > 'Upload File(s)' buttons. (Do not unzip; just upload the whole zip). Invoke via URL "http://my-duet-name-or-ip/multi.htm". 61 | 62 | Multi Duet Web Control and Monitoring need only be uploaded to one Duet; after loading, other Duets can be added for monitoring. 63 | 64 | ## General Notes 65 | 66 | * ALL configuration information is kept in browser local storage. This means that if you run DMWMC from a different browser than where you originally set up printers, you must re-enter the printer setup information. 67 | 68 | * Passwords are not encrypted, neither "on the wire" nor in browser storage. This is exactly the same as DWC. 69 | 70 | * Duet firmware has some oddities when clients "just go away" without disconnecting. Try and remember to press "Disconnect All and Stop" before closing the page. 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /buildAll.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Build script for MultiDuetWebMonitor 3 | # The "buildAll" flavor produces a package suitable for a stand-alone web server, or file system. 4 | # 5 | # licensed under the terms of the GNU Public License v3, 6 | # derived from build.sh written by Christian Hammacher 2016-2017 for DWC 7 | # rewritten for Multi Duet Web Control by Danal Estes (c) 2018 8 | # 9 | # The following tools are required: 10 | # - yui-compressor from https://yui.github.io/yuicompressor 11 | # - UglifyJS from https://github.com/mishoo/UglifyJS 12 | # - gzip utility 13 | # Make sure all tools are accessible via your PATH environment variable! 14 | 15 | # Optional paths to the required tools 16 | YUI_COMPRESSOR=yuicompressor 17 | UGLIFYJS=uglifyjs 18 | GZIP=gzip 19 | 20 | # Check for required tools 21 | if [[ ! $(type $YUI_COMPRESSOR 2>/dev/null) ]]; then 22 | echo "yui-compressor not found in PATH!" 23 | echo $PATH 24 | exit 25 | fi 26 | 27 | if [[ ! $(type $UGLIFYJS 2>/dev/null) ]]; then 28 | echo "uglifyjs not found in PATH!" 29 | exit 30 | fi 31 | 32 | if [[ ! $(type $GZIP 2>/dev/null) ]]; then 33 | echo "gzip not found in PATH!" 34 | exit 35 | fi 36 | 37 | # Core directory must contain Multi.htm 38 | if [ ! -f "./core/Multi.htm" ] ; then 39 | echo "core directory doesn't contain Multi.htm" 40 | exit 41 | fi 42 | 43 | # Repository for DWC must be in directory at same level (parallel) to MultiDuetWebMonitor 44 | if [ ! -f "../DuetWebControl/core/html404.htm" ] ; then 45 | echo "DWC repository must be in parallel directory. Not Found." 46 | exit 47 | fi 48 | if [ ! -f "../DuetWebControl/core/js/notify.js" ] ; then 49 | echo "DWC repository must be in parallel directory. Not Found." 50 | exit 51 | fi 52 | 53 | # Get the current version 54 | VERSION=$(perl -nl0e 'print $1 if /MultiDWMC Web Interface Version.*(\d.\d\d).*/' ./core/Multi.htm | tr -d '\0') 55 | 56 | # Create an empty build directory and clean up 57 | if [ -d "./build" ] ; then 58 | rm -r ./build 59 | fi 60 | mkdir ./build 61 | set -- MultiDuetWebControl-All*.zip 62 | if [ -f "$1" ]; then 63 | rm -f ./MultiDuetWebControl-All*.zip 64 | fi 65 | 66 | echo "=> Building compressed Duet Multi Web Control v$VERSION bundle" 67 | 68 | # Copy HTML files and change CSS and JS rels 69 | echo "Changing CSS and JS paths in HTML files" 70 | cp ../DuetWebControl/core/html404.htm ./build/html404.htm 71 | cp ./core/Multi.htm ./build/Multi.htm 72 | sed -i '' '/\' ./build/Multi.htm 76 | sed -i '' '/ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Multi Duet Monitor and Control 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 68 | 69 | 70 | 71 | 72 | 73 | 74 |
75 |
109 | 110 | 111 | 134 | 135 | 157 | 158 | 182 | 183 | 194 | 195 | 196 |
197 | 198 | 207 |
208 | 209 | 210 | 211 | 214 | 215 |
216 |
217 |
218 |
219 | 220 |
221 | MultiDWMC Web Interface Version 2.01 222 |
223 |
224 | Limitations of this release: 225 | 229 | 230 |
231 | 232 | Hints: 233 | 236 | 237 |
238 | 239 | ToDo, in very rough order of priority: 240 |
    241 |
  1. Done! Make Status (beyond "Idle") auto-update work.
  2. 242 |
  3. Done: Make Other Buttons work.
  4. 243 |
  5. Done! Allow serving from duet.
  6. 244 |
  7. Test displaying on Phone/Tablet, etc.
  8. 245 |
  9. Temperature is hardcoded to specific heaters. ToDo is bring the correct logic over from DWC so that any configuration (that DWC reports) is reported properly.
  10. 246 |
  11. Export/Import printer setup (to allow to move to another browser.)
  12. 247 |
  13. Done! A way to re-order the printer list (clickable headers?)
  14. 248 |
  15. Done! Maybe: Thicker or more visible lines in the table.
  16. 249 |
  17. Done! This was built on DWC and has enormous swaths of DWC code in it that are not used. ToDo is "Cleanup. Take unusued code out" before putting on Github
  18. 250 |
  19. Done! Put on Github, with instructions on how to download from github and upload to one of your Duets.
  20. 251 | 252 |
253 | 254 |
255 |
256 | Release Notes, 2.01: 257 |
    258 |
  1. Language button now works (translation tables not yet built).
  2. 259 |
  3. Can serve from a Duet.
  4. 260 |
  5. Various bug fixes
  6. 261 |
  7. Removed buttons that did not (yet) work. Some may be added back in future releases.
  8. 262 |
263 | Release Notes, 2.00: 264 |
    265 |
  1. Repackaged to make building for Duet vs. "any server" easier.
  2. 266 |
  3. Added sorting of rows. Not entirely happy with how it works internally, may change it.
  4. 267 |
  5. Added file name and size when printing.
  6. 268 |
269 | Release Notes, 1.03: 270 |
    271 |
  1. Fixed a bug introduced in 1.02 that sometimes prevented newly added printers from obtaining and displaying the board name. (i.e. the name stayed "TBD" forever.)
  2. 272 |
273 | Release Notes, 1.02: 274 |
    275 |
  1. Speedup initial connect on page load.
  2. 276 |
  3. Cleanup wording around IP or HostName in several places
  4. 277 |
  5. Added "Disconnect and Close" button.
  6. 278 |
  7. Made individual line "Disconnect" buttons active.
  8. 279 |
  9. Added completion percentage to status while printing
  10. 280 |
281 | Release Notes, 1.01: 282 |
    283 |
  1. Allow hostnames (in addition to IP addresses)
  2. 284 |
  3. Fixed table sometimes not (re-)built properly after add or delete
  4. 285 |
286 | 287 | 288 |
289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | z 301 | 302 | 303 | -------------------------------------------------------------------------------- /core/MultiLanguage.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Nächster 6 | Multi Duet Web Überwachung und Kontrolle 7 | Erledigt 8 | Test 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /core/fonts/Homenaje-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanalEstes/MultiDuetWebMonitor/c2532ff9f27465a422f635b7be8310e6adc54e13/core/fonts/Homenaje-Regular.ttf -------------------------------------------------------------------------------- /core/fonts/glyphicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanalEstes/MultiDuetWebMonitor/c2532ff9f27465a422f635b7be8310e6adc54e13/core/fonts/glyphicons.eot -------------------------------------------------------------------------------- /core/fonts/glyphicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanalEstes/MultiDuetWebMonitor/c2532ff9f27465a422f635b7be8310e6adc54e13/core/fonts/glyphicons.ttf -------------------------------------------------------------------------------- /core/fonts/glyphicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanalEstes/MultiDuetWebMonitor/c2532ff9f27465a422f635b7be8310e6adc54e13/core/fonts/glyphicons.woff -------------------------------------------------------------------------------- /core/fonts/glyphicons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanalEstes/MultiDuetWebMonitor/c2532ff9f27465a422f635b7be8310e6adc54e13/core/fonts/glyphicons.woff2 -------------------------------------------------------------------------------- /core/js/MultiDWMC.comm.js: -------------------------------------------------------------------------------- 1 | /* Communication routines between RepRapFirmware and Duet Web Control 2 | * 3 | * written by Christian Hammacher (c) 2016-2017 4 | * modified for Multi by Danal Estes (c) 2018 5 | * 6 | * licensed under the terms of the GPL v3 7 | * see http://www.gnu.org/licenses/gpl-3.0.html 8 | */ 9 | 10 | var sessionTimeout = 8000; // Time in ms before RepRapFirmware kills our session 11 | var ajaxRequests = []; // List of all outstanding AJAX requests 12 | 13 | 14 | /* AJAX Events */ 15 | 16 | $(document).ajaxSend(function (event, jqxhr, settings) { 17 | ajaxRequests.push(jqxhr); 18 | }); 19 | 20 | $(document).ajaxComplete(function (event, jqxhr, settings) { 21 | ajaxRequests = $.grep(ajaxRequests, function (item) { 22 | item != jqxhr; 23 | }); 24 | }); 25 | 26 | $(document).ajaxError(function (event, jqxhr, xhrsettings, thrownError) { 27 | if (thrownError == "abort") { 28 | // Ignore this error if this request was cancelled intentionally 29 | return; 30 | } 31 | console.log(event,thrownError); 32 | 33 | }); 34 | 35 | 36 | /* Connect / Disconnect */ 37 | 38 | 39 | function connect(ip, password) { 40 | ajaxPrefix = 'HTTP://'+ip+'/'; 41 | console.log("Connection attempt ", ajaxPrefix) 42 | 43 | $.ajax(ajaxPrefix + "rr_connect?password=" + password + "&time=" + encodeURIComponent(timeToStr(new Date())), { 44 | dataType: "json", 45 | error: function (response) { 46 | console.log("Connection Fail ",response.statusText) 47 | //showMessage("danger", T("Error"), T("Could not establish a connection to the Duet "+ip+" firmware! Please check your settings and try again.") , 30); 48 | updateRowConnectFail(ip); 49 | }, 50 | success: function (response) { 51 | console.log("Connection OK ", response) 52 | if (response.err == 2) { // Looks like the firmware ran out of HTTP sessions 53 | showMessage("danger", T("Error"), T("Could not connect to Duet "+ip+", because there are no more HTTP sessions available."), 30); 54 | } else if (response.err == 0) { 55 | postConnect(response,ip); 56 | } else { 57 | showMessage("danger", T("Error"), T("Invalid password!"), 0); 58 | } 59 | } 60 | }); 61 | } 62 | 63 | function postConnect(response,ip) { 64 | if (response.hasOwnProperty("sessionTimeout")) { 65 | sessionTimeout = response.sessionTimeout; 66 | $.ajaxSetup({ 67 | timeout: sessionTimeout / (settings.maxRetries + 1) 68 | }); 69 | } 70 | if (response.hasOwnProperty("boardType")) { 71 | setBoardType(response.boardType,ip); 72 | } 73 | showMessage("success", T("Connected"), T("Connected to Duet "+ip+". Starting automatic status tracking"), 40); 74 | updateRowConnected(ip); 75 | //log("success", "" + T("Connection established!") + ""); 76 | } 77 | 78 | 79 | function disconnect(ip) { 80 | ajaxPrefix = 'HTTP://'+ip+'/'; 81 | console.warn("Disconnecting ",ajaxPrefix); 82 | $.ajax(ajaxPrefix + "rr_disconnect", { 83 | dataType: "json", 84 | global: false 85 | }); 86 | updateRowDisconnected(ip) 87 | } 88 | 89 | function requestFileInfo(which) { 90 | ajaxPrefix = 'HTTP://'+printers[which].ip+'/'; 91 | $.ajax(ajaxPrefix + "rr_fileinfo", { 92 | dataType: "json", 93 | success: function (response) { 94 | if (response.err == 2) { 95 | // The firmware is still busy parsing the file, so try again until it's ready 96 | setTimeout(function () { 97 | requestFileInfo(); 98 | }, 250); 99 | } else if (response.err == 0) { 100 | // File info is valid, use it 101 | printersStatus[which].fileinfo = response; 102 | } 103 | } 104 | }); 105 | } 106 | 107 | 108 | 109 | // Send G-Code directly to the firmware 110 | function sendGCode(ip, gcode) { 111 | if (gcode == "") { 112 | return; 113 | } 114 | 115 | // Although rr_gcode gives us a JSON response, it doesn't provide any useful values for DWC. 116 | // We only need to worry about an AJAX error event, which is handled by the global AJAX error callback. 117 | var ajaxPrefix = 'HTTP://'+ip+'/'; 118 | $.ajax(ajaxPrefix + "rr_gcode?gcode=" + encodeURIComponent(gcode), { 119 | dataType: "json" 120 | }); 121 | } 122 | 123 | -------------------------------------------------------------------------------- /core/js/MultiDWMC.interface.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* Main interface logic for Multi Duet Web Monitoring and Control 4 | * 5 | * written by Danal Estes (c) 2018 6 | * inspired by Christian Hammacher's DWC 7 | * 8 | * licensed under the terms of the GPL v3 9 | * see http://www.gnu.org/licenses/gpl-3.0.html 10 | */ 11 | 12 | // Truly Global Variables 13 | printers = []; 14 | printers[0] = {name: 'Example Printer', pwd: "", ip: "192.168.1.20", camurl: "http://192.168.1.21/video"} 15 | printersStatus = []; 16 | printersStatus[0] = {connected: false, status: ''} 17 | 18 | showTranslationWarning = true; // Override the setting in i18n.js, at least for now 19 | 20 | var machineName = "Multi Duet Web Monitoring and Control"; 21 | 22 | var isPrinting, isPaused, printHasFinished; 23 | 24 | function resetGuiData() { 25 | //setBoardType("unknown"); 26 | } 27 | 28 | $(document).ready(function () { 29 | $('[data-min]').each(function () { 30 | $(this).attr("min", $(this).data("min")).attr("step", "any"); 31 | }); 32 | $('[data-max]').each(function () { 33 | $(this).attr("max", $(this).data("max")).attr("step", "any"); 34 | }); 35 | //$('[data-toggle="popover"]').popover(); 36 | $(".app-control").toggleClass("hidden", typeof app === "undefined"); 37 | 38 | //disableControls(); 39 | resetGuiData(); 40 | //updateGui(); 41 | 42 | loadSettings(); 43 | }); 44 | 45 | 46 | function pageLoadComplete() { 47 | // Add link to GitHub and log event 48 | //$("#span_copyright").html($("#span_copyright").html().replace("Christian Hammacher", 'Christian Hammacher')); 49 | //log("info", "" + T("Page Load complete!") + ""); 50 | 51 | // Users may want to connect automatically once the page has loaded 52 | //if (settings.autoConnect) { 53 | // connect(sessionPassword, true); 54 | //} 55 | 56 | // Check if this browser is supported and display a message if it is not 57 | var userAgent = navigator.userAgent.toLowerCase(); 58 | var browserSupported = true; 59 | browserSupported &= (String.prototype.startsWith != undefined); 60 | browserSupported &= (userAgent.indexOf("webkit") != -1 || userAgent.indexOf("gecko") != -1); 61 | if (!browserSupported) { 62 | showMessage("warning", T("Unsupported browser"), "" + T("Warning") + ": " + T("Your browser is not officially supported. To achieve the best experience it is recommended to use either Mozilla Firefox, Google Chrome or Opera."), 0, true); 63 | } 64 | 65 | // Make sure the loaded JS matches the HTML version 66 | if (typeof MDWMCVersion != "undefined" && MDWMCVersion != $("#mdwmc_version").text()) { 67 | showMessage("warning", T("Version mismatch"), "" + T("Warning") + ": " + T("The versions of your HTML and JavaScript files do not match. This can lead to unpredictable behavior and other problems.

FIRST THING TO TRY IS Ctrl+Shift+R."), 0, false); 68 | } 69 | rebuildTable(); 70 | pollForActionsInterval = setInterval(pollForActions,1000); 71 | 72 | } 73 | /* End of initilization. Everything from here driven by pollFor Actions */ 74 | 75 | var cycleCount = 9; // Immediately try to connect. 76 | function pollForActions() { 77 | cycleCount++; 78 | for (var i = 0; i < printers.length; i++) { 79 | if ((0 == cycleCount % 10) && (! printersStatus[i].connected)) { 80 | connect(printers[i].ip,printers[i].pwd) 81 | } 82 | if ((0 == cycleCount % 2 ) && ( printersStatus[i].connected)) { 83 | updateStatusNew(i); 84 | } 85 | } 86 | } 87 | 88 | var statusAlternate = 0; 89 | function updateStatusNew(which) { 90 | var ajaxPrefix = 'HTTP://'+printers[which].ip+'/'; 91 | var ajaxRequest = "rr_status?type=2"; 92 | if ('P' == printersStatus[which].status) {ajaxRequest = "rr_status?type=" + ((statusAlternate = !statusAlternate) ? 2 : 3)}; 93 | //console.log("Requesting ", ajaxPrefix, ajaxRequest) 94 | $.ajax(ajaxPrefix + ajaxRequest, { 95 | dataType: "json", 96 | success: function (status) { 97 | // Don't process this one if we're no longer connected 98 | if ((typeof printersStatus[which] === 'undefined') || (!printersStatus[which].connected)) { 99 | return; 100 | } 101 | if (status.hasOwnProperty("name")) { 102 | updateRowName(which,status.name); 103 | } 104 | if (status.hasOwnProperty("status")) { 105 | updateRowStatus(which,status.status); 106 | } 107 | 108 | if (status.hasOwnProperty("message")) { 109 | showMessage("info", T("Message from Duet firmware"), status.message, 30); 110 | } 111 | 112 | // Hard coded temps, for now 113 | if (status.temps.hasOwnProperty("current") && status.temps.hasOwnProperty("state")) { 114 | updateRowTemp(which, 115 | status.temps.current[1], 116 | status.temps.tools.active[0][0], 117 | status.temps.bed.current, 118 | status.temps.bed.active, 119 | ); 120 | } 121 | 122 | if (status.temps.hasOwnProperty("chamber") && status.temps.hasOwnProperty("state")) { 123 | updateRowTempChamber(which, 124 | status.temps.chamber.current, 125 | status.temps.chamber.active, 126 | ); 127 | } 128 | 129 | /* Capture percent printed, if we received it */ 130 | if (status.hasOwnProperty("fractionPrinted") ) { 131 | var progress = status.fractionPrinted; 132 | if (progress < 0) { 133 | progress = 100; 134 | } 135 | printersStatus[which].progress = progress; 136 | } 137 | /* Plot percent printed, if it is printing */ 138 | if ('P' == printersStatus[which].status) updateRowProgress(which); 139 | 140 | } /* Ajax Success */ 141 | }); 142 | } 143 | 144 | 145 | /* Start of Add A Printer */ 146 | $("#b-addprinter").click({ 147 | apply: function (event) {$('#input_host').val(""); $("#modal_host_input").modal("show");} 148 | }); 149 | 150 | $("#modal_host_input").on("shown.bs.modal", function () { 151 | $("#input_host").focus(); 152 | }); 153 | 154 | $("#form_host").submit(function (e) { 155 | $("#modal_host_input").off("hide.bs.modal").modal("hide"); 156 | var ip = $("#input_host").val(); 157 | e.preventDefault(); 158 | if (ip == '' ) return; 159 | 160 | var badip = 0; 161 | /* 162 | var arrIp = ip.split("."); 163 | if (arrIp.length !== 4) badip=1; 164 | for (let oct of arrIp) { 165 | if ( isNaN(oct) || Number(oct) < 0 || Number(oct) > 255) badip=1; 166 | } 167 | if (badip) showMessage("warning","Malformed IP", "Printer IP " + ip + " is not a valid V4 IP address", 5, true); 168 | */ 169 | 170 | printers.forEach(function(printer) { 171 | if (printer.ip == ip) { 172 | showMessage("warning",T("Duplicate IP or Hostname"), T("Printer ") + ip + T(" already exists"), 5, true); 173 | badip=1; 174 | } 175 | }); 176 | 177 | if (badip) return; 178 | 179 | var i=printers.length; 180 | printers[i]= {name: T("TBD at first status update"), pwd: "", ip: ip, camurl: "Null" }; 181 | printersStatus[i] = {connected: false, status: ''} 182 | rebuildTable(); 183 | showPasswordPrompt(); 184 | }); 185 | 186 | /* 187 | $("body").on("click", ".btn-connect", function () { 188 | console.log("In btn-connect") 189 | if (!$(this).hasClass("disabled")) { 190 | if (!isConnected) { 191 | // Attempt to connect with the last-known password first 192 | //connect(sessionPassword, true); 193 | } else { 194 | //disconnect(true); 195 | } 196 | } 197 | }); 198 | */ 199 | 200 | /* Password prompt */ 201 | 202 | function showPasswordPrompt() { 203 | $('#input_password').val(""); 204 | $("#modal_pass_input").modal("show"); 205 | $("#modal_pass_input").one("hide.bs.modal", function () { 206 | // The network request will take a few ms anyway, so no matter if the user has 207 | // cancelled the password input, we can reset the Connect button here... 208 | $(".btn-connect").removeClass("btn-warning disabled").addClass("btn-info").find("span:not(.glyphicon)").text(T("Connect")); 209 | }); 210 | } 211 | 212 | $("#form_password").submit(function (e) { 213 | $("#modal_pass_input").off("hide.bs.modal").modal("hide"); 214 | printers[printers.length-1].pwd = $("#input_password").val() 215 | e.preventDefault(); 216 | saveSettings(); 217 | rebuildTable(); 218 | }); 219 | 220 | $("#modal_pass_input").on("shown.bs.modal", function () { 221 | $("#input_password").focus(); 222 | }); 223 | 224 | 225 | /* Start of Delete A Printer */ 226 | $("#b-delprinter").click({ 227 | apply: function (event) { 228 | $("#input_del_drop").empty(); 229 | if (0 == printers.length) return 230 | for (i = 0; i < printers.length; i++) { 231 | $("