diff --git a/Makefile b/Makefile index 33b5598..84a769a 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,7 @@ define Package/doodle3d-client/install $(CP) $(PKG_BUILD_DIR)/www/favicon* $(1)/www/ $(CP) $(PKG_BUILD_DIR)/www/index.html $(1)/www/ $(CP) $(PKG_BUILD_DIR)/www/settings.html $(1)/www/ + $(CP) $(PKG_BUILD_DIR)/www/helpcontent.html $(1)/www/ $(CP) $(PKG_BUILD_DIR)/www/css/debug.min.css $(1)/www/css/ $(CP) $(PKG_BUILD_DIR)/www/css/settings.min.css $(1)/www/css/ diff --git a/js_src/Help.js b/js_src/Help.js index bf46efa..371321a 100644 --- a/js_src/Help.js +++ b/js_src/Help.js @@ -4,6 +4,7 @@ function GrandTour(_name) { console.log("GrandTour"); this.tour = ""; this.name = _name; + this.active = false; var self = this; this.init = function() { @@ -20,17 +21,18 @@ function GrandTour(_name) { 'nubPosition': 'auto', // override on a per tooltip bases 'scrollSpeed': 300, // Page scrolling speed in ms // 'timer': 2000, // 0 = off, all other numbers = time(ms) - 'startTimerOnClick': true, // true/false to start timer on first click +// 'startTimerOnClick': true, // true/false to start timer on first click 'nextButton': true, // true/false for next button visibility 'tipAnimation': 'fade', // 'pop' or 'fade' in each tip - 'pauseAfter': [], // array of indexes where to pause the tour after - 'tipAnimationFadeSpeed': 250, // if 'fade'- speed in ms of transition +// 'pauseAfter': [], // array of indexes where to pause the tour after + 'tipAnimationFadeSpeed': 350, // if 'fade'- speed in ms of transition // 'cookieMonster': true, // true/false for whether cookies are used // 'cookieDomain': false, // set to false or yoursite.com // 'cookieName': 'Doodle3DFirstTime', // choose your own cookie name // 'localStorage': true, // // 'localStorageKey': 'Doodle3DFirstTime', // choose your own cookie name 'preRideCallback' : self.preRideCallback, + 'preStepCallback': self.preStepCallback, // A method to call before each step 'postStepCallback': self.postStepCallback, // A method to call after each step 'postRideCallback': self.postRideCallback // a method to call once the tour closes }); @@ -40,41 +42,126 @@ function GrandTour(_name) { this.preRideCallback = function(index, tip) { console.log("GrandTour >> f:preRideCallback() >> index: " + index); - if ($.cookie("Doodle3DFirstTime") == "ridden" && index == 0) { - console.log("we've been here before..."); - // $(this).joyride('set_li', false, 1); + if (index == 0 && $.cookie("Doodle3DFirstTime") == "ridden") { + console.log("GrandTour >> f:preRideCallback() >> we've been here before..."); + + if ($.cookie("grandTourFinished")) { + // grand tour was previously finished (eh.. is that useful?) + + // executing this 3 times because there doesn't seem to be a 'go to step X' method +// $(this).joyride('set_li', false); + $(this).joyride('set_li', false); + $(this).joyride('set_li', false); + } else { + $(this).joyride('set_li', false); + } } - if ($.cookie("Doodle3DFirstTime") == 'ridden') { - console.log("we've been here before..."); - $(this).joyride('set_li', false); - } + + // bring up all the elements + thermometer.show(); + progressbar.show(); +// if ($.cookie("Doodle3DFirstTime") == 'ridden') { +// console.log("we've been here before..."); +// $(this).joyride('set_li', false, 4); +// } // if (index == 0) { // console.log("...yeah"); // $(this).joyride('set_li', false, 1); // } }; + this.preStepCallback = function(index, tip) { + console.log("GrandTour >> f:preStepCallback() >> index: " + index); + + var dataset = $(this)[0].$li[0].dataset; + if (dataset.action != undefined) { + console.log(" THERE'S AN ACTION!"); + switch (dataset.action) { + case "sayHello": + console.log(" action: sayHello"); + break; + case "showMessage": + console.log(" action: showMessage"); + message.set("Just a notification...", Message.NOTICE); + message.show(); + break; + case "showProgressBar": + console.log(" action: showProgressBar"); + progressbar.show(); + break; + case "showThermometer": + console.log(" action: showThermometer"); + thermometer.show(); + break; + } + } + }; this.postStepCallback = function(index, tip) { console.log("GrandTour >> f:postStepCallback() >> index: " + index); + + var dataset = $(this)[0].$li[0].dataset; + if (dataset.action != undefined) { + console.log(" THERE *WAS* AN ACTION!"); + switch (dataset.action) { + case "sayHello": + console.log(" action: sayHello"); + break; + case "showMessage": + console.log(" action: showMessage"); +// message.hide(); + break; + case "showProgressBar": + console.log(" action: showProgressBar"); +// progressbar.hide(); + break; + case "showThermometer": + console.log(" action: showThermometer"); +// thermometer.hide(); + break; + } + } }; this.postRideCallback = function(index, tip) { - console.log("GrandTour >> f:postRideCallback() >> index: " + index); +// console.log("GrandTour >> f:postRideCallback() >> index: " + index + ", self.active: " + self.active); +// console.log("GrandTour >> f:postRideCallback() >> this: " , self); + + self.active = false; $(document).trigger(helpTours.TOURFINISHED, self.name); + // hide the elements which were summoned for the purposes of the tour + thermometer.hide(); + progressbar.hide(); + message.hide(); + + // after seeing the grand tour for the first time ever, set cookie 'Doodle3DFirstTime' to true + if (!$.cookie("Doodle3DFirstTime")) { + $.cookie("Doodle3DFirstTime", 'ridden', { expires: 365, domain: false, path: '/' }); + } + if (index < $(this)[0].$tip_content.length - 1) { - console.log("doPostRideCallback >> ENDED BEFORE END"); - helpTours.startTour(helpTours.INFOREMINDER); + console.log("GrandTour >> f:postRideCallback() >> tour terminated before its true end"); + // tour wasn't finished + + // tour was ended prematurely. For only the first few visits, nag the user about being able to revisit the tour.. + if (parseInt($.cookie("Doodle3DVisitCounter")) < helpTours.numTimesToShowNagPopup) { + helpTours.startTour(helpTours.INFOREMINDER, helpTours); + } // infoReminderTour.start(); } else { - console.log("doPostRideCallback >> this is the end my friend..."); + // tour was finished + console.log("GrandTour >> f:postRideCallback() >> tour ended at its true end"); // we should be at the end... - $.cookie("Doodle3DFirstTime", 'ridden', { expires: 365, domain: false, path: '/' }); + if (!$.cookie("grandTourFinished") && parseInt($.cookie("Doodle3DVisitCounter")) < helpTours.numTimesToShowNagPopup) { + helpTours.startTour(helpTours.INFOREMINDER, helpTours); + } + $.cookie("grandTourFinished", 'yes', { expires: 365, domain: false, path: '/' }); } }; this.start = function() { - console.log("GrandTour >> f:start()"); + console.log("GrandTour >> f:start() >> this: " , this); + this.active = true; $(window).joyride('restart'); // self.tour(); }; @@ -85,6 +172,7 @@ function InfoReminderTour(_name) { console.log("InfoReminderTour"); this.tour = ""; this.name = _name; + this.active = false; var self = this; this.init = function(callback) { @@ -97,12 +185,12 @@ function InfoReminderTour(_name) { expose: true, 'tipAdjustmentX': 15, 'tipAdjustmentY': 15, - 'tipLocation': 'left', // 'top' or 'bottom' in relation to parent + 'tipLocation': 'bottom', // 'top' or 'bottom' in relation to parent 'nubPosition': 'auto', // override on a per tooltip bases 'scrollSpeed': 300, // Page scrolling speed in ms 'nextButton': true, // true/false for next button visibility 'tipAnimation': 'fade', // 'pop' or 'fade' in each tip - 'tipAnimationFadeSpeed': 250, // if 'fade'- speed in ms of transition + 'tipAnimationFadeSpeed': 350, // if 'fade'- speed in ms of transition 'preRideCallback' : self.preRideCallback, 'postStepCallback': self.postStepCallback, // A method to call after each step 'postRideCallback': self.postRideCallback // a method to call once the tour closes @@ -120,11 +208,13 @@ function InfoReminderTour(_name) { }; this.postRideCallback = function(index, tip) { console.log("InfoReminderTour >> f:postRideCallback() >> index: " + index + ", tip: " , tip); + this.active = false; $(document).trigger(helpTours.TOURFINISHED, self.name); }; this.start = function() { console.log("InfoReminderTour >> f:start()"); + this.active = true; $(window).joyride('restart'); // self.tour(); }; @@ -133,26 +223,31 @@ function InfoReminderTour(_name) { function initHelp() { console.log("f:initHelp()"); + // track number of visits of this user + if ($.cookie("Doodle3DVisitCounter") == null) { + $.cookie("Doodle3DVisitCounter", '0'); + } else { + $.cookie("Doodle3DVisitCounter", parseInt($.cookie("Doodle3DVisitCounter")) + 1); + } - -// grandTour = new GrandTour(); -// infoReminderTour = new InfoReminderTour(); - - // first call inits the tour -// joyride2(); - + // load the html file which describes the tour contents $("#helpContainer").load("helpcontent.html", function() { console.log("helpContent loaded"); - helpTours = new HelpTours(); - helpTours.init(); -// grandTour.init(); -//// infoReminderTour.init(); -// -// if ($.cookie("Doodle3DFirstTime") != "ridden") { -// console.log("intro tour has not been given yet > let's go!"); -// setTimeout(grandTour.start, 1000); -// } + helpTours = new HelpTours(); + + helpTours.init( function () { + + // only trigger starttour if user is seeing Doodle3D for the first time + if ($.cookie("Doodle3DFirstTime") != "ridden") { + console.log("initHelp >> intro tour has not been given yet > let's go!"); + setTimeout(helpTours.startTour, 750, helpTours.tours.grandTour, helpTours); + } else if (parseInt($.cookie("Doodle3DVisitCounter")) < helpTours.numTimesToShowNagPopup) { + console.log("initHelp >> Doodle3DFirstTime cookie is set, Doodle3DVisitCounter is < 4"); + // remind user of our nifty tour + setTimeout(helpTours.startTour, 750, helpTours.tours.infoReminderTour, helpTours); + } + }); }); } @@ -161,64 +256,97 @@ var helpTours; function HelpTours() { console.log("HelpTours"); + this.numTimesToShowNagPopup = 4; + this.WELCOMETOUR = "welcometour"; this.INFOREMINDER = "inforeminder"; this.TOURFINISHED = "tourfinished"; + this.tours = { + 'grandTour' : this.WELCOMETOUR, + 'infoReminderTour' : this.INFOREMINDER + }; + this.currActiveTour = ""; this.tourActive = false; var self = this; - this.init = function() { - console.log("HelpTours >> f:init"); + this.init = function(callback) { + console.log("HelpTours >> f:init >> self: " + self); $(document).on(this.TOURFINISHED, this.tourEnded); grandTour = new GrandTour(this.WELCOMETOUR); infoReminderTour = new InfoReminderTour(this.INFOREMINDER); - if ($.cookie("Doodle3DFirstTime") != "ridden") { - console.log("HelpTours >> f:init >> intro tour has not been given yet > let's go! (this.WELCOMETOUR = " + this.WELCOMETOUR + ")"); - setTimeout(this.startTour, 1000, this.WELCOMETOUR); - } +// this.tours["grandTour"] = self.WELCOMETOUR; +// this.tours["infoReminderTour "]= self.INFOREMINDER; + console.log("HelpTours >> f:init >> this.tours: " , this.tours); + + if (callback != undefined) callback(); }; - this.startTour = function(which) { - console.log("HelpTours >> f:startTour >> target to start: '" + which); + this.startTour = function(which, scope) { + if (scope == undefined) scope = this; +// console.log("HelpTours >> f:startTour >> scope: " , scope); +// console.log("HelpTours >> f:startTour >> currActiveTour: " , scope.currActiveTour.name); +// console.log("HelpTours >> f:startTour >> currActiveTour.active: " , scope.currActiveTour.active); +// console.log("HelpTours >> f:startTour >> target to start: '" + which); + + switch (which) { - case self.WELCOMETOUR: + case scope.WELCOMETOUR: // do welcometour - console.log("HelpTours >> f:startTour >> case this.WELCOMETOUR >> self.tourActive = " + self.tourActive); - if (this.tourActive) { - $(window).joyride('end'); - this.tourActive = false; +// console.log("HelpTours >> f:startTour >> case this.WELCOMETOUR >> scope.tourActive = " + scope.tourActive); + console.log("HelpTours >> f:startTour >> case this.WELCOMETOUR"); + if (scope.tourActive) { + if (scope.currActiveTour.active == true) { + $(window).joyride('end'); + scope.currActiveTour = undefined; + } + scope.tourActive = false; } $(window).joyride('destroy'); - grandTour.init(); - grandTour.start(); - this.tourActive = true; +// var self = this; + grandTour.init(); + setTimeout(function(scp) { + grandTour.start(); + scp.currActiveTour = grandTour; + scp.tourActive = true; + }, 250, scope); // $(window).joyride('restart'); break; case self.INFOREMINDER: // do info reminder - console.log("HelpTours >> f:startTour >> case self.INFOREMINDER >> self.tourActive = " + self.tourActive); - if (this.tourActive) { - $(window).joyride('end'); - this.tourActive = false; +// console.log("HelpTours >> f:startTour >> case self.INFOREMINDER >> scope.tourActive = " + scope.tourActive); + console.log("HelpTours >> f:startTour >> case self.INFOREMINDER"); + if (scope.tourActive) { +// console.log(" killing previous joyride... "); + if (scope.currActiveTour.active == true) { + $(window).joyride('end'); + scope.currActiveTour = undefined; + } +// console.log(" setting tourActive to false...."); + scope.tourActive = false; +// console.log(" scope.tourActive: " + scope.tourActive); } $(window).joyride('destroy'); - infoReminderTour.init(); - infoReminderTour.start(); - this.tourActive = true; +// var self = this; + infoReminderTour.init(); + setTimeout(function(scp) { + infoReminderTour.start(); + scp.currActiveTour = infoReminderTour; + scp.tourActive = true; + }, 250, scope); break; } } this.tourEnded = function(e, n) { - console.log("HelpTours >> f:tourEnded >> name: " + n); + console.log("HelpTours >> f:tourEnded >> this.tourActive: " + self.tourActive + ", name: " + n); - this.tourActive = false; + self.tourActive = false; } } \ No newline at end of file diff --git a/js_src/Message.js b/js_src/Message.js index dc3cab3..54c347e 100644 --- a/js_src/Message.js +++ b/js_src/Message.js @@ -10,7 +10,7 @@ function Message() { this.$element; var self = this; - var autoHideDelay = 2000; + var autoHideDelay = 5000; var autohideTimeout; this.init = function($element) { diff --git a/js_src/Printer.js b/js_src/Printer.js index 5895831..bdbd89f 100644 --- a/js_src/Printer.js +++ b/js_src/Printer.js @@ -11,7 +11,7 @@ function setPrintprogress(val) { //*/ function Printer() { - + Printer.WIFIBOX_DISCONNECTED_STATE = "wifibox disconnected"; Printer.UNKNOWN_STATE = "unknown"; // happens when a printer is connection but there isn't communication yet Printer.DISCONNECTED_STATE = "disconnected"; // printer disconnected @@ -21,22 +21,22 @@ function Printer() { Printer.STOPPING_STATE = "stopping"; // when you stop (abort) a print it prints the endcode Printer.ON_BEFORE_UNLOAD_MESSAGE = "You're doodle is still being send to the printer, leaving will result in a incomplete 3D print"; - + this.temperature = 0; this.targetTemperature = 0; this.currentLine = 0; this.totalLines = 0; this.bufferedLines = 0; this.state = Printer.UNKNOWN_STATE; - this.hasControl = true; // whether this client has control access - - this.wifiboxURL; - + this.hasControl = true; // whether this client has control access + + this.wifiboxURL; + this.checkStatusInterval = 3000; this.checkStatusDelay; this.timeoutTime = 3000; this.sendPrintPartTimeoutTime = 5000; - + this.gcode; // gcode to be printed this.sendLength = 1500; // max amount of gcode lines per post (limited because WiFi box can't handle to much) @@ -45,16 +45,16 @@ function Printer() { this.retryCheckStatusDelay; // retry setTimout instance this.retryStopDelay; // retry setTimout instance this.retryPreheatDelay; // retry setTimout instance - - this.maxGCodeSize = 10; // max size of gcode in MB's (estimation) - + + Printer.MAX_GCODE_SIZE = 10; // max size of gcode in MB's (estimation) + this.stateOverruled = false; - + // Events Printer.UPDATE = "update"; - + var self = this; - + this.init = function() { console.log("Printer:init"); //this.wifiboxURL = "http://" + window.location.host + "/cgi-bin/d3dapi"; @@ -62,21 +62,21 @@ function Printer() { this.wifiboxURL = wifiboxURL; //this.wifiboxURL = "proxy5.php"; console.log(" wifiboxURL: ",this.wifiboxURL); - + if(autoUpdate) { this.startStatusCheckInterval(); } } - + this.preheat = function() { console.log("Printer:preheat"); - + if( this.state == Printer.BUFFERING_STATE || this.state == Printer.PRINTING_STATE || this.state == Printer.STOPPING_STATE) { return; } - + var self = this; if (communicateWithWifibox) { $.ajax({ @@ -91,7 +91,7 @@ function Printer() { self.retryPreheatDelay = setTimeout(function() { self.preheat() },self.retryDelay); // retry after delay } } - }).fail(function() { + }).fail(function() { console.log("Printer:preheat: failed"); clearTimeout(self.retryPreheatDelay); self.retryPreheatDelay = setTimeout(function() { self.preheat() },self.retryDelay); // retry after delay @@ -100,34 +100,41 @@ function Printer() { console.log ("Printer >> f:preheat() >> communicateWithWifibox is false, so not executing this function"); } } - + this.print = function(gcode) { console.log("Printer:print"); console.log(" gcode total # of lines: " + gcode.length); - + message.set("Sending doodle to printer...",Message.NOTICE); self.addLeaveWarning(); - + /*for (i = 0; i < gcode.length; i++) { gcode[i] += " (" + i + ")"; }*/ - + this.sendIndex = 0; this.gcode = gcode; - + //console.log(" gcode[20]: ",gcode[20]); var gcodeLineSize = this.byteSize(gcode[20]); //console.log(" gcodeLineSize: ",gcodeLineSize); var gcodeSize = gcodeLineSize*gcode.length/1024/1024; // estimate gcode size in MB's console.log(" gcodeSize: ",gcodeSize); - - if(gcodeSize > this.maxGCodeSize) { - console.log("Error: Printer:print: gcode file is probably to big ("+gcodeSize+"MB) (max: "+this.maxGCodeSize+"MB)"); + + if(gcodeSize > Printer.MAX_GCODE_SIZE) { + alert("Error: Printer:print: gcode file is probably too big ("+gcodeSize+"MB) (max: "+Printer.MAX_GCODE_SIZE+"MB)"); + console.log("Error: Printer:print: gcode file is probably too big ("+gcodeSize+"MB) (max: "+Printer.MAX_GCODE_SIZE+"MB)"); + + this.overruleState(Printer.IDLE_STATE); + this.startStatusCheckInterval(); + message.hide(); + self.removeLeaveWarning(); + return; } - + //this.targetTemperature = settings["printer.temperature"]; // slight hack - + this.sendPrintPart(this.sendIndex, this.sendLength); } this.byteSize = function(s){ @@ -135,10 +142,10 @@ function Printer() { } this.sendPrintPart = function(sendIndex,sendLength) { console.log("Printer:sendPrintPart sendIndex: " + sendIndex + "/" + this.gcode.length + ", sendLength: " + sendLength); - + var firstOne = (sendIndex == 0)? true : false; var start = firstOne; // start printing right away - + var completed = false; if (this.gcode.length < (sendIndex + sendLength)) { console.log(" sending less than max sendLength (and last)"); @@ -147,7 +154,7 @@ function Printer() { completed = true; } var gcodePart = this.gcode.slice(sendIndex, sendIndex+sendLength); - + var postData = { gcode: gcodePart.join("\n"), first: firstOne, start: start}; var self = this; if (communicateWithWifibox) { @@ -159,7 +166,7 @@ function Printer() { timeout: this.sendPrintPartTimeoutTime, success: function(data){ console.log("Printer:sendPrintPart response: ",data); - + if(data.status == "success") { if (completed) { console.log("Printer:sendPrintPart:gcode sending completed"); @@ -170,8 +177,8 @@ function Printer() { //self.targetTemperature = settings["printer.temperature"]; // slight hack } else { // only if the state hasn't bin changed (by for example pressing stop) we send more gcode - - console.log("Printer:sendPrintPart:gcode part received (state: ",self.state,")"); + + console.log("Printer:sendPrintPart:gcode part received (state: ",self.state,")"); if(self.state == Printer.PRINTING_STATE || self.state == Printer.BUFFERING_STATE) { console.log("Printer:sendPrintPart:sending next part"); self.sendPrintPart(sendIndex + sendLength, sendLength); @@ -179,22 +186,22 @@ function Printer() { } } // after we know the first gcode packed has bin received or failed - // (and the driver had time to update the printer.state) + // (and the driver had time to update the printer.state) // we start checking the status again if(sendIndex == 0) { self.startStatusCheckInterval(); } } - }).fail(function() { + }).fail(function() { console.log("Printer:sendPrintPart: failed"); clearTimeout(self.retrySendPrintPartDelay); self.retrySendPrintPartDelay = setTimeout(function() { console.log("request printer:sendPrintPart failed retry"); - self.sendPrintPart(sendIndex, sendLength) + self.sendPrintPart(sendIndex, sendLength) },self.retryDelay); // retry after delay - + // after we know the gcode packed has bin received or failed - // (and the driver had time to update the printer.state) + // (and the driver had time to update the printer.state) // we start checking the status again self.startStatusCheckInterval(); }); @@ -202,7 +209,7 @@ function Printer() { console.log ("Printer >> f:sendPrintPart() >> communicateWithWifibox is false, so not executing this function"); } } - + this.stop = function() { console.log("Printer:stop"); var self = this; @@ -214,19 +221,19 @@ function Printer() { timeout: this.timeoutTime, success: function(data){ console.log("Printer:stop response: ", data); - + // after we know the stop has bin received or failed - // (and the driver had time to update the printer.state) + // (and the driver had time to update the printer.state) // we start checking the status again self.startStatusCheckInterval(); } - }).fail(function() { + }).fail(function() { console.log("Printer:stop: failed"); clearTimeout(self.retryStopDelay); self.retryStopDelay = setTimeout(function() { self.stop() },self.retryDelay); // retry after delay - + // after we know the stop has bin received or failed - // (and the driver had time to update the printer.state) + // (and the driver had time to update the printer.state) // we start checking the status again self.startStatusCheckInterval(); }); @@ -258,9 +265,9 @@ function Printer() { timeout: this.timeoutTime, success: function(response){ //console.log(" Printer:status: ",response.data.state); //," response: ",response); - + self.handleStatusUpdate(response); - + clearTimeout(self.checkStatusDelay); clearTimeout(self.retryCheckStatusDelay); self.checkStatusDelay = setTimeout(function() { self.checkStatus() }, self.checkStatusInterval); @@ -289,11 +296,11 @@ function Printer() { self.state = data.state; //console.log(" state > ",self.state); } - + // temperature self.temperature = data.hotend; self.targetTemperature = data.hotend_target; - + // progress self.currentLine = data.current_line; self.totalLines = data.total_lines; @@ -301,7 +308,7 @@ function Printer() { // access self.hasControl = data.has_control; - + if(self.state == Printer.PRINTING_STATE || self.state == Printer.STOPPING_STATE) { console.log("progress: ",self.currentLine+"/"+self.totalLines+" ("+self.bufferedLines+") ("+self.state+")"); } @@ -311,20 +318,21 @@ function Printer() { this.overruleState = function(newState) { this.stateOverruled = true; console.log(" stateOverruled: ",this.stateOverruled); - + self.state = newState; - + $(document).trigger(Printer.UPDATE); - + this.stopStatusCheckInterval(); } - + this.removeLeaveWarning = function() { window.onbeforeunload = null; } this.addLeaveWarning = function() { window.onbeforeunload = function() { + console.log("WARNING:"+Printer.ON_BEFORE_UNLOAD_MESSAGE); return Printer.ON_BEFORE_UNLOAD_MESSAGE; }; } -} +} \ No newline at end of file diff --git a/js_src/Progressbar.js b/js_src/Progressbar.js index a148ea8..0a91a3e 100644 --- a/js_src/Progressbar.js +++ b/js_src/Progressbar.js @@ -12,6 +12,9 @@ function Progressbar() { this.quartPI = .5 * Math.PI; this.twoPI = 2 * Math.PI; + // To make the progressbar start with a minimal amount of 'progress' + // so that you can visually see that there is progress + this.progressPadding = Math.PI * .1; this.$canvas; this.canvas; @@ -73,7 +76,7 @@ function Progressbar() { this.context.beginPath(); this.context.moveTo(45, 45); this.context.lineTo(45, 0); - this.context.arc(45, 45, 45, -this.quartPI, -this.quartPI + (progress * (this.twoPI)), false); // circle bottom of thermometer + this.context.arc(45, 45, 45, -this.quartPI, -this.quartPI + this.progressPadding + (progress * (this.twoPI - this.progressPadding)), false); // circle bottom of thermometer this.context.lineTo(45, 45); this.context.clip(); diff --git a/js_src/SettingsWindow.js b/js_src/SettingsWindow.js index 9c56c0c..9170b8a 100644 --- a/js_src/SettingsWindow.js +++ b/js_src/SettingsWindow.js @@ -250,16 +250,13 @@ function SettingsWindow() { } this.displayValidationError = function(key,msg) { var formElement = self.form.find("[name|='"+key+"']"); - console.log("formElement: ",formElement); formElement.addClass("error"); var errorMsg = "
"+msg+"
" formElement.after(errorMsg); } this.clearValidationErrors = function() { - var formElements = self.form.find(".error"); - formElements.each( function(index,element) { - $(element).removeClass("error"); - }); + self.form.find(".errorMsg").remove(); + self.form.find(".error").removeClass("error"); } this.readForm = function() { diff --git a/js_src/buttonbehaviors.js b/js_src/buttonbehaviors.js index 7ce03c4..25cd55e 100644 --- a/js_src/buttonbehaviors.js +++ b/js_src/buttonbehaviors.js @@ -170,7 +170,7 @@ function initButtonBehavior() { btnInfo.mouseup(function(e) { e.preventDefault(); console.log("btnInfo mouse up"); - helpTours.startTour(helpTours.WELCOMETOUR); + if (!clientInfo.isSmartphone) helpTours.startTour(helpTours.WELCOMETOUR); }); // DEBUG diff --git a/js_src/gcodeGenerating.js b/js_src/gcodeGenerating.js index 8cd3a4c..d75bc23 100644 --- a/js_src/gcodeGenerating.js +++ b/js_src/gcodeGenerating.js @@ -25,7 +25,7 @@ gcodeEnd.push("G90"); // absolute positioning gcodeEnd.push("M117 Done "); // display message (20 characters to clear whole screen)*/ -var MAX_POINTS_TO_PRINT = 400000; //80000; //40000; +var MAX_POINTS_TO_PRINT = 200000; //400000; //80000; //40000; var gcode = []; function generate_gcode() { @@ -139,9 +139,11 @@ function generate_gcode() { //console.log(" pointsToPrint: ",pointsToPrint); //console.log(" MAX_POINTS_TO_PRINT: ",MAX_POINTS_TO_PRINT); + console.log("pointsToPrint: ",pointsToPrint); + if(pointsToPrint > MAX_POINTS_TO_PRINT) { - alert("Sorry, your doodle to to complex and / or to high"); - console.log("WARNING: to many points to convert to gcode"); + alert("Sorry, your doodle too complex and / or to high"); + console.log("ERROR: to many points too convert to gcode"); return []; } diff --git a/js_src/main.js b/js_src/main.js index adc2a89..0eb87d4 100644 --- a/js_src/main.js +++ b/js_src/main.js @@ -20,10 +20,11 @@ var $drawAreaContainer, $doodleCanvas, doodleCanvas, doodleCanvasContext, $previ var showhideInterval; var showOrHide = false; +var clientInfo = {}; + $(function() { console.log("ready"); - //TODO give this a more logical place in code if (getURLParameter("d") != "null") debugMode = (getURLParameter("d") == "1"); @@ -49,13 +50,17 @@ $(function() { console.log("wifiboxIsRemote: " + wifiboxIsRemote); console.log("wifibox URL: " + wifiboxURL); + // rudimentary client info + clientInfo.isMobileDevice = isMobileDevice(); + clientInfo.isSmartphone = isSmartphone(); + initDoodleDrawing(); initPreviewRendering(); initLayouting(); initSidebars(); initButtonBehavior(); initVerticalShapes(); - initHelp(); + if (!clientInfo.isSmartphone) initHelp(); thermometer.init($("#thermometerCanvas"), $("#thermometerContainer")); progressbar.init($("#progressbarCanvas"), $("#progressbarCanvasContainer")); diff --git a/js_src/utils.js b/js_src/utils.js index 5ab9f65..3a88529 100644 --- a/js_src/utils.js +++ b/js_src/utils.js @@ -5,3 +5,24 @@ function getURLParameter(name) { (new RegExp('[&?]'+name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1] ); } + +// returns true for all smartphones and tablets +function isMobileDevice() { + return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Windows Mobile/i.test(navigator.userAgent); +} + +// returns true for smartphones (Android will be a bit dodgy (tablet or phone, all depends on pixels vs devicePixelRatio...) +function isSmartphone() { + var returnBool = false; + if( /Android/i.test(navigator.userAgent) && window.devicePixelRatio > 1) { + var w = $(window).width() / window.devicePixelRatio; + console.log("Android device >> ratio'd width: " + w); + if (w < 480) { + returnBool = true; + } + } else { + returnBool = /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini|Windows Mobile/i.test(navigator.userAgent) + } + + return returnBool; +} diff --git a/less/help_joyride-2.1.less b/less/help_joyride-2.1.less index 2ec4430..cfa7f99 100644 --- a/less/help_joyride-2.1.less +++ b/less/help_joyride-2.1.less @@ -1,11 +1,8 @@ -/* Artfully masterminded by ZURB */ -body { - /*position: relative;*/ -} - -//#joyRideTipContent { display: none; } -// -//.joyRideTipContent { display: none; } +//@helpBlue: #2470E2; +@darkBlue: #013; +@helpBlue: #1B76FF; +@helpFullBlue: rgb(0,85,214); +@helpDarkBlue: darken(desaturate(@helpBlue, 25%), 35%); /* Default styles for the container */ .joyride-tip-guide { @@ -13,7 +10,8 @@ body { // background: #000; background: rgba(255, 255, 255, 0.92); display: none; - color: #222; + color: @darkBlue; +// color: rgb(0,99,255); width: 300px; z-index: 101; top: 0; /* keeps the page from scrolling when calculating position */ @@ -21,7 +19,9 @@ body { // font-family: "HelveticaNeue", "Helvetica Neue", "Helvetica", Helvetica, Arial, Lucida, sans-serif; font-weight: normal; border-radius: 10px; - border: 3px solid #5FCE4F; +// border: 3px solid #5FCE4F; +// border: 3px solid #374952; + border: 3px solid @helpFullBlue; box-shadow: 0 0 15px rgba(0, 0, 0, 0.4); } @@ -64,7 +64,8 @@ body { and override the top,left,right colors below. */ // border-color: #000; - border-color: rgba(67, 216, 20, 1.0); +// border-color: rgba(67, 216, 20, 1.0) !important; + border-color: @helpFullBlue !important; // border-color: rgba(0,0,0,0.8); border-top-color: transparent !important; border-left-color: transparent !important; @@ -83,7 +84,8 @@ body { and override the bottom,left,right colors below. */ // border-color: #000; - border-color: rgba(67, 216, 20, 1.0) !important; +// border-color: rgba(67, 216, 20, 1.0) !important; + border-color: @helpFullBlue !important; // border-color: rgba(0,0,0,0.8) !important; border-bottom-color: transparent !important; border-left-color: transparent !important; @@ -95,7 +97,8 @@ body { .joyride-tip-guide span.joyride-nub.right { // border-color: #000; - border-color: rgba(67, 216, 20, 1.0) !important; +// border-color: rgba(67, 216, 20, 1.0) !important; + border-color: @helpFullBlue !important; // border-color: rgba(0,0,0,0.8) !important; border-top-color: transparent !important; border-right-color: transparent !important; @@ -109,7 +112,8 @@ body { .joyride-tip-guide span.joyride-nub.left { // border-color: #000; - border-color: rgba(67, 216, 20, 1.0) !important; +// border-color: rgba(67, 216, 20, 1.0) !important; + border-color: @helpFullBlue !important; // border-color: rgba(0,0,0,0.8) !important; border-top-color: transparent !important; border-left-color: transparent !important; @@ -122,8 +126,8 @@ body { } .joyride-tip-guide span.joyride-nub.top-right { - border-color: #000; - border-color: rgba(0,0,0,0.8); +// border-color: #000; + border-color: @helpFullBlue; border-top-color: transparent !important; border-left-color: transparent !important; border-right-color: transparent !important; @@ -143,7 +147,8 @@ body { line-height: 1.25; margin: 0; font-weight: bold; - color: #2DDF34; +// color: #2DDF34; + color: @helpFullBlue; // color: #fff; } } @@ -160,12 +165,15 @@ body { line-height: 18px; } .joyride-tip-guide a { - color: rgb(255,255,255); +// color: rgb(255,255,255); + color: @helpFullBlue; text-decoration: none; - border-bottom: dotted 1px rgba(255,255,255,0.6); +// border-bottom: dotted 1px rgba(255,255,255,0.6); + border-bottom: dotted 1px lighten(@helpFullBlue, 20%); } .joyride-tip-guide a:hover { - color: rgba(255,255,255,0.8); +// color: rgba(255,255,255,0.8); + color: lighten(@helpFullBlue, 20%); border-bottom: none; } diff --git a/www/helpcontent.html b/www/helpcontent.html index 950cec9..a9d75cb 100644 --- a/www/helpcontent.html +++ b/www/helpcontent.html @@ -16,30 +16,58 @@You can control all the details for you tour stop. Any valid HTML will work inside of Joyride.
+Get the details right by styling Joyride with a custom stylesheet!
+Get the details right by styling Joyride with a custom stylesheet!
It works as a modal too!
-It works right aligned.
It works as a modal too!
+It works with classes, and only on the first visible element with that class.
It works with classes, and only on the first visible element with that class.
It works with classes, and only on the first visible element with that class.
It works with classes, and only on the first visible element with that class.
+It works with classes, and only on the first visible element with that class.
+Status messages can inform you about the connection between Doodle3D and your 3D printer
+Status messages can inform you about the connection between Doodle3D and your 3D printer
+You're now ready to start using Doodle3d!
+You can always find this tour in the info window.
+