2013-01-02 15:33:37 +00:00
//~~ View models
2013-03-19 22:06:48 +00:00
function LoginStateViewModel ( ) {
2012-12-28 19:37:40 +00:00
var self = this ;
2013-03-19 22:06:48 +00:00
self . loggedIn = ko . observable ( false ) ;
self . username = ko . observable ( undefined ) ;
self . isAdmin = ko . observable ( false ) ;
self . isUser = ko . observable ( false ) ;
2013-04-13 19:40:28 +00:00
self . currentUser = ko . observable ( undefined ) ;
2013-03-19 22:06:48 +00:00
self . userMenuText = ko . computed ( function ( ) {
if ( self . loggedIn ( ) ) {
return "\"" + self . username ( ) + "\"" ;
} else {
return "Login" ;
}
} )
2013-04-13 19:40:28 +00:00
self . subscribers = [ ] ;
self . subscribe = function ( callback ) {
self . subscribers . push ( callback ) ;
}
2013-03-19 22:06:48 +00:00
self . requestData = function ( ) {
$ . ajax ( {
url : AJAX _BASEURL + "login" ,
type : "POST" ,
data : { "passive" : true } ,
success : self . fromResponse
} )
}
self . fromResponse = function ( response ) {
if ( response && response . name ) {
self . loggedIn ( true ) ;
self . username ( response . name ) ;
self . isUser ( response . user ) ;
self . isAdmin ( response . admin ) ;
2013-04-13 19:40:28 +00:00
self . currentUser ( response ) ;
_ . each ( self . subscribers , function ( callback ) { callback ( "login" , response ) ; } ) ;
2013-03-19 22:06:48 +00:00
} else {
self . loggedIn ( false ) ;
self . username ( undefined ) ;
self . isUser ( false ) ;
self . isAdmin ( false ) ;
2013-04-13 19:40:28 +00:00
self . currentUser ( undefined ) ;
_ . each ( self . subscribers , function ( callback ) { callback ( "logout" , { } ) ; } ) ;
2013-03-19 22:06:48 +00:00
}
}
self . login = function ( ) {
var username = $ ( "#login_user" ) . val ( ) ;
var password = $ ( "#login_pass" ) . val ( ) ;
var remember = $ ( "#login_remember" ) . is ( ":checked" ) ;
2013-04-13 19:40:28 +00:00
$ ( "#login_user" ) . val ( "" ) ;
$ ( "#login_pass" ) . val ( "" ) ;
$ ( "#login_remember" ) . prop ( "checked" , false ) ;
2013-03-19 22:06:48 +00:00
$ . ajax ( {
url : AJAX _BASEURL + "login" ,
type : "POST" ,
data : { "user" : username , "pass" : password , "remember" : remember } ,
success : function ( response ) {
2013-04-13 19:40:28 +00:00
$ . pnotify ( { title : "Login successful" , text : "You are now logged in as \"" + response . name + "\"" , type : "success" } ) ;
2013-03-19 22:06:48 +00:00
self . fromResponse ( response ) ;
} ,
error : function ( jqXHR , textStatus , errorThrown ) {
$ . pnotify ( { title : "Login failed" , text : "User unknown or wrong password" , type : "error" } ) ;
}
} )
}
self . logout = function ( ) {
$ . ajax ( {
url : AJAX _BASEURL + "logout" ,
type : "POST" ,
success : function ( response ) {
$ . pnotify ( { title : "Logout successful" , text : "You are now logged out" , type : "success" } ) ;
self . fromResponse ( response ) ;
}
} )
}
}
function ConnectionViewModel ( loginStateViewModel ) {
var self = this ;
self . loginState = loginStateViewModel ;
2012-12-28 19:37:40 +00:00
self . portOptions = ko . observableArray ( undefined ) ;
self . baudrateOptions = ko . observableArray ( undefined ) ;
self . selectedPort = ko . observable ( undefined ) ;
self . selectedBaudrate = ko . observable ( undefined ) ;
2013-01-01 20:04:00 +00:00
self . saveSettings = ko . observable ( undefined ) ;
2012-12-28 19:37:40 +00:00
self . isErrorOrClosed = ko . observable ( undefined ) ;
self . isOperational = ko . observable ( undefined ) ;
self . isPrinting = ko . observable ( undefined ) ;
self . isPaused = ko . observable ( undefined ) ;
self . isError = ko . observable ( undefined ) ;
self . isReady = ko . observable ( undefined ) ;
self . isLoading = ko . observable ( undefined ) ;
self . buttonText = ko . computed ( function ( ) {
if ( self . isErrorOrClosed ( ) )
return "Connect" ;
else
return "Disconnect" ;
} )
2012-12-29 18:34:55 +00:00
self . previousIsOperational = undefined ;
2013-01-01 20:04:00 +00:00
self . requestData = function ( ) {
$ . ajax ( {
2013-04-12 21:08:14 +00:00
url : AJAX _BASEURL + "control/connection/options" ,
2013-01-01 20:04:00 +00:00
method : "GET" ,
dataType : "json" ,
success : function ( response ) {
self . fromResponse ( response ) ;
}
} )
}
2012-12-28 19:37:40 +00:00
self . fromResponse = function ( response ) {
self . portOptions ( response . ports ) ;
self . baudrateOptions ( response . baudrates ) ;
if ( ! self . selectedPort ( ) && response . ports && response . ports . indexOf ( response . portPreference ) >= 0 )
self . selectedPort ( response . portPreference ) ;
if ( ! self . selectedBaudrate ( ) && response . baudrates && response . baudrates . indexOf ( response . baudratePreference ) >= 0 )
self . selectedBaudrate ( response . baudratePreference ) ;
2013-01-01 20:04:00 +00:00
self . saveSettings ( false ) ;
2012-12-28 19:37:40 +00:00
}
2013-01-11 23:00:58 +00:00
self . fromHistoryData = function ( data ) {
self . _processStateData ( data . state ) ;
}
2013-01-10 22:40:00 +00:00
self . fromCurrentData = function ( data ) {
self . _processStateData ( data . state ) ;
}
self . _processStateData = function ( data ) {
2012-12-29 18:34:55 +00:00
self . previousIsOperational = self . isOperational ( ) ;
2013-01-06 15:51:04 +00:00
self . isErrorOrClosed ( data . flags . closedOrError ) ;
self . isOperational ( data . flags . operational ) ;
self . isPaused ( data . flags . paused ) ;
self . isPrinting ( data . flags . printing ) ;
self . isError ( data . flags . error ) ;
self . isReady ( data . flags . ready ) ;
self . isLoading ( data . flags . loading ) ;
2012-12-29 18:34:55 +00:00
var connectionTab = $ ( "#connection" ) ;
if ( self . previousIsOperational != self . isOperational ( ) ) {
if ( self . isOperational ( ) && connectionTab . hasClass ( "in" ) ) {
// connection just got established, close connection tab for now
connectionTab . collapse ( "hide" ) ;
} else if ( ! connectionTab . hasClass ( "in" ) ) {
// connection just dropped, make sure connection tab is open
connectionTab . collapse ( "show" ) ;
}
}
2012-12-28 19:37:40 +00:00
}
self . connect = function ( ) {
if ( self . isErrorOrClosed ( ) ) {
2013-01-01 20:04:00 +00:00
var data = {
2013-04-12 21:08:14 +00:00
"command" : "connect" ,
2013-01-01 20:04:00 +00:00
"port" : self . selectedPort ( ) ,
"baudrate" : self . selectedBaudrate ( )
} ;
if ( self . saveSettings ( ) )
data [ "save" ] = true ;
2012-12-28 19:37:40 +00:00
$ . ajax ( {
2013-04-12 21:08:14 +00:00
url : AJAX _BASEURL + "control/connection" ,
2012-12-28 19:37:40 +00:00
type : "POST" ,
dataType : "json" ,
2013-01-01 20:04:00 +00:00
data : data
2012-12-28 19:37:40 +00:00
} )
} else {
2013-01-01 20:04:00 +00:00
self . requestData ( ) ;
2012-12-28 19:37:40 +00:00
$ . ajax ( {
2013-04-12 21:08:14 +00:00
url : AJAX _BASEURL + "control/connection" ,
2012-12-28 19:37:40 +00:00
type : "POST" ,
2013-04-12 21:08:14 +00:00
dataType : "json" ,
data : { "command" : "disconnect" }
2012-12-28 19:37:40 +00:00
} )
}
}
}
2013-03-19 22:06:48 +00:00
function PrinterStateViewModel ( loginStateViewModel ) {
2012-12-25 19:49:10 +00:00
var self = this ;
2013-03-19 22:06:48 +00:00
self . loginState = loginStateViewModel ;
2012-12-25 19:49:10 +00:00
self . stateString = ko . observable ( undefined ) ;
self . isErrorOrClosed = ko . observable ( undefined ) ;
self . isOperational = ko . observable ( undefined ) ;
2012-12-26 14:03:34 +00:00
self . isPrinting = ko . observable ( undefined ) ;
self . isPaused = ko . observable ( undefined ) ;
self . isError = ko . observable ( undefined ) ;
self . isReady = ko . observable ( undefined ) ;
2012-12-28 19:37:40 +00:00
self . isLoading = ko . observable ( undefined ) ;
2013-05-26 16:53:43 +00:00
self . isSdReady = ko . observable ( undefined ) ;
2012-12-25 19:49:10 +00:00
2012-12-28 19:37:40 +00:00
self . filename = ko . observable ( undefined ) ;
2012-12-25 19:49:10 +00:00
self . filament = ko . observable ( undefined ) ;
self . estimatedPrintTime = ko . observable ( undefined ) ;
self . printTime = ko . observable ( undefined ) ;
self . printTimeLeft = ko . observable ( undefined ) ;
2013-05-20 17:18:03 +00:00
self . progress = ko . observable ( undefined ) ;
2012-12-25 19:49:10 +00:00
self . currentLine = ko . observable ( undefined ) ;
self . totalLines = ko . observable ( undefined ) ;
self . currentHeight = ko . observable ( undefined ) ;
self . lineString = ko . computed ( function ( ) {
if ( ! self . totalLines ( ) )
return "-" ;
var currentLine = self . currentLine ( ) ? self . currentLine ( ) : "-" ;
return currentLine + " / " + self . totalLines ( ) ;
2012-12-26 14:03:34 +00:00
} ) ;
2013-06-09 16:13:12 +00:00
self . heightString = ko . computed ( function ( ) {
if ( ! self . currentHeight ( ) )
return "-" ;
return self . currentHeight ( ) ;
} )
2013-05-20 17:18:03 +00:00
self . progressString = ko . computed ( function ( ) {
if ( ! self . progress ( ) )
2012-12-25 19:49:10 +00:00
return 0 ;
2013-05-20 17:18:03 +00:00
return self . progress ( ) ;
2012-12-25 19:49:10 +00:00
} ) ;
2012-12-26 14:03:34 +00:00
self . pauseString = ko . computed ( function ( ) {
if ( self . isPaused ( ) )
return "Continue" ;
else
return "Pause" ;
} ) ;
2012-12-25 19:49:10 +00:00
2013-01-10 22:40:00 +00:00
self . fromCurrentData = function ( data ) {
2013-01-11 23:00:58 +00:00
self . _fromData ( data ) ;
2013-01-10 22:40:00 +00:00
}
self . fromHistoryData = function ( data ) {
2013-01-11 23:00:58 +00:00
self . _fromData ( data ) ;
}
self . _fromData = function ( data ) {
2013-01-10 22:40:00 +00:00
self . _processStateData ( data . state )
2013-01-11 23:00:58 +00:00
self . _processJobData ( data . job ) ;
self . _processGcodeData ( data . gcode ) ;
2013-05-20 17:18:03 +00:00
self . _processSdUploadData ( data . sdUpload ) ;
2013-01-11 23:00:58 +00:00
self . _processProgressData ( data . progress ) ;
self . _processZData ( data . currentZ ) ;
2013-01-10 22:40:00 +00:00
}
self . _processStateData = function ( data ) {
self . stateString ( data . stateString ) ;
2013-01-06 15:51:04 +00:00
self . isErrorOrClosed ( data . flags . closedOrError ) ;
self . isOperational ( data . flags . operational ) ;
self . isPaused ( data . flags . paused ) ;
self . isPrinting ( data . flags . printing ) ;
self . isError ( data . flags . error ) ;
self . isReady ( data . flags . ready ) ;
self . isLoading ( data . flags . loading ) ;
2013-05-26 16:53:43 +00:00
self . isSdReady ( data . flags . sdReady ) ;
2013-01-06 15:51:04 +00:00
}
2013-01-10 22:40:00 +00:00
self . _processJobData = function ( data ) {
2013-01-06 15:51:04 +00:00
self . filename ( data . filename ) ;
2013-01-11 23:00:58 +00:00
self . totalLines ( data . lines ) ;
2013-01-06 15:51:04 +00:00
self . estimatedPrintTime ( data . estimatedPrintTime ) ;
self . filament ( data . filament ) ;
}
2013-01-10 22:40:00 +00:00
self . _processGcodeData = function ( data ) {
2013-01-10 20:02:47 +00:00
if ( self . isLoading ( ) ) {
2013-01-12 23:58:54 +00:00
var progress = Math . round ( data . progress * 100 ) ;
if ( data . mode == "loading" ) {
self . filename ( "Loading... (" + progress + "%)" ) ;
} else if ( data . mode == "parsing" ) {
self . filename ( "Parsing... (" + progress + "%)" ) ;
}
2013-01-10 20:02:47 +00:00
}
}
2013-05-20 17:18:03 +00:00
self . _processSdUploadData = function ( data ) {
if ( self . isLoading ( ) ) {
var progress = Math . round ( data . progress * 100 ) ;
2013-05-21 21:30:29 +00:00
self . filename ( "Streaming... (" + progress + "%)" ) ;
2013-05-20 17:18:03 +00:00
}
}
2013-01-10 22:40:00 +00:00
self . _processProgressData = function ( data ) {
2013-05-20 17:18:03 +00:00
if ( data . progress ) {
self . progress ( Math . round ( data . progress * 100 ) ) ;
} else {
self . progress ( undefined ) ;
}
self . currentLine ( data . currentLine ) ;
2013-01-06 15:51:04 +00:00
self . printTime ( data . printTime ) ;
self . printTimeLeft ( data . printTimeLeft ) ;
}
2013-01-10 22:40:00 +00:00
self . _processZData = function ( data ) {
2013-01-11 23:00:58 +00:00
self . currentHeight ( data ) ;
2013-01-06 15:51:04 +00:00
}
2013-04-10 14:37:12 +00:00
self . print = function ( ) {
var printAction = function ( ) {
2013-04-13 20:26:23 +00:00
self . _jobCommand ( "start" ) ;
2013-04-10 14:37:12 +00:00
}
if ( self . isPaused ( ) ) {
$ ( "#confirmation_dialog .confirmation_dialog_message" ) . text ( "This will restart the print job from the beginning." ) ;
$ ( "#confirmation_dialog .confirmation_dialog_acknowledge" ) . click ( function ( e ) { e . preventDefault ( ) ; $ ( "#confirmation_dialog" ) . modal ( "hide" ) ; printAction ( ) ; } ) ;
$ ( "#confirmation_dialog" ) . modal ( "show" ) ;
} else {
printAction ( ) ;
}
}
self . pause = function ( ) {
2013-04-13 20:26:23 +00:00
self . _jobCommand ( "pause" ) ;
2013-04-10 14:37:12 +00:00
}
self . cancel = function ( ) {
2013-04-13 20:26:23 +00:00
self . _jobCommand ( "cancel" ) ;
}
self . _jobCommand = function ( command ) {
2013-04-10 14:37:12 +00:00
$ . ajax ( {
2013-04-13 20:26:23 +00:00
url : AJAX _BASEURL + "control/job" ,
2013-04-10 14:37:12 +00:00
type : "POST" ,
2013-04-13 20:26:23 +00:00
dataType : "json" ,
data : { command : command }
2013-04-10 14:37:12 +00:00
} ) ;
}
2012-12-25 19:49:10 +00:00
}
2013-03-19 22:06:48 +00:00
function TemperatureViewModel ( loginStateViewModel , settingsViewModel ) {
2012-12-25 19:49:10 +00:00
var self = this ;
2013-03-19 22:06:48 +00:00
self . loginState = loginStateViewModel ;
2012-12-25 19:49:10 +00:00
self . temp = ko . observable ( undefined ) ;
self . bedTemp = ko . observable ( undefined ) ;
2012-12-26 14:03:34 +00:00
self . targetTemp = ko . observable ( undefined ) ;
self . bedTargetTemp = ko . observable ( undefined ) ;
2012-12-28 19:37:40 +00:00
2012-12-26 14:03:34 +00:00
self . isErrorOrClosed = ko . observable ( undefined ) ;
self . isOperational = ko . observable ( undefined ) ;
self . isPrinting = ko . observable ( undefined ) ;
self . isPaused = ko . observable ( undefined ) ;
self . isError = ko . observable ( undefined ) ;
self . isReady = ko . observable ( undefined ) ;
2012-12-28 19:37:40 +00:00
self . isLoading = ko . observable ( undefined ) ;
2012-12-26 14:03:34 +00:00
2013-02-23 17:47:01 +00:00
self . temperature _profiles = settingsViewModel . temperature _profiles ;
2013-02-23 21:46:29 +00:00
self . setTempFromProfile = function ( profile ) {
if ( ! profile )
return ;
self . setTemp ( profile . extruder ) ;
}
self . setTemp = function ( temp ) {
$ . ajax ( {
url : AJAX _BASEURL + "control/temperature" ,
type : "POST" ,
dataType : "json" ,
data : { temp : temp } ,
success : function ( ) { $ ( "#temp_newTemp" ) . val ( "" ) }
} )
} ;
self . setBedTempFromProfile = function ( profile ) {
if ( ! profile )
return ;
self . setBedTemp ( profile . bed ) ;
}
self . setBedTemp = function ( bedTemp ) {
$ . ajax ( {
url : AJAX _BASEURL + "control/temperature" ,
type : "POST" ,
dataType : "json" ,
data : { bedTemp : bedTemp } ,
success : function ( ) { $ ( "#temp_newBedTemp" ) . val ( "" ) }
} )
} ;
2013-02-23 18:38:18 +00:00
2012-12-26 14:03:34 +00:00
self . tempString = ko . computed ( function ( ) {
if ( ! self . temp ( ) )
return "-" ;
2013-02-23 17:47:01 +00:00
return self . temp ( ) + " °C" ;
2012-12-26 14:03:34 +00:00
} ) ;
self . bedTempString = ko . computed ( function ( ) {
if ( ! self . bedTemp ( ) )
return "-" ;
2013-02-23 17:47:01 +00:00
return self . bedTemp ( ) + " °C" ;
2012-12-26 14:03:34 +00:00
} ) ;
self . targetTempString = ko . computed ( function ( ) {
if ( ! self . targetTemp ( ) )
return "-" ;
2013-02-23 17:47:01 +00:00
return self . targetTemp ( ) + " °C" ;
2012-12-26 14:03:34 +00:00
} ) ;
self . bedTargetTempString = ko . computed ( function ( ) {
if ( ! self . bedTargetTemp ( ) )
return "-" ;
2013-02-23 17:47:01 +00:00
return self . bedTargetTemp ( ) + " °C" ;
2012-12-26 14:03:34 +00:00
} ) ;
2012-12-25 19:49:10 +00:00
self . temperatures = [ ] ;
self . plotOptions = {
yaxis : {
min : 0 ,
max : 310 ,
ticks : 10
} ,
xaxis : {
2012-12-26 14:03:34 +00:00
mode : "time" ,
minTickSize : [ 2 , "minute" ] ,
tickFormatter : function ( val , axis ) {
2013-01-27 10:12:28 +00:00
if ( val == undefined || val == 0 )
return "" ; // we don't want to display the minutes since the epoch if not connected yet ;)
2013-01-22 16:44:20 +00:00
2013-03-03 15:57:35 +00:00
// current time in milliseconds in UTC
var timestampUtc = Date . now ( ) ;
2013-01-22 16:44:20 +00:00
2013-01-27 10:12:28 +00:00
// calculate difference in milliseconds
2013-01-22 16:44:20 +00:00
var diff = timestampUtc - val ;
2013-01-27 10:12:28 +00:00
// convert to minutes
2013-01-22 16:44:20 +00:00
var diffInMins = Math . round ( diff / ( 60 * 1000 ) ) ;
2012-12-26 14:03:34 +00:00
if ( diffInMins == 0 )
return "just now" ;
else
return "- " + diffInMins + " min" ;
}
2012-12-25 19:49:10 +00:00
} ,
legend : {
noColumns : 4
}
}
2013-01-10 22:40:00 +00:00
self . fromCurrentData = function ( data ) {
self . _processStateData ( data . state ) ;
self . _processTemperatureUpdateData ( data . temperatures ) ;
}
self . fromHistoryData = function ( data ) {
self . _processStateData ( data . state ) ;
self . _processTemperatureHistoryData ( data . temperatureHistory ) ;
}
self . _processStateData = function ( data ) {
2013-01-06 15:51:04 +00:00
self . isErrorOrClosed ( data . flags . closedOrError ) ;
self . isOperational ( data . flags . operational ) ;
self . isPaused ( data . flags . paused ) ;
self . isPrinting ( data . flags . printing ) ;
self . isError ( data . flags . error ) ;
self . isReady ( data . flags . ready ) ;
self . isLoading ( data . flags . loading ) ;
}
2013-01-10 22:40:00 +00:00
self . _processTemperatureUpdateData = function ( data ) {
2013-01-10 20:02:47 +00:00
if ( data . length == 0 )
return ;
self . temp ( data [ data . length - 1 ] . temp ) ;
self . bedTemp ( data [ data . length - 1 ] . bedTemp ) ;
self . targetTemp ( data [ data . length - 1 ] . targetTemp ) ;
2013-01-12 12:15:39 +00:00
self . bedTargetTemp ( data [ data . length - 1 ] . targetBedTemp ) ;
2013-01-06 20:19:39 +00:00
if ( ! self . temperatures )
self . temperatures = [ ] ;
if ( ! self . temperatures . actual )
self . temperatures . actual = [ ] ;
if ( ! self . temperatures . target )
self . temperatures . target = [ ] ;
if ( ! self . temperatures . actualBed )
self . temperatures . actualBed = [ ] ;
if ( ! self . temperatures . targetBed )
self . temperatures . targetBed = [ ] ;
2013-01-10 20:02:47 +00:00
for ( var i = 0 ; i < data . length ; i ++ ) {
self . temperatures . actual . push ( [ data [ i ] . currentTime , data [ i ] . temp ] )
self . temperatures . target . push ( [ data [ i ] . currentTime , data [ i ] . targetTemp ] )
self . temperatures . actualBed . push ( [ data [ i ] . currentTime , data [ i ] . bedTemp ] )
2013-01-12 12:15:39 +00:00
self . temperatures . targetBed . push ( [ data [ i ] . currentTime , data [ i ] . targetBedTemp ] )
2013-01-10 20:02:47 +00:00
}
2013-01-06 20:19:39 +00:00
self . temperatures . actual = self . temperatures . actual . slice ( - 300 ) ;
self . temperatures . target = self . temperatures . target . slice ( - 300 ) ;
self . temperatures . actualBed = self . temperatures . actualBed . slice ( - 300 ) ;
self . temperatures . targetBed = self . temperatures . targetBed . slice ( - 300 ) ;
2012-12-26 14:03:34 +00:00
2013-01-11 23:00:58 +00:00
self . updatePlot ( ) ;
2012-12-25 19:49:10 +00:00
}
2013-01-10 22:40:00 +00:00
self . _processTemperatureHistoryData = function ( data ) {
2013-01-06 20:19:39 +00:00
self . temperatures = data ;
2013-01-11 23:00:58 +00:00
self . updatePlot ( ) ;
2013-01-06 20:19:39 +00:00
}
2013-01-11 23:00:58 +00:00
self . updatePlot = function ( ) {
2012-12-25 19:49:10 +00:00
var data = [
{ label : "Actual" , color : "#FF4040" , data : self . temperatures . actual } ,
{ label : "Target" , color : "#FFA0A0" , data : self . temperatures . target } ,
{ label : "Bed Actual" , color : "#4040FF" , data : self . temperatures . actualBed } ,
{ label : "Bed Target" , color : "#A0A0FF" , data : self . temperatures . targetBed }
]
$ . plot ( $ ( "#temperature-graph" ) , data , self . plotOptions ) ;
}
}
2013-03-19 22:06:48 +00:00
function ControlViewModel ( loginStateViewModel ) {
2013-01-27 10:12:28 +00:00
var self = this ;
2013-03-19 22:06:48 +00:00
self . loginState = loginStateViewModel ;
2013-01-27 10:12:28 +00:00
self . isErrorOrClosed = ko . observable ( undefined ) ;
self . isOperational = ko . observable ( undefined ) ;
self . isPrinting = ko . observable ( undefined ) ;
self . isPaused = ko . observable ( undefined ) ;
self . isError = ko . observable ( undefined ) ;
self . isReady = ko . observable ( undefined ) ;
self . isLoading = ko . observable ( undefined ) ;
2013-02-09 23:40:06 +00:00
self . extrusionAmount = ko . observable ( undefined ) ;
2013-01-27 10:12:28 +00:00
self . controls = ko . observableArray ( [ ] ) ;
self . fromCurrentData = function ( data ) {
self . _processStateData ( data . state ) ;
}
self . fromHistoryData = function ( data ) {
self . _processStateData ( data . state ) ;
}
self . _processStateData = function ( data ) {
self . isErrorOrClosed ( data . flags . closedOrError ) ;
self . isOperational ( data . flags . operational ) ;
self . isPaused ( data . flags . paused ) ;
self . isPrinting ( data . flags . printing ) ;
self . isError ( data . flags . error ) ;
self . isReady ( data . flags . ready ) ;
self . isLoading ( data . flags . loading ) ;
}
self . requestData = function ( ) {
$ . ajax ( {
url : AJAX _BASEURL + "control/custom" ,
method : "GET" ,
dataType : "json" ,
success : function ( response ) {
self . _fromResponse ( response ) ;
}
} ) ;
}
self . _fromResponse = function ( response ) {
2013-01-27 17:28:11 +00:00
self . controls ( self . _enhanceControls ( response . controls ) ) ;
}
self . _enhanceControls = function ( controls ) {
for ( var i = 0 ; i < controls . length ; i ++ ) {
controls [ i ] = self . _enhanceControl ( controls [ i ] ) ;
}
return controls ;
}
self . _enhanceControl = function ( control ) {
2013-02-23 17:08:59 +00:00
if ( control . type == "parametric_command" || control . type == "parametric_commands" ) {
2013-01-27 17:28:11 +00:00
for ( var i = 0 ; i < control . input . length ; i ++ ) {
control . input [ i ] . value = control . input [ i ] . default ;
}
} else if ( control . type == "section" ) {
control . children = self . _enhanceControls ( control . children ) ;
}
return control ;
}
2013-02-10 16:00:47 +00:00
self . sendJogCommand = function ( axis , multiplier , distance ) {
if ( typeof distance === "undefined" )
distance = $ ( '#jog_distance button.active' ) . data ( 'distance' ) ;
2013-01-27 17:28:11 +00:00
$ . ajax ( {
url : AJAX _BASEURL + "control/jog" ,
type : "POST" ,
dataType : "json" ,
2013-02-10 16:00:47 +00:00
data : axis + "=" + ( distance * multiplier )
2013-01-27 17:28:11 +00:00
} )
}
self . sendHomeCommand = function ( axis ) {
$ . ajax ( {
url : AJAX _BASEURL + "control/jog" ,
type : "POST" ,
dataType : "json" ,
data : "home" + axis
} )
2013-01-27 10:12:28 +00:00
}
2013-02-09 23:40:06 +00:00
self . sendExtrudeCommand = function ( ) {
self . _sendECommand ( 1 ) ;
}
self . sendRetractCommand = function ( ) {
self . _sendECommand ( - 1 ) ;
}
self . _sendECommand = function ( dir ) {
var length = self . extrusionAmount ( ) ;
if ( ! length )
length = 5 ;
$ . ajax ( {
url : AJAX _BASEURL + "control/jog" ,
type : "POST" ,
dataType : "json" ,
data : "extrude=" + ( dir * length )
} )
}
2013-01-27 10:12:28 +00:00
self . sendCustomCommand = function ( command ) {
2013-01-27 17:28:11 +00:00
if ( ! command )
return ;
2013-02-23 17:08:59 +00:00
var data = undefined ;
if ( command . type == "command" || command . type == "parametric_command" ) {
// single command
data = { "command" : command . command } ;
} else if ( command . type == "commands" || command . type == "parametric_commands" ) {
// multi command
data = { "commands" : command . commands } ;
}
if ( command . type == "parametric_command" || command . type == "parametric_commands" ) {
// parametric command(s)
data [ "parameters" ] = { } ;
2013-01-27 17:28:11 +00:00
for ( var i = 0 ; i < command . input . length ; i ++ ) {
2013-02-23 17:08:59 +00:00
data [ "parameters" ] [ command . input [ i ] . parameter ] = command . input [ i ] . value ;
2013-01-27 17:28:11 +00:00
}
2013-01-27 10:12:28 +00:00
}
2013-02-23 17:08:59 +00:00
if ( ! data )
return ;
$ . ajax ( {
url : AJAX _BASEURL + "control/command" ,
type : "POST" ,
dataType : "json" ,
contentType : "application/json; charset=UTF-8" ,
data : JSON . stringify ( data )
} )
2013-01-27 10:12:28 +00:00
}
self . displayMode = function ( customControl ) {
switch ( customControl . type ) {
case "section" :
return "customControls_sectionTemplate" ;
case "command" :
2013-02-23 17:08:59 +00:00
case "commands" :
2013-01-27 10:12:28 +00:00
return "customControls_commandTemplate" ;
2013-01-27 17:52:25 +00:00
case "parametric_command" :
2013-02-23 17:08:59 +00:00
case "parametric_commands" :
2013-01-27 17:52:25 +00:00
return "customControls_parametricCommandTemplate" ;
2013-01-27 10:12:28 +00:00
default :
return "customControls_emptyTemplate" ;
}
}
}
2013-03-19 22:06:48 +00:00
function TerminalViewModel ( loginStateViewModel ) {
2012-12-25 19:49:10 +00:00
var self = this ;
2013-03-19 22:06:48 +00:00
self . loginState = loginStateViewModel ;
2013-01-06 20:19:39 +00:00
self . log = [ ] ;
2012-12-25 19:49:10 +00:00
2013-01-06 15:51:04 +00:00
self . isErrorOrClosed = ko . observable ( undefined ) ;
self . isOperational = ko . observable ( undefined ) ;
self . isPrinting = ko . observable ( undefined ) ;
self . isPaused = ko . observable ( undefined ) ;
self . isError = ko . observable ( undefined ) ;
self . isReady = ko . observable ( undefined ) ;
self . isLoading = ko . observable ( undefined ) ;
2013-01-20 13:34:44 +00:00
self . autoscrollEnabled = ko . observable ( true ) ;
2013-01-11 23:00:58 +00:00
self . fromCurrentData = function ( data ) {
self . _processStateData ( data . state ) ;
self . _processCurrentLogData ( data . logs ) ;
}
self . fromHistoryData = function ( data ) {
self . _processStateData ( data . state ) ;
self . _processHistoryLogData ( data . logHistory ) ;
2013-01-06 15:51:04 +00:00
}
2012-12-25 19:49:10 +00:00
2013-01-11 23:00:58 +00:00
self . _processCurrentLogData = function ( data ) {
2013-01-06 20:19:39 +00:00
if ( ! self . log )
self . log = [ ]
2013-01-11 23:00:58 +00:00
self . log = self . log . concat ( data )
2013-03-19 22:06:48 +00:00
self . log = self . log . slice ( - 300 )
2013-01-06 20:19:39 +00:00
self . updateOutput ( ) ;
}
2013-01-11 23:00:58 +00:00
self . _processHistoryLogData = function ( data ) {
2013-01-06 20:19:39 +00:00
self . log = data ;
2012-12-25 19:49:10 +00:00
self . updateOutput ( ) ;
}
2013-01-11 23:00:58 +00:00
self . _processStateData = function ( data ) {
self . isErrorOrClosed ( data . flags . closedOrError ) ;
self . isOperational ( data . flags . operational ) ;
self . isPaused ( data . flags . paused ) ;
self . isPrinting ( data . flags . printing ) ;
self . isError ( data . flags . error ) ;
self . isReady ( data . flags . ready ) ;
self . isLoading ( data . flags . loading ) ;
}
2012-12-25 19:49:10 +00:00
self . updateOutput = function ( ) {
2013-01-06 20:19:39 +00:00
if ( ! self . log )
return ;
2012-12-28 19:37:40 +00:00
var output = "" ;
2012-12-25 19:49:10 +00:00
for ( var i = 0 ; i < self . log . length ; i ++ ) {
2012-12-28 19:37:40 +00:00
output += self . log [ i ] + "\n" ;
2012-12-25 19:49:10 +00:00
}
var container = $ ( "#terminal-output" ) ;
2012-12-26 14:03:34 +00:00
container . text ( output ) ;
2012-12-25 19:49:10 +00:00
2013-01-20 13:34:44 +00:00
if ( self . autoscrollEnabled ( ) ) {
2012-12-25 19:49:10 +00:00
container . scrollTop ( container [ 0 ] . scrollHeight - container . height ( ) )
}
}
}
2013-03-19 22:06:48 +00:00
function GcodeFilesViewModel ( loginStateViewModel ) {
2012-12-25 19:49:10 +00:00
var self = this ;
2013-03-19 22:06:48 +00:00
self . loginState = loginStateViewModel ;
2013-03-30 17:21:49 +00:00
self . isErrorOrClosed = ko . observable ( undefined ) ;
self . isOperational = ko . observable ( undefined ) ;
self . isPrinting = ko . observable ( undefined ) ;
self . isPaused = ko . observable ( undefined ) ;
self . isError = ko . observable ( undefined ) ;
self . isReady = ko . observable ( undefined ) ;
self . isLoading = ko . observable ( undefined ) ;
2013-05-26 16:53:43 +00:00
self . isSdReady = ko . observable ( undefined ) ;
2013-03-30 17:21:49 +00:00
2013-03-06 22:27:16 +00:00
// initialize list helper
self . listHelper = new ItemListHelper (
"gcodeFiles" ,
{
"name" : function ( a , b ) {
// sorts ascending
if ( a [ "name" ] . toLocaleLowerCase ( ) < b [ "name" ] . toLocaleLowerCase ( ) ) return - 1 ;
if ( a [ "name" ] . toLocaleLowerCase ( ) > b [ "name" ] . toLocaleLowerCase ( ) ) return 1 ;
return 0 ;
} ,
"upload" : function ( a , b ) {
2013-05-20 17:18:03 +00:00
// sorts descending
if ( b [ "date" ] === undefined || a [ "date" ] > b [ "date" ] ) return - 1 ;
if ( a [ "date" ] < b [ "date" ] ) return 1 ;
return 0 ;
2013-03-06 22:27:16 +00:00
} ,
"size" : function ( a , b ) {
// sorts descending
2013-05-20 17:18:03 +00:00
if ( b [ "bytes" ] === undefined || a [ "bytes" ] > b [ "bytes" ] ) return - 1 ;
2013-03-06 22:27:16 +00:00
if ( a [ "bytes" ] < b [ "bytes" ] ) return 1 ;
return 0 ;
2013-01-20 12:43:29 +00:00
}
2013-03-06 22:27:16 +00:00
} ,
{
"printed" : function ( file ) {
return ! ( file [ "prints" ] && file [ "prints" ] [ "success" ] && file [ "prints" ] [ "success" ] > 0 ) ;
2013-05-20 17:18:03 +00:00
} ,
"sd" : function ( file ) {
return file [ "origin" ] && file [ "origin" ] == "sd" ;
} ,
"local" : function ( file ) {
return ! ( file [ "origin" ] && file [ "origin" ] == "sd" ) ;
2013-01-20 12:43:29 +00:00
}
2013-03-06 22:27:16 +00:00
} ,
"name" ,
[ ] ,
2013-05-20 17:18:03 +00:00
[ [ "sd" , "local" ] ] ,
2013-03-06 22:27:16 +00:00
CONFIG _GCODEFILESPERPAGE
2013-03-30 17:21:49 +00:00
) ;
self . isLoadActionPossible = ko . computed ( function ( ) {
2013-04-13 19:40:28 +00:00
return self . loginState . isUser ( ) && ! self . isPrinting ( ) && ! self . isPaused ( ) && ! self . isLoading ( ) ;
2013-03-30 17:21:49 +00:00
} ) ;
self . isLoadAndPrintActionPossible = ko . computed ( function ( ) {
2013-04-13 19:40:28 +00:00
return self . loginState . isUser ( ) && self . isOperational ( ) && self . isLoadActionPossible ( ) ;
2013-03-30 17:21:49 +00:00
} ) ;
self . fromCurrentData = function ( data ) {
self . _processStateData ( data . state ) ;
}
self . fromHistoryData = function ( data ) {
self . _processStateData ( data . state ) ;
}
self . _processStateData = function ( data ) {
self . isErrorOrClosed ( data . flags . closedOrError ) ;
self . isOperational ( data . flags . operational ) ;
self . isPaused ( data . flags . paused ) ;
self . isPrinting ( data . flags . printing ) ;
self . isError ( data . flags . error ) ;
self . isReady ( data . flags . ready ) ;
self . isLoading ( data . flags . loading ) ;
2013-05-26 16:53:43 +00:00
self . isSdReady ( data . flags . sdReady ) ;
2013-03-30 17:21:49 +00:00
}
2012-12-25 19:49:10 +00:00
2013-01-01 20:04:00 +00:00
self . requestData = function ( ) {
$ . ajax ( {
url : AJAX _BASEURL + "gcodefiles" ,
method : "GET" ,
dataType : "json" ,
success : function ( response ) {
self . fromResponse ( response ) ;
}
} ) ;
}
2012-12-25 19:49:10 +00:00
self . fromResponse = function ( response ) {
2013-03-06 22:27:16 +00:00
self . listHelper . updateItems ( response . files ) ;
2013-02-04 21:24:32 +00:00
if ( response . filename ) {
// got a file to scroll to
2013-03-06 22:27:16 +00:00
self . listHelper . switchToItem ( function ( item ) { return item . name == response . filename } ) ;
2013-02-04 21:24:32 +00:00
}
2012-12-25 19:49:10 +00:00
}
2013-03-30 17:21:49 +00:00
self . loadFile = function ( filename , printAfterLoad ) {
2013-05-20 17:18:03 +00:00
var file = self . listHelper . getItem ( function ( item ) { return item . name == filename } ) ;
if ( ! file ) return ;
2012-12-25 19:49:10 +00:00
$ . ajax ( {
url : AJAX _BASEURL + "gcodefiles/load" ,
type : "POST" ,
dataType : "json" ,
2013-05-20 17:18:03 +00:00
data : { filename : filename , print : printAfterLoad , target : file . origin }
2013-03-26 05:09:36 +00:00
} )
}
2013-02-04 20:41:02 +00:00
self . removeFile = function ( filename ) {
2013-05-20 17:18:03 +00:00
var file = self . listHelper . getItem ( function ( item ) { return item . name == filename } ) ;
if ( ! file ) return ;
2012-12-25 19:49:10 +00:00
$ . ajax ( {
url : AJAX _BASEURL + "gcodefiles/delete" ,
type : "POST" ,
dataType : "json" ,
2013-05-20 17:18:03 +00:00
data : { filename : filename , target : file . origin } ,
2012-12-25 19:49:10 +00:00
success : self . fromResponse
} )
}
2013-01-20 12:43:29 +00:00
2013-05-26 16:53:43 +00:00
self . initSdCard = function ( ) {
self . _sendSdCommand ( "init" ) ;
}
self . releaseSdCard = function ( ) {
self . _sendSdCommand ( "release" ) ;
}
self . refreshSdFiles = function ( ) {
self . _sendSdCommand ( "refresh" ) ;
}
self . _sendSdCommand = function ( command ) {
$ . ajax ( {
url : AJAX _BASEURL + "control/sd" ,
type : "POST" ,
dataType : "json" ,
data : { command : command }
} ) ;
}
2013-01-30 19:56:17 +00:00
self . getPopoverContent = function ( data ) {
var output = "<p><strong>Uploaded:</strong> " + data [ "date" ] + "</p>" ;
if ( data [ "gcodeAnalysis" ] ) {
output += "<p>" ;
output += "<strong>Filament:</strong> " + data [ "gcodeAnalysis" ] [ "filament" ] + "<br>" ;
output += "<strong>Estimated Print Time:</strong> " + data [ "gcodeAnalysis" ] [ "estimatedPrintTime" ] ;
output += "</p>" ;
}
if ( data [ "prints" ] && data [ "prints" ] [ "last" ] ) {
output += "<p>" ;
output += "<strong>Last Print:</strong> <span class=\"" + ( data [ "prints" ] [ "last" ] [ "success" ] ? "text-success" : "text-error" ) + "\">" + data [ "prints" ] [ "last" ] [ "date" ] + "</span>" ;
output += "</p>" ;
}
return output ;
}
self . getSuccessClass = function ( data ) {
if ( ! data [ "prints" ] || ! data [ "prints" ] [ "last" ] ) {
return "" ;
}
return data [ "prints" ] [ "last" ] [ "success" ] ? "text-success" : "text-error" ;
}
2012-12-25 19:49:10 +00:00
}
2013-03-19 22:06:48 +00:00
function TimelapseViewModel ( loginStateViewModel ) {
2013-01-03 14:25:20 +00:00
var self = this ;
2013-03-19 22:06:48 +00:00
self . loginState = loginStateViewModel ;
2013-01-03 14:25:20 +00:00
self . timelapseType = ko . observable ( undefined ) ;
self . timelapseTimedInterval = ko . observable ( undefined ) ;
self . isErrorOrClosed = ko . observable ( undefined ) ;
self . isOperational = ko . observable ( undefined ) ;
self . isPrinting = ko . observable ( undefined ) ;
self . isPaused = ko . observable ( undefined ) ;
self . isError = ko . observable ( undefined ) ;
self . isReady = ko . observable ( undefined ) ;
self . isLoading = ko . observable ( undefined ) ;
self . intervalInputEnabled = ko . computed ( function ( ) {
return ( "timed" == self . timelapseType ( ) ) ;
} )
self . isOperational . subscribe ( function ( newValue ) {
self . requestData ( ) ;
} )
2013-03-06 22:27:16 +00:00
// initialize list helper
self . listHelper = new ItemListHelper (
"timelapseFiles" ,
{
"name" : function ( a , b ) {
// sorts ascending
if ( a [ "name" ] . toLocaleLowerCase ( ) < b [ "name" ] . toLocaleLowerCase ( ) ) return - 1 ;
if ( a [ "name" ] . toLocaleLowerCase ( ) > b [ "name" ] . toLocaleLowerCase ( ) ) return 1 ;
return 0 ;
} ,
"creation" : function ( a , b ) {
// sorts descending
if ( a [ "date" ] > b [ "date" ] ) return - 1 ;
if ( a [ "date" ] < b [ "date" ] ) return 1 ;
return 0 ;
} ,
"size" : function ( a , b ) {
// sorts descending
if ( a [ "bytes" ] > b [ "bytes" ] ) return - 1 ;
if ( a [ "bytes" ] < b [ "bytes" ] ) return 1 ;
return 0 ;
}
} ,
{
} ,
"name" ,
[ ] ,
2013-05-20 17:18:03 +00:00
[ ] ,
2013-03-06 22:27:16 +00:00
CONFIG _TIMELAPSEFILESPERPAGE
)
2013-01-03 14:25:20 +00:00
self . requestData = function ( ) {
$ . ajax ( {
url : AJAX _BASEURL + "timelapse" ,
type : "GET" ,
dataType : "json" ,
success : self . fromResponse
2013-01-06 15:51:04 +00:00
} ) ;
2013-01-03 14:25:20 +00:00
}
self . fromResponse = function ( response ) {
2013-03-06 22:27:16 +00:00
self . timelapseType ( response . type ) ;
self . listHelper . updateItems ( response . files ) ;
2013-01-03 14:25:20 +00:00
if ( response . type == "timed" && response . config && response . config . interval ) {
self . timelapseTimedInterval ( response . config . interval )
} else {
self . timelapseTimedInterval ( undefined )
}
}
2013-01-11 23:00:58 +00:00
self . fromCurrentData = function ( data ) {
self . _processStateData ( data . state ) ;
}
self . fromHistoryData = function ( data ) {
self . _processStateData ( data . state ) ;
}
self . _processStateData = function ( data ) {
2013-01-06 15:51:04 +00:00
self . isErrorOrClosed ( data . flags . closedOrError ) ;
self . isOperational ( data . flags . operational ) ;
self . isPaused ( data . flags . paused ) ;
self . isPrinting ( data . flags . printing ) ;
self . isError ( data . flags . error ) ;
self . isReady ( data . flags . ready ) ;
self . isLoading ( data . flags . loading ) ;
2013-01-03 14:25:20 +00:00
}
2013-06-17 20:10:14 +00:00
self . removeFile = function ( filename ) {
2013-01-04 12:11:00 +00:00
$ . ajax ( {
url : AJAX _BASEURL + "timelapse/" + filename ,
type : "DELETE" ,
dataType : "json" ,
success : self . requestData
} )
}
2013-01-03 14:25:20 +00:00
self . save = function ( ) {
var data = {
"type" : self . timelapseType ( )
}
if ( self . timelapseType ( ) == "timed" ) {
data [ "interval" ] = self . timelapseTimedInterval ( ) ;
}
$ . ajax ( {
2013-05-01 18:17:30 +00:00
url : AJAX _BASEURL + "timelapse" ,
2013-01-03 14:25:20 +00:00
type : "POST" ,
dataType : "json" ,
data : data ,
success : self . fromResponse
} )
}
}
2013-03-19 22:06:48 +00:00
function GcodeViewModel ( loginStateViewModel ) {
2013-02-02 11:36:43 +00:00
var self = this ;
2013-03-19 22:06:48 +00:00
self . loginState = loginStateViewModel ;
2013-02-02 13:24:11 +00:00
self . loadedFilename = undefined ;
self . status = 'idle' ;
2013-02-02 16:45:36 +00:00
self . enabled = false ;
2013-05-20 17:18:03 +00:00
self . errorCount = 0 ;
2013-02-02 16:45:36 +00:00
self . initialize = function ( ) {
self . enabled = true ;
GCODE . ui . initHandlers ( ) ;
}
2013-02-02 13:24:11 +00:00
self . loadFile = function ( filename ) {
2013-05-20 17:18:03 +00:00
if ( self . status == 'idle' && self . errorCount < 3 ) {
2013-02-02 13:24:11 +00:00
self . status = 'request' ;
$ . ajax ( {
2013-02-03 21:01:11 +00:00
url : AJAX _BASEURL + "gcodefiles/" + filename ,
2013-02-02 13:24:11 +00:00
type : "GET" ,
success : function ( response , rstatus ) {
if ( rstatus === 'success' ) {
self . showGCodeViewer ( response , rstatus ) ;
self . loadedFilename = filename ;
self . status = 'idle' ;
}
} ,
error : function ( ) {
self . status = 'idle' ;
2013-05-20 17:18:03 +00:00
self . errorCount ++ ;
2013-02-02 13:24:11 +00:00
}
} )
}
}
2013-02-03 21:01:11 +00:00
self . showGCodeViewer = function ( response , rstatus ) {
2013-02-02 13:24:11 +00:00
var par = { } ;
par . target = { } ;
par . target . result = response ;
GCODE . gCodeReader . loadFile ( par ) ;
}
2013-02-02 11:36:43 +00:00
self . fromHistoryData = function ( data ) {
2013-02-02 13:24:11 +00:00
self . _processData ( data ) ;
2013-02-02 11:36:43 +00:00
}
self . fromCurrentData = function ( data ) {
2013-02-02 13:24:11 +00:00
self . _processData ( data ) ;
2013-02-02 11:36:43 +00:00
}
2013-02-02 13:24:11 +00:00
self . _processData = function ( data ) {
2013-06-09 12:00:15 +00:00
if ( ! self . enabled ) return ;
if ( ! data . job . filename ) return ;
if ( self . loadedFilename && self . loadedFilename == data . job . filename ) {
if ( data . state . flags && ( data . state . flags . printing || data . state . flags . paused ) ) {
var cmdIndex = GCODE . gCodeReader . getCmdIndexForPercentage ( data . progress . progress * 100 ) ;
if ( cmdIndex ) {
GCODE . renderer . render ( cmdIndex . layer , 0 , cmdIndex . cmd ) ;
GCODE . ui . updateLayerInfo ( cmdIndex . layer ) ;
}
2013-02-02 13:24:11 +00:00
}
2013-05-20 17:18:03 +00:00
self . errorCount = 0
2013-02-03 21:01:11 +00:00
} else if ( data . job . filename ) {
2013-02-02 13:24:11 +00:00
self . loadFile ( data . job . filename ) ;
2013-02-02 11:36:43 +00:00
}
}
}
2013-04-12 21:08:14 +00:00
function UsersViewModel ( loginStateViewModel ) {
2013-02-17 21:30:34 +00:00
var self = this ;
2013-03-19 22:06:48 +00:00
self . loginState = loginStateViewModel ;
2013-04-12 21:08:14 +00:00
// initialize list helper
self . listHelper = new ItemListHelper (
"users" ,
{
"name" : function ( a , b ) {
// sorts ascending
if ( a [ "name" ] . toLocaleLowerCase ( ) < b [ "name" ] . toLocaleLowerCase ( ) ) return - 1 ;
if ( a [ "name" ] . toLocaleLowerCase ( ) > b [ "name" ] . toLocaleLowerCase ( ) ) return 1 ;
return 0 ;
}
} ,
{ } ,
"name" ,
[ ] ,
CONFIG _USERSPERPAGE
2013-04-13 19:40:28 +00:00
) ;
2013-04-12 21:08:14 +00:00
self . emptyUser = { name : "" , admin : false , active : false } ;
self . currentUser = ko . observable ( self . emptyUser ) ;
self . editorUsername = ko . observable ( undefined ) ;
self . editorPassword = ko . observable ( undefined ) ;
self . editorRepeatedPassword = ko . observable ( undefined ) ;
self . editorAdmin = ko . observable ( undefined ) ;
self . editorActive = ko . observable ( undefined ) ;
self . currentUser . subscribe ( function ( newValue ) {
if ( newValue === undefined ) {
self . editorUsername ( undefined ) ;
self . editorAdmin ( undefined ) ;
self . editorActive ( undefined ) ;
} else {
self . editorUsername ( newValue . name ) ;
self . editorAdmin ( newValue . admin ) ;
self . editorActive ( newValue . active ) ;
}
self . editorPassword ( undefined ) ;
self . editorRepeatedPassword ( undefined ) ;
} ) ;
self . editorPasswordMismatch = ko . computed ( function ( ) {
return self . editorPassword ( ) != self . editorRepeatedPassword ( ) ;
} ) ;
self . requestData = function ( ) {
2013-04-13 19:40:28 +00:00
if ( ! CONFIG _ACCESS _CONTROL ) return ;
2013-04-12 21:08:14 +00:00
$ . ajax ( {
url : AJAX _BASEURL + "users" ,
type : "GET" ,
dataType : "json" ,
success : self . fromResponse
} ) ;
}
self . fromResponse = function ( response ) {
self . listHelper . updateItems ( response . users ) ;
}
self . showAddUserDialog = function ( ) {
2013-04-13 19:40:28 +00:00
if ( ! CONFIG _ACCESS _CONTROL ) return ;
2013-04-12 21:08:14 +00:00
self . currentUser ( undefined ) ;
2013-04-13 19:40:28 +00:00
self . editorActive ( true ) ;
2013-04-12 21:08:14 +00:00
$ ( "#settings-usersDialogAddUser" ) . modal ( "show" ) ;
}
self . confirmAddUser = function ( ) {
2013-04-13 19:40:28 +00:00
if ( ! CONFIG _ACCESS _CONTROL ) return ;
2013-04-12 21:08:14 +00:00
var user = { name : self . editorUsername ( ) , password : self . editorPassword ( ) , admin : self . editorAdmin ( ) , active : self . editorActive ( ) } ;
self . addUser ( user , function ( ) {
// close dialog
self . currentUser ( undefined ) ;
$ ( "#settings-usersDialogAddUser" ) . modal ( "hide" ) ;
} ) ;
}
self . showEditUserDialog = function ( user ) {
2013-04-13 19:40:28 +00:00
if ( ! CONFIG _ACCESS _CONTROL ) return ;
2013-04-12 21:08:14 +00:00
self . currentUser ( user ) ;
$ ( "#settings-usersDialogEditUser" ) . modal ( "show" ) ;
}
self . confirmEditUser = function ( ) {
2013-04-13 19:40:28 +00:00
if ( ! CONFIG _ACCESS _CONTROL ) return ;
2013-04-12 21:08:14 +00:00
var user = self . currentUser ( ) ;
user . active = self . editorActive ( ) ;
user . admin = self . editorAdmin ( ) ;
// make AJAX call
self . updateUser ( user , function ( ) {
// close dialog
self . currentUser ( undefined ) ;
$ ( "#settings-usersDialogEditUser" ) . modal ( "hide" ) ;
} ) ;
}
self . showChangePasswordDialog = function ( user ) {
2013-04-13 19:40:28 +00:00
if ( ! CONFIG _ACCESS _CONTROL ) return ;
2013-04-12 21:08:14 +00:00
self . currentUser ( user ) ;
$ ( "#settings-usersDialogChangePassword" ) . modal ( "show" ) ;
}
self . confirmChangePassword = function ( ) {
2013-04-13 19:40:28 +00:00
if ( ! CONFIG _ACCESS _CONTROL ) return ;
2013-04-12 21:08:14 +00:00
self . updatePassword ( self . currentUser ( ) . name , self . editorPassword ( ) , function ( ) {
// close dialog
self . currentUser ( undefined ) ;
$ ( "#settings-usersDialogChangePassword" ) . modal ( "hide" ) ;
} ) ;
}
//~~ AJAX calls
self . addUser = function ( user , callback ) {
2013-04-13 19:40:28 +00:00
if ( ! CONFIG _ACCESS _CONTROL ) return ;
2013-04-12 21:08:14 +00:00
if ( user === undefined ) return ;
$ . ajax ( {
url : AJAX _BASEURL + "users" ,
type : "POST" ,
contentType : "application/json; charset=UTF-8" ,
data : JSON . stringify ( user ) ,
success : function ( response ) {
self . fromResponse ( response ) ;
callback ( ) ;
}
} ) ;
}
self . removeUser = function ( user , callback ) {
2013-04-13 19:40:28 +00:00
if ( ! CONFIG _ACCESS _CONTROL ) return ;
2013-04-12 21:08:14 +00:00
if ( user === undefined ) return ;
2013-04-13 19:40:28 +00:00
2013-04-12 21:08:14 +00:00
if ( user . name == loginStateViewModel . username ( ) ) {
2013-05-20 17:18:03 +00:00
// we do not allow to delete ourselves
2013-04-12 21:08:14 +00:00
$ . pnotify ( { title : "Not possible" , text : "You may not delete your own account." , type : "error" } ) ;
return ;
}
$ . ajax ( {
url : AJAX _BASEURL + "users/" + user . name ,
type : "DELETE" ,
success : function ( response ) {
self . fromResponse ( response ) ;
callback ( ) ;
}
} ) ;
}
self . updateUser = function ( user , callback ) {
2013-04-13 19:40:28 +00:00
if ( ! CONFIG _ACCESS _CONTROL ) return ;
2013-04-12 21:08:14 +00:00
if ( user === undefined ) return ;
$ . ajax ( {
url : AJAX _BASEURL + "users/" + user . name ,
type : "PUT" ,
contentType : "application/json; charset=UTF-8" ,
data : JSON . stringify ( user ) ,
success : function ( response ) {
self . fromResponse ( response ) ;
callback ( ) ;
}
} ) ;
}
self . updatePassword = function ( username , password , callback ) {
2013-04-13 19:40:28 +00:00
if ( ! CONFIG _ACCESS _CONTROL ) return ;
2013-04-12 21:08:14 +00:00
$ . ajax ( {
url : AJAX _BASEURL + "users/" + username + "/password" ,
type : "PUT" ,
contentType : "application/json; charset=UTF-8" ,
data : JSON . stringify ( { password : password } ) ,
success : callback
} ) ;
}
}
function SettingsViewModel ( loginStateViewModel , usersViewModel ) {
var self = this ;
self . loginState = loginStateViewModel ;
self . users = usersViewModel ;
2013-03-02 10:56:32 +00:00
self . appearance _name = ko . observable ( undefined ) ;
self . appearance _color = ko . observable ( undefined ) ;
/* I did attempt to allow arbitrary gradients but cross browser support via knockout or jquery was going to be horrible */
2013-06-09 00:05:09 +00:00
self . appearance _available _colors = ko . observable ( [ "default" , "red" , "orange" , "yellow" , "green" , "blue" , "violet" , "black" ] ) ;
2013-03-02 10:56:32 +00:00
2013-02-17 21:30:34 +00:00
self . printer _movementSpeedX = ko . observable ( undefined ) ;
self . printer _movementSpeedY = ko . observable ( undefined ) ;
self . printer _movementSpeedZ = ko . observable ( undefined ) ;
self . printer _movementSpeedE = ko . observable ( undefined ) ;
self . webcam _streamUrl = ko . observable ( undefined ) ;
self . webcam _snapshotUrl = ko . observable ( undefined ) ;
self . webcam _ffmpegPath = ko . observable ( undefined ) ;
self . webcam _bitrate = ko . observable ( undefined ) ;
2013-03-08 23:23:52 +00:00
self . webcam _watermark = ko . observable ( undefined ) ;
2013-06-18 22:42:43 +00:00
self . webcam _flipX = ko . observable ( undefined ) ;
self . webcam _flipY = ko . observable ( undefined ) ;
2013-02-17 21:30:34 +00:00
self . feature _gcodeViewer = ko . observable ( undefined ) ;
self . feature _waitForStart = ko . observable ( undefined ) ;
2013-03-16 00:57:05 +00:00
self . feature _alwaysSendChecksum = ko . observable ( undefined ) ;
2013-03-16 17:25:39 +00:00
self . feature _resetLineNumbersWithPrefixedN = ko . observable ( undefined ) ;
2013-05-20 17:18:03 +00:00
self . feature _sdSupport = ko . observable ( undefined ) ;
2013-02-17 21:30:34 +00:00
self . folder _uploads = ko . observable ( undefined ) ;
self . folder _timelapse = ko . observable ( undefined ) ;
self . folder _timelapseTmp = ko . observable ( undefined ) ;
self . folder _logs = ko . observable ( undefined ) ;
2013-02-23 17:59:27 +00:00
self . temperature _profiles = ko . observableArray ( undefined ) ;
2013-03-10 16:04:05 +00:00
self . system _actions = ko . observableArray ( [ ] ) ;
2013-02-23 17:59:27 +00:00
self . addTemperatureProfile = function ( ) {
self . temperature _profiles . push ( { name : "New" , extruder : 0 , bed : 0 } ) ;
} ;
self . removeTemperatureProfile = function ( profile ) {
self . temperature _profiles . remove ( profile ) ;
} ;
2013-02-23 01:09:30 +00:00
2013-02-17 21:30:34 +00:00
self . requestData = function ( ) {
$ . ajax ( {
url : AJAX _BASEURL + "settings" ,
type : "GET" ,
dataType : "json" ,
success : self . fromResponse
2013-04-12 21:08:14 +00:00
} ) ;
2013-02-17 21:30:34 +00:00
}
self . fromResponse = function ( response ) {
2013-03-02 10:56:32 +00:00
self . appearance _name ( response . appearance . name ) ;
self . appearance _color ( response . appearance . color ) ;
2013-02-17 21:30:34 +00:00
self . printer _movementSpeedX ( response . printer . movementSpeedX ) ;
self . printer _movementSpeedY ( response . printer . movementSpeedY ) ;
self . printer _movementSpeedZ ( response . printer . movementSpeedZ ) ;
self . printer _movementSpeedE ( response . printer . movementSpeedE ) ;
self . webcam _streamUrl ( response . webcam . streamUrl ) ;
self . webcam _snapshotUrl ( response . webcam . snapshotUrl ) ;
self . webcam _ffmpegPath ( response . webcam . ffmpegPath ) ;
self . webcam _bitrate ( response . webcam . bitrate ) ;
2013-03-08 23:23:52 +00:00
self . webcam _watermark ( response . webcam . watermark ) ;
2013-06-18 22:42:43 +00:00
self . webcam _flipX ( response . webcam . flipX ) ;
self . webcam _flipY ( response . webcam . flipY ) ;
2013-02-17 21:30:34 +00:00
self . feature _gcodeViewer ( response . feature . gcodeViewer ) ;
self . feature _waitForStart ( response . feature . waitForStart ) ;
2013-03-16 00:57:05 +00:00
self . feature _alwaysSendChecksum ( response . feature . alwaysSendChecksum ) ;
2013-03-16 17:25:39 +00:00
self . feature _resetLineNumbersWithPrefixedN ( response . feature . resetLineNumbersWithPrefixedN ) ;
2013-05-20 17:18:03 +00:00
self . feature _sdSupport ( response . feature . sdSupport ) ;
2013-02-17 21:30:34 +00:00
self . folder _uploads ( response . folder . uploads ) ;
self . folder _timelapse ( response . folder . timelapse ) ;
self . folder _timelapseTmp ( response . folder . timelapseTmp ) ;
self . folder _logs ( response . folder . logs ) ;
2013-02-23 01:09:30 +00:00
2013-02-23 17:47:01 +00:00
self . temperature _profiles ( response . temperature . profiles ) ;
2013-03-10 16:04:05 +00:00
self . system _actions ( response . system . actions ) ;
2013-02-17 21:30:34 +00:00
}
self . saveData = function ( ) {
var data = {
2013-03-02 10:56:32 +00:00
"appearance" : {
"name" : self . appearance _name ( ) ,
"color" : self . appearance _color ( )
} ,
2013-02-17 21:30:34 +00:00
"printer" : {
"movementSpeedX" : self . printer _movementSpeedX ( ) ,
"movementSpeedY" : self . printer _movementSpeedY ( ) ,
"movementSpeedZ" : self . printer _movementSpeedZ ( ) ,
"movementSpeedE" : self . printer _movementSpeedE ( )
} ,
"webcam" : {
"streamUrl" : self . webcam _streamUrl ( ) ,
"snapshotUrl" : self . webcam _snapshotUrl ( ) ,
"ffmpegPath" : self . webcam _ffmpegPath ( ) ,
2013-03-08 23:23:52 +00:00
"bitrate" : self . webcam _bitrate ( ) ,
2013-06-18 22:42:43 +00:00
"watermark" : self . webcam _watermark ( ) ,
"flipX" : self . webcam _flipX ( ) ,
"flipY" : self . webcam _flipY ( )
2013-02-17 21:30:34 +00:00
} ,
"feature" : {
"gcodeViewer" : self . feature _gcodeViewer ( ) ,
2013-05-20 17:18:03 +00:00
"waitForStart" : self . feature _waitForStart ( ) ,
2013-03-16 17:25:39 +00:00
"alwaysSendChecksum" : self . feature _alwaysSendChecksum ( ) ,
2013-05-23 20:53:34 +00:00
"resetLineNumbersWithPrefixedN" : self . feature _resetLineNumbersWithPrefixedN ( ) ,
"waitForStart" : self . feature _waitForStart ( ) ,
2013-05-20 17:18:03 +00:00
"sdSupport" : self . feature _sdSupport ( )
2013-02-17 21:30:34 +00:00
} ,
"folder" : {
"uploads" : self . folder _uploads ( ) ,
"timelapse" : self . folder _timelapse ( ) ,
"timelapseTmp" : self . folder _timelapseTmp ( ) ,
"logs" : self . folder _logs ( )
2013-02-23 01:09:30 +00:00
} ,
"temperature" : {
2013-02-23 21:46:29 +00:00
"profiles" : self . temperature _profiles ( )
2013-03-10 16:04:05 +00:00
} ,
"system" : {
"actions" : self . system _actions ( )
2013-02-23 21:46:29 +00:00
}
2013-02-17 21:30:34 +00:00
}
$ . ajax ( {
url : AJAX _BASEURL + "settings" ,
type : "POST" ,
dataType : "json" ,
contentType : "application/json; charset=UTF-8" ,
data : JSON . stringify ( data ) ,
success : function ( response ) {
self . fromResponse ( response ) ;
$ ( "#settings_dialog" ) . modal ( "hide" ) ;
}
} )
}
}
2013-04-13 19:40:28 +00:00
function NavigationViewModel ( loginStateViewModel , appearanceViewModel , settingsViewModel , usersViewModel ) {
2013-03-10 16:04:05 +00:00
var self = this ;
2013-03-19 22:06:48 +00:00
self . loginState = loginStateViewModel ;
2013-03-10 16:04:05 +00:00
self . appearance = appearanceViewModel ;
self . systemActions = settingsViewModel . system _actions ;
2013-04-13 19:40:28 +00:00
self . users = usersViewModel ;
2013-03-10 16:04:05 +00:00
self . triggerAction = function ( action ) {
var callback = function ( ) {
$ . ajax ( {
url : AJAX _BASEURL + "system" ,
type : "POST" ,
dataType : "json" ,
data : "action=" + action . action ,
success : function ( ) {
$ . pnotify ( { title : "Success" , text : "The command \"" + action . name + "\" executed successfully" , type : "success" } ) ;
} ,
error : function ( jqXHR , textStatus , errorThrown ) {
$ . pnotify ( { title : "Error" , text : "<p>The command \"" + action . name + "\" could not be executed.</p><p>Reason: <pre>" + jqXHR . responseText + "</pre></p>" , type : "error" } ) ;
}
} )
}
if ( action . confirm ) {
$ ( "#confirmation_dialog .confirmation_dialog_message" ) . text ( action . confirm ) ;
$ ( "#confirmation_dialog .confirmation_dialog_acknowledge" ) . click ( function ( e ) { e . preventDefault ( ) ; $ ( "#confirmation_dialog" ) . modal ( "hide" ) ; callback ( ) ; } ) ;
$ ( "#confirmation_dialog" ) . modal ( "show" ) ;
} else {
callback ( ) ;
}
}
}
2013-04-13 19:40:28 +00:00
function DataUpdater ( loginStateViewModel , connectionViewModel , printerStateViewModel , temperatureViewModel , controlViewModel , terminalViewModel , gcodeFilesViewModel , timelapseViewModel , gcodeViewModel ) {
2012-12-25 19:49:10 +00:00
var self = this ;
2013-03-19 22:06:48 +00:00
self . loginStateViewModel = loginStateViewModel ;
2012-12-28 19:37:40 +00:00
self . connectionViewModel = connectionViewModel ;
2012-12-25 19:49:10 +00:00
self . printerStateViewModel = printerStateViewModel ;
self . temperatureViewModel = temperatureViewModel ;
2013-04-07 20:15:04 +00:00
self . controlViewModel = controlViewModel ;
2012-12-25 19:49:10 +00:00
self . terminalViewModel = terminalViewModel ;
2013-02-03 20:14:22 +00:00
self . gcodeFilesViewModel = gcodeFilesViewModel ;
2013-04-07 20:15:04 +00:00
self . timelapseViewModel = timelapseViewModel ;
2013-02-02 11:36:43 +00:00
self . gcodeViewModel = gcodeViewModel ;
2012-12-25 19:49:10 +00:00
2013-01-11 23:00:58 +00:00
self . _socket = io . connect ( ) ;
self . _socket . on ( "connect" , function ( ) {
2013-01-06 21:10:59 +00:00
if ( $ ( "#offline_overlay" ) . is ( ":visible" ) ) {
$ ( "#offline_overlay" ) . hide ( ) ;
2013-04-07 20:15:04 +00:00
self . timelapseViewModel . requestData ( ) ;
$ ( "#webcam_image" ) . attr ( "src" , CONFIG _WEBCAM _STREAM + "?" + new Date ( ) . getTime ( ) ) ;
2013-03-19 22:06:48 +00:00
self . loginStateViewModel . requestData ( ) ;
2013-05-21 21:08:34 +00:00
self . gcodeFilesViewModel . requestData ( ) ;
2013-01-06 21:10:59 +00:00
}
} )
2013-01-11 23:00:58 +00:00
self . _socket . on ( "disconnect" , function ( ) {
2013-01-13 17:28:55 +00:00
$ ( "#offline_overlay_message" ) . html (
"The server appears to be offline, at least I'm not getting any response from it. I'll try to reconnect " +
"automatically <strong>over the next couple of minutes</strong>, however you are welcome to try a manual reconnect " +
"anytime using the button below."
) ;
2013-01-06 21:10:59 +00:00
if ( ! $ ( "#offline_overlay" ) . is ( ":visible" ) )
$ ( "#offline_overlay" ) . show ( ) ;
} )
2013-01-13 17:28:55 +00:00
self . _socket . on ( "reconnect_failed" , function ( ) {
$ ( "#offline_overlay_message" ) . html (
"The server appears to be offline, at least I'm not getting any response from it. I <strong>could not reconnect automatically</strong>, " +
"but you may try a manual reconnect using the button below."
) ;
} )
2013-01-11 23:00:58 +00:00
self . _socket . on ( "history" , function ( data ) {
self . connectionViewModel . fromHistoryData ( data ) ;
2013-01-10 22:40:00 +00:00
self . printerStateViewModel . fromHistoryData ( data ) ;
self . temperatureViewModel . fromHistoryData ( data ) ;
2013-04-07 20:15:04 +00:00
self . controlViewModel . fromHistoryData ( data ) ;
2013-01-11 23:00:58 +00:00
self . terminalViewModel . fromHistoryData ( data ) ;
2013-04-07 20:15:04 +00:00
self . timelapseViewModel . fromHistoryData ( data ) ;
2013-02-02 11:36:43 +00:00
self . gcodeViewModel . fromHistoryData ( data ) ;
2013-03-30 17:21:49 +00:00
self . gcodeFilesViewModel . fromCurrentData ( data ) ;
2013-01-10 22:40:00 +00:00
} )
2013-01-11 23:00:58 +00:00
self . _socket . on ( "current" , function ( data ) {
2013-01-10 22:40:00 +00:00
self . connectionViewModel . fromCurrentData ( data ) ;
self . printerStateViewModel . fromCurrentData ( data ) ;
self . temperatureViewModel . fromCurrentData ( data ) ;
2013-04-07 20:15:04 +00:00
self . controlViewModel . fromCurrentData ( data ) ;
2013-01-11 23:00:58 +00:00
self . terminalViewModel . fromCurrentData ( data ) ;
2013-04-07 20:15:04 +00:00
self . timelapseViewModel . fromCurrentData ( data ) ;
2013-02-02 11:36:43 +00:00
self . gcodeViewModel . fromCurrentData ( data ) ;
2013-03-30 17:21:49 +00:00
self . gcodeFilesViewModel . fromCurrentData ( data ) ;
2013-01-06 20:19:39 +00:00
} )
2013-02-03 20:14:22 +00:00
self . _socket . on ( "updateTrigger" , function ( type ) {
if ( type == "gcodeFiles" ) {
gcodeFilesViewModel . requestData ( ) ;
}
} )
2013-01-11 23:00:58 +00:00
self . reconnect = function ( ) {
self . _socket . socket . connect ( ) ;
}
2012-12-25 19:49:10 +00:00
}
2013-05-20 17:18:03 +00:00
function ItemListHelper ( listType , supportedSorting , supportedFilters , defaultSorting , defaultFilters , exclusiveFilters , filesPerPage ) {
2013-03-06 22:27:16 +00:00
var self = this ;
self . listType = listType ;
self . supportedSorting = supportedSorting ;
self . supportedFilters = supportedFilters ;
self . defaultSorting = defaultSorting ;
self . defaultFilters = defaultFilters ;
2013-05-20 17:18:03 +00:00
self . exclusiveFilters = exclusiveFilters ;
2013-03-06 22:27:16 +00:00
self . allItems = [ ] ;
self . items = ko . observableArray ( [ ] ) ;
self . pageSize = ko . observable ( filesPerPage ) ;
self . currentPage = ko . observable ( 0 ) ;
self . currentSorting = ko . observable ( self . defaultSorting ) ;
self . currentFilters = ko . observableArray ( self . defaultFilters ) ;
//~~ item handling
self . updateItems = function ( items ) {
self . allItems = items ;
self . _updateItems ( ) ;
}
//~~ pagination
self . paginatedItems = ko . dependentObservable ( function ( ) {
if ( self . items ( ) == undefined ) {
return [ ] ;
} else {
var from = Math . max ( self . currentPage ( ) * self . pageSize ( ) , 0 ) ;
var to = Math . min ( from + self . pageSize ( ) , self . items ( ) . length ) ;
return self . items ( ) . slice ( from , to ) ;
}
} )
self . lastPage = ko . dependentObservable ( function ( ) {
return Math . ceil ( self . items ( ) . length / self . pageSize ( ) ) - 1 ;
} )
self . pages = ko . dependentObservable ( function ( ) {
var pages = [ ] ;
if ( self . lastPage ( ) < 7 ) {
for ( var i = 0 ; i < self . lastPage ( ) + 1 ; i ++ ) {
pages . push ( { number : i , text : i + 1 } ) ;
}
} else {
pages . push ( { number : 0 , text : 1 } ) ;
if ( self . currentPage ( ) < 5 ) {
for ( var i = 1 ; i < 5 ; i ++ ) {
pages . push ( { number : i , text : i + 1 } ) ;
}
pages . push ( { number : - 1 , text : "…" } ) ;
} else if ( self . currentPage ( ) > self . lastPage ( ) - 5 ) {
pages . push ( { number : - 1 , text : "…" } ) ;
for ( var i = self . lastPage ( ) - 4 ; i < self . lastPage ( ) ; i ++ ) {
pages . push ( { number : i , text : i + 1 } ) ;
}
} else {
pages . push ( { number : - 1 , text : "…" } ) ;
for ( var i = self . currentPage ( ) - 1 ; i <= self . currentPage ( ) + 1 ; i ++ ) {
pages . push ( { number : i , text : i + 1 } ) ;
}
pages . push ( { number : - 1 , text : "…" } ) ;
}
pages . push ( { number : self . lastPage ( ) , text : self . lastPage ( ) + 1 } )
}
return pages ;
} )
self . switchToItem = function ( matcher ) {
var pos = - 1 ;
var itemList = self . items ( ) ;
for ( var i = 0 ; i < itemList . length ; i ++ ) {
if ( matcher ( itemList [ i ] ) ) {
pos = i ;
break ;
}
}
if ( pos > - 1 ) {
var page = Math . floor ( pos / self . pageSize ( ) ) ;
self . changePage ( page ) ;
}
}
self . changePage = function ( newPage ) {
if ( newPage < 0 || newPage > self . lastPage ( ) )
return ;
self . currentPage ( newPage ) ;
}
self . prevPage = function ( ) {
if ( self . currentPage ( ) > 0 ) {
self . currentPage ( self . currentPage ( ) - 1 ) ;
}
}
self . nextPage = function ( ) {
if ( self . currentPage ( ) < self . lastPage ( ) ) {
self . currentPage ( self . currentPage ( ) + 1 ) ;
}
}
2013-05-20 17:18:03 +00:00
self . getItem = function ( matcher ) {
var itemList = self . items ( ) ;
for ( var i = 0 ; i < itemList . length ; i ++ ) {
if ( matcher ( itemList [ i ] ) ) {
return itemList [ i ] ;
}
}
return undefined ;
}
2013-03-06 22:27:16 +00:00
//~~ sorting
self . changeSorting = function ( sorting ) {
if ( ! _ . contains ( _ . keys ( self . supportedSorting ) , sorting ) )
return ;
self . currentSorting ( sorting ) ;
self . _saveCurrentSortingToLocalStorage ( ) ;
self . changePage ( 0 ) ;
self . _updateItems ( ) ;
}
//~~ filtering
self . toggleFilter = function ( filter ) {
if ( ! _ . contains ( _ . keys ( self . supportedFilters ) , filter ) )
return ;
if ( _ . contains ( self . currentFilters ( ) , filter ) ) {
self . removeFilter ( filter ) ;
} else {
self . addFilter ( filter ) ;
}
}
self . addFilter = function ( filter ) {
if ( ! _ . contains ( _ . keys ( self . supportedFilters ) , filter ) )
return ;
2013-05-20 17:18:03 +00:00
for ( var i = 0 ; i < self . exclusiveFilters . length ; i ++ ) {
if ( _ . contains ( self . exclusiveFilters [ i ] , filter ) ) {
for ( var j = 0 ; j < self . exclusiveFilters [ i ] . length ; j ++ ) {
if ( self . exclusiveFilters [ i ] [ j ] == filter )
continue ;
self . removeFilter ( self . exclusiveFilters [ i ] [ j ] ) ;
}
}
}
2013-03-06 22:27:16 +00:00
var filters = self . currentFilters ( ) ;
filters . push ( filter ) ;
self . currentFilters ( filters ) ;
self . _saveCurrentFiltersToLocalStorage ( ) ;
self . _updateItems ( ) ;
}
self . removeFilter = function ( filter ) {
2013-05-20 17:18:03 +00:00
if ( ! _ . contains ( _ . keys ( self . supportedFilters ) , filter ) )
2013-03-06 22:27:16 +00:00
return ;
var filters = self . currentFilters ( ) ;
filters . pop ( filter ) ;
self . currentFilters ( filters ) ;
self . _saveCurrentFiltersToLocalStorage ( ) ;
self . _updateItems ( ) ;
}
//~~ update for sorted and filtered view
self . _updateItems = function ( ) {
// determine comparator
var comparator = undefined ;
var currentSorting = self . currentSorting ( ) ;
if ( typeof currentSorting !== undefined && typeof self . supportedSorting [ currentSorting ] !== undefined ) {
comparator = self . supportedSorting [ currentSorting ] ;
}
// work on all items
var result = self . allItems ;
// filter if necessary
var filters = self . currentFilters ( ) ;
_ . each ( filters , function ( filter ) {
if ( typeof filter !== undefined && typeof supportedFilters [ filter ] !== undefined )
result = _ . filter ( result , supportedFilters [ filter ] ) ;
} ) ;
// sort if necessary
if ( typeof comparator !== undefined )
result . sort ( comparator ) ;
// set result list
self . items ( result ) ;
}
//~~ local storage
self . _saveCurrentSortingToLocalStorage = function ( ) {
2013-06-06 05:23:30 +00:00
if ( self . _initializeLocalStorage ( ) ) {
var currentSorting = self . currentSorting ( ) ;
if ( currentSorting !== undefined )
localStorage [ self . listType + "." + "currentSorting" ] = currentSorting ;
else
localStorage [ self . listType + "." + "currentSorting" ] = undefined ;
}
2013-03-06 22:27:16 +00:00
}
self . _loadCurrentSortingFromLocalStorage = function ( ) {
2013-06-06 05:23:30 +00:00
if ( self . _initializeLocalStorage ( ) ) {
if ( _ . contains ( _ . keys ( supportedSorting ) , localStorage [ self . listType + "." + "currentSorting" ] ) )
self . currentSorting ( localStorage [ self . listType + "." + "currentSorting" ] ) ;
else
self . currentSorting ( defaultSorting ) ;
}
2013-03-06 22:27:16 +00:00
}
self . _saveCurrentFiltersToLocalStorage = function ( ) {
2013-06-06 05:23:30 +00:00
if ( self . _initializeLocalStorage ( ) ) {
var filters = _ . intersection ( _ . keys ( self . supportedFilters ) , self . currentFilters ( ) ) ;
localStorage [ self . listType + "." + "currentFilters" ] = JSON . stringify ( filters ) ;
}
2013-03-06 22:27:16 +00:00
}
self . _loadCurrentFiltersFromLocalStorage = function ( ) {
2013-06-06 05:23:30 +00:00
if ( self . _initializeLocalStorage ( ) ) {
self . currentFilters ( _ . intersection ( _ . keys ( self . supportedFilters ) , JSON . parse ( localStorage [ self . listType + "." + "currentFilters" ] ) ) ) ;
}
2013-03-06 22:27:16 +00:00
}
self . _initializeLocalStorage = function ( ) {
2013-06-06 05:23:30 +00:00
if ( ! Modernizr . localstorage )
return false ;
2013-03-13 08:01:18 +00:00
if ( localStorage [ self . listType + "." + "currentSorting" ] !== undefined && localStorage [ self . listType + "." + "currentFilters" ] !== undefined && JSON . parse ( localStorage [ self . listType + "." + "currentFilters" ] ) instanceof Array )
2013-06-06 05:23:30 +00:00
return true ;
2013-03-06 22:27:16 +00:00
2013-03-13 08:01:18 +00:00
localStorage [ self . listType + "." + "currentSorting" ] = self . defaultSorting ;
localStorage [ self . listType + "." + "currentFilters" ] = JSON . stringify ( self . defaultFilters ) ;
2013-06-06 05:23:30 +00:00
return true ;
2013-03-06 22:27:16 +00:00
}
self . _loadCurrentFiltersFromLocalStorage ( ) ;
self . _loadCurrentSortingFromLocalStorage ( ) ;
}
2013-03-10 16:04:05 +00:00
function AppearanceViewModel ( settingsViewModel ) {
var self = this ;
self . name = settingsViewModel . appearance _name ;
self . color = settingsViewModel . appearance _color ;
self . brand = ko . computed ( function ( ) {
if ( self . name ( ) )
return "OctoPrint: " + self . name ( ) ;
else
return "OctoPrint" ;
} )
self . title = ko . computed ( function ( ) {
if ( self . name ( ) )
return self . name ( ) + " [OctoPrint]" ;
else
return "OctoPrint" ;
} )
}
2012-12-25 19:49:10 +00:00
$ ( function ( ) {
2012-12-29 14:41:23 +00:00
2013-01-11 23:00:58 +00:00
//~~ View models
2013-04-12 21:08:14 +00:00
var loginStateViewModel = new LoginStateViewModel ( loginStateViewModel ) ;
var usersViewModel = new UsersViewModel ( loginStateViewModel ) ;
2013-03-19 22:06:48 +00:00
var connectionViewModel = new ConnectionViewModel ( loginStateViewModel ) ;
var printerStateViewModel = new PrinterStateViewModel ( loginStateViewModel ) ;
2013-04-12 21:08:14 +00:00
var settingsViewModel = new SettingsViewModel ( loginStateViewModel , usersViewModel ) ;
2013-03-02 10:56:32 +00:00
var appearanceViewModel = new AppearanceViewModel ( settingsViewModel ) ;
2013-03-19 22:06:48 +00:00
var temperatureViewModel = new TemperatureViewModel ( loginStateViewModel , settingsViewModel ) ;
2013-04-13 20:26:23 +00:00
var controlViewModel = new ControlViewModel ( loginStateViewModel ) ;
2013-03-19 22:06:48 +00:00
var terminalViewModel = new TerminalViewModel ( loginStateViewModel ) ;
var gcodeFilesViewModel = new GcodeFilesViewModel ( loginStateViewModel ) ;
var timelapseViewModel = new TimelapseViewModel ( loginStateViewModel ) ;
var gcodeViewModel = new GcodeViewModel ( loginStateViewModel ) ;
2013-04-13 19:40:28 +00:00
var navigationViewModel = new NavigationViewModel ( loginStateViewModel , appearanceViewModel , settingsViewModel , usersViewModel ) ;
2013-02-03 21:01:11 +00:00
2013-02-03 20:38:00 +00:00
var dataUpdater = new DataUpdater (
2013-03-19 22:06:48 +00:00
loginStateViewModel ,
2013-02-03 20:38:00 +00:00
connectionViewModel ,
printerStateViewModel ,
temperatureViewModel ,
2013-04-07 20:15:04 +00:00
controlViewModel ,
2013-02-03 20:38:00 +00:00
terminalViewModel ,
gcodeFilesViewModel ,
2013-04-07 20:15:04 +00:00
timelapseViewModel ,
2013-02-03 20:38:00 +00:00
gcodeViewModel
) ;
2013-03-15 01:55:02 +00:00
2013-03-19 22:06:48 +00:00
// work around a stupid iOS6 bug where ajax requests get cached and only work once, as described at
// http://stackoverflow.com/questions/12506897/is-safari-on-ios-6-caching-ajax-results
2013-03-15 01:55:02 +00:00
$ . ajaxSetup ( {
2013-04-07 20:15:04 +00:00
type : 'POST' ,
headers : { "cache-control" : "no-cache" }
} ) ;
2013-02-03 20:14:22 +00:00
2013-03-02 10:56:32 +00:00
//~~ Show settings - to ensure centered
$ ( '#navbar_show_settings' ) . click ( function ( ) {
$ ( '#settings_dialog' ) . modal ( )
. css ( {
width : 'auto' ,
'margin-left' : function ( ) { return - ( $ ( this ) . width ( ) / 2 ) ; }
} ) ;
return false ;
} )
2013-02-23 18:38:18 +00:00
//~~ Temperature control (should really move to knockout click binding)
2012-12-29 14:41:23 +00:00
2013-02-23 18:38:18 +00:00
$ ( "#temp_newTemp_set" ) . click ( function ( ) {
2012-12-26 14:03:34 +00:00
var newTemp = $ ( "#temp_newTemp" ) . val ( ) ;
$ . ajax ( {
url : AJAX _BASEURL + "control/temperature" ,
type : "POST" ,
dataType : "json" ,
data : { temp : newTemp } ,
success : function ( ) { $ ( "#temp_newTemp" ) . val ( "" ) }
} )
} )
2013-02-23 18:38:18 +00:00
$ ( "#temp_newBedTemp_set" ) . click ( function ( ) {
2012-12-26 14:03:34 +00:00
var newBedTemp = $ ( "#temp_newBedTemp" ) . val ( ) ;
$ . ajax ( {
url : AJAX _BASEURL + "control/temperature" ,
type : "POST" ,
dataType : "json" ,
data : { bedTemp : newBedTemp } ,
success : function ( ) { $ ( "#temp_newBedTemp" ) . val ( "" ) }
} )
} )
2013-01-11 23:00:58 +00:00
$ ( '#tabs a[data-toggle="tab"]' ) . on ( 'shown' , function ( e ) {
temperatureViewModel . updatePlot ( ) ;
2013-03-19 22:06:48 +00:00
terminalViewModel . updateOutput ( ) ;
2013-01-11 23:00:58 +00:00
} ) ;
2012-12-26 14:03:34 +00:00
2012-12-29 14:41:23 +00:00
//~~ Terminal
2013-03-11 20:46:05 +00:00
$ ( "#terminal-send" ) . click ( function ( ) {
2012-12-25 19:49:10 +00:00
var command = $ ( "#terminal-command" ) . val ( ) ;
2013-04-16 12:45:25 +00:00
/ *
var re = /^([gm][0-9]+)(\s.*)?/ ;
var commandMatch = command . match ( re ) ;
if ( commandMatch != null ) {
command = commandMatch [ 1 ] . toUpperCase ( ) + ( ( commandMatch [ 2 ] !== undefined ) ? commandMatch [ 2 ] : "" ) ;
}
* /
2012-12-29 14:41:23 +00:00
if ( command ) {
$ . ajax ( {
url : AJAX _BASEURL + "control/command" ,
type : "POST" ,
dataType : "json" ,
2013-02-23 17:08:59 +00:00
contentType : "application/json; charset=UTF-8" ,
data : JSON . stringify ( { "command" : command } )
2012-12-29 14:41:23 +00:00
} )
2013-03-11 20:46:05 +00:00
$ ( "#terminal-command" ) . val ( '' )
2012-12-29 14:41:23 +00:00
}
2013-03-11 20:46:05 +00:00
2013-03-11 14:38:41 +00:00
} )
2013-03-11 20:46:05 +00:00
$ ( "#terminal-command" ) . keyup ( function ( event ) {
if ( event . keyCode == 13 ) {
2013-03-11 14:38:41 +00:00
$ ( "#terminal-send" ) . click ( )
2013-03-11 20:46:05 +00:00
}
2012-12-25 19:49:10 +00:00
} )
2012-12-29 14:41:23 +00:00
//~~ Gcode upload
2013-05-20 21:31:17 +00:00
function gcode _upload _done ( e , data ) {
gcodeFilesViewModel . fromResponse ( data . result ) ;
$ ( "#gcode_upload_progress .bar" ) . css ( "width" , "0%" ) ;
$ ( "#gcode_upload_progress" ) . removeClass ( "progress-striped" ) . removeClass ( "active" ) ;
$ ( "#gcode_upload_progress .bar" ) . text ( "" ) ;
}
function gcode _upload _progress ( e , data ) {
var progress = parseInt ( data . loaded / data . total * 100 , 10 ) ;
$ ( "#gcode_upload_progress .bar" ) . css ( "width" , progress + "%" ) ;
$ ( "#gcode_upload_progress .bar" ) . text ( "Uploading ..." ) ;
if ( progress >= 100 ) {
$ ( "#gcode_upload_progress" ) . addClass ( "progress-striped" ) . addClass ( "active" ) ;
$ ( "#gcode_upload_progress .bar" ) . text ( "Saving ..." ) ;
}
}
var localTarget ;
if ( CONFIG _SD _SUPPORT ) {
localTarget = $ ( "#drop_locally" ) ;
} else {
localTarget = $ ( "#drop" ) ;
}
2012-12-28 19:37:40 +00:00
$ ( "#gcode_upload" ) . fileupload ( {
dataType : "json" ,
2013-05-20 21:31:17 +00:00
dropZone : localTarget ,
formData : { target : "local" } ,
done : gcode _upload _done ,
progressall : gcode _upload _progress
2012-12-25 19:49:10 +00:00
} ) ;
2013-05-20 21:31:17 +00:00
if ( CONFIG _SD _SUPPORT ) {
$ ( "#gcode_upload_sd" ) . fileupload ( {
dataType : "json" ,
dropZone : $ ( "#drop_sd" ) ,
formData : { target : "sd" } ,
done : gcode _upload _done ,
progressall : gcode _upload _progress
} ) ;
}
$ ( document ) . bind ( "dragover" , function ( e ) {
var dropOverlay = $ ( "#drop_overlay" ) ;
var dropZone = $ ( "#drop" ) ;
var dropZoneLocal = $ ( "#drop_locally" ) ;
var dropZoneSd = $ ( "#drop_sd" ) ;
var dropZoneBackground = $ ( "#drop_background" ) ;
var dropZoneLocalBackground = $ ( "#drop_locally_background" ) ;
var dropZoneSdBackground = $ ( "#drop_sd_background" ) ;
var timeout = window . dropZoneTimeout ;
if ( ! timeout ) {
dropOverlay . addClass ( 'in' ) ;
} else {
clearTimeout ( timeout ) ;
}
var foundLocal = false ;
var foundSd = false ;
var found = false
var node = e . target ;
do {
if ( dropZoneLocal && node === dropZoneLocal [ 0 ] ) {
foundLocal = true ;
break ;
} else if ( dropZoneSd && node === dropZoneSd [ 0 ] ) {
foundSd = true ;
break ;
} else if ( dropZone && node === dropZone [ 0 ] ) {
found = true ;
break ;
2013-05-20 17:18:03 +00:00
}
2013-05-20 21:31:17 +00:00
node = node . parentNode ;
} while ( node != null ) ;
if ( foundLocal ) {
dropZoneLocalBackground . addClass ( "hover" ) ;
dropZoneSdBackground . removeClass ( "hover" ) ;
} else if ( foundSd ) {
dropZoneSdBackground . addClass ( "hover" ) ;
dropZoneLocalBackground . removeClass ( "hover" ) ;
} else if ( found ) {
dropZoneBackground . addClass ( "hover" ) ;
} else {
if ( dropZoneLocalBackground ) dropZoneLocalBackground . removeClass ( "hover" ) ;
if ( dropZoneSdBackground ) dropZoneSdBackground . removeClass ( "hover" ) ;
if ( dropZoneBackground ) dropZoneBackground . removeClass ( "hover" ) ;
2013-05-20 17:18:03 +00:00
}
2013-05-20 21:31:17 +00:00
window . dropZoneTimeout = setTimeout ( function ( ) {
window . dropZoneTimeout = null ;
dropOverlay . removeClass ( "in" ) ;
if ( dropZoneLocal ) dropZoneLocalBackground . removeClass ( "hover" ) ;
if ( dropZoneSd ) dropZoneSdBackground . removeClass ( "hover" ) ;
if ( dropZone ) dropZoneBackground . removeClass ( "hover" ) ;
} , 100 ) ;
2013-05-20 17:18:03 +00:00
} ) ;
2012-12-30 19:30:31 +00:00
//~~ Offline overlay
2013-01-11 23:00:58 +00:00
$ ( "#offline_overlay_reconnect" ) . click ( function ( ) { dataUpdater . reconnect ( ) } ) ;
2012-12-30 19:30:31 +00:00
2012-12-29 14:41:23 +00:00
//~~ knockout.js bindings
2013-01-30 19:56:17 +00:00
ko . bindingHandlers . popover = {
init : function ( element , valueAccessor , allBindingsAccessor , viewModel , bindingContext ) {
var val = ko . utils . unwrapObservable ( valueAccessor ( ) ) ;
var options = {
title : val . title ,
animation : val . animation ,
placement : val . placement ,
trigger : val . trigger ,
delay : val . delay ,
content : val . content ,
html : val . html
} ;
$ ( element ) . popover ( options ) ;
}
}
2013-04-13 19:40:28 +00:00
ko . applyBindings ( connectionViewModel , document . getElementById ( "connection_accordion" ) ) ;
ko . applyBindings ( printerStateViewModel , document . getElementById ( "state_accordion" ) ) ;
ko . applyBindings ( gcodeFilesViewModel , document . getElementById ( "files_accordion" ) ) ;
2012-12-25 19:49:10 +00:00
ko . applyBindings ( temperatureViewModel , document . getElementById ( "temp" ) ) ;
2013-04-07 20:15:04 +00:00
ko . applyBindings ( controlViewModel , document . getElementById ( "control" ) ) ;
2012-12-25 19:49:10 +00:00
ko . applyBindings ( terminalViewModel , document . getElementById ( "term" ) ) ;
2013-02-03 21:01:11 +00:00
ko . applyBindings ( gcodeViewModel , document . getElementById ( "gcode" ) ) ;
2013-02-17 21:30:34 +00:00
ko . applyBindings ( settingsViewModel , document . getElementById ( "settings_dialog" ) ) ;
2013-03-10 16:04:05 +00:00
ko . applyBindings ( navigationViewModel , document . getElementById ( "navbar" ) ) ;
2013-03-02 10:56:32 +00:00
ko . applyBindings ( appearanceViewModel , document . getElementsByTagName ( "head" ) [ 0 ] ) ;
2012-12-29 14:41:23 +00:00
2013-04-07 20:15:04 +00:00
var timelapseElement = document . getElementById ( "timelapse" ) ;
if ( timelapseElement ) {
2013-03-19 22:06:48 +00:00
ko . applyBindings ( timelapseViewModel , timelapseElement ) ;
2013-01-03 14:25:20 +00:00
}
2013-02-03 21:01:11 +00:00
var gCodeVisualizerElement = document . getElementById ( "gcode" ) ;
2013-03-19 22:06:48 +00:00
if ( gCodeVisualizerElement ) {
2013-02-02 16:45:36 +00:00
gcodeViewModel . initialize ( ) ;
}
2013-04-13 19:40:28 +00:00
2012-12-29 14:41:23 +00:00
//~~ startup commands
2012-12-25 19:49:10 +00:00
2013-03-19 22:06:48 +00:00
loginStateViewModel . requestData ( ) ;
2013-01-01 20:04:00 +00:00
connectionViewModel . requestData ( ) ;
2013-04-07 20:15:04 +00:00
controlViewModel . requestData ( ) ;
2013-01-01 20:04:00 +00:00
gcodeFilesViewModel . requestData ( ) ;
2013-04-07 20:15:04 +00:00
timelapseViewModel . requestData ( ) ;
2013-04-13 19:40:28 +00:00
loginStateViewModel . subscribe ( function ( change , data ) {
if ( "login" == change ) {
$ ( "#gcode_upload" ) . fileupload ( "enable" ) ;
settingsViewModel . requestData ( ) ;
if ( data . admin ) {
usersViewModel . requestData ( ) ;
}
} else {
$ ( "#gcode_upload" ) . fileupload ( "disable" ) ;
}
2013-05-20 17:18:03 +00:00
} ) ;
2013-01-01 20:04:00 +00:00
2013-01-30 19:56:17 +00:00
//~~ UI stuff
$ ( ".accordion-toggle[href='#files']" ) . click ( function ( ) {
if ( $ ( "#files" ) . hasClass ( "in" ) ) {
$ ( "#files" ) . removeClass ( "overflow_visible" ) ;
} else {
setTimeout ( function ( ) {
$ ( "#files" ) . addClass ( "overflow_visible" ) ;
} , 1000 ) ;
}
} )
2013-03-10 16:04:05 +00:00
$ . pnotify . defaults . history = false ;
2013-04-12 21:08:14 +00:00
$ . fn . modal . defaults . maxHeight = function ( ) {
// subtract the height of the modal header and footer
return $ ( window ) . height ( ) - 165 ;
}
2013-03-19 22:06:48 +00:00
// Fix input element click problem on login dialog
2013-05-20 21:31:17 +00:00
$ ( ".dropdown input, .dropdown label" ) . click ( function ( e ) {
2013-03-17 21:28:08 +00:00
e . stopPropagation ( ) ;
} ) ;
2013-05-20 21:31:17 +00:00
$ ( document ) . bind ( "drop dragover" , function ( e ) {
e . preventDefault ( ) ;
} ) ;
2012-12-25 19:49:10 +00:00
}
) ;