Track browser tab visibility, only activate webcam/gcode viewer when visible
This might help with #1065 if indeed is related to background tab suspending behaviours in
browsers, but is a completely blind guess at this point since I still have not been able to
reproduce that issue myself.
Backported.
(cherry picked from commit 720cdad)
This commit is contained in:
parent
454f16a7c3
commit
acc85127c5
5 changed files with 165 additions and 31 deletions
|
|
@ -379,7 +379,7 @@ GCODE.renderer = (function(){
|
|||
};
|
||||
|
||||
var drawLayer = function(layerNum, fromProgress, toProgress, isNotCurrentLayer){
|
||||
console.log("Drawing layer " + layerNum + " from " + fromProgress + " to " + toProgress + " (current: " + !isNotCurrentLayer + ")");
|
||||
log.trace("Drawing layer " + layerNum + " from " + fromProgress + " to " + toProgress + " (current: " + !isNotCurrentLayer + ")");
|
||||
|
||||
var i;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,72 @@ $(function() {
|
|||
|
||||
log.setLevel(CONFIG_DEBUG ? "debug" : "info");
|
||||
|
||||
//~~ setup browser and internal tab tracking (in 1.3.0 that will be
|
||||
// much nicer with the global OctoPrint object...)
|
||||
|
||||
var tabTracking = (function() {
|
||||
var exports = {
|
||||
browserTabVisibility: undefined,
|
||||
selectedTab: undefined
|
||||
};
|
||||
|
||||
var browserVisibilityCallbacks = [];
|
||||
|
||||
var getHiddenProp = function() {
|
||||
var prefixes = ["webkit", "moz", "ms", "o"];
|
||||
|
||||
// if "hidden" is natively supported just return it
|
||||
if ("hidden" in document) {
|
||||
return "hidden"
|
||||
}
|
||||
|
||||
// otherwise loop over all the known prefixes until we find one
|
||||
var vendorPrefix = _.find(prefixes, function(prefix) {
|
||||
return (prefix + "Hidden" in document);
|
||||
});
|
||||
if (vendorPrefix !== undefined) {
|
||||
return vendorPrefix + "Hidden";
|
||||
}
|
||||
|
||||
// nothing found
|
||||
return undefined;
|
||||
};
|
||||
|
||||
var isHidden = function() {
|
||||
var prop = getHiddenProp();
|
||||
if (!prop) return false;
|
||||
|
||||
return document[prop];
|
||||
};
|
||||
|
||||
var updateBrowserVisibility = function() {
|
||||
var visible = !isHidden();
|
||||
exports.browserTabVisible = visible;
|
||||
_.each(browserVisibilityCallbacks, function(callback) {
|
||||
callback(visible);
|
||||
})
|
||||
};
|
||||
|
||||
// register for browser visibility tracking
|
||||
|
||||
var prop = getHiddenProp();
|
||||
if (!prop) return undefined;
|
||||
|
||||
var eventName = prop.replace(/[H|h]idden/, "") + "visibilitychange";
|
||||
document.addEventListener(eventName, updateBrowserVisibility);
|
||||
|
||||
updateBrowserVisibility();
|
||||
|
||||
// exports
|
||||
|
||||
exports.isVisible = function() { return !isHidden() };
|
||||
exports.onBrowserVisibilityChange = function(callback) {
|
||||
browserVisibilityCallbacks.push(callback);
|
||||
};
|
||||
|
||||
return exports;
|
||||
})();
|
||||
|
||||
//~~ AJAX setup
|
||||
|
||||
// work around a stupid iOS6 bug where ajax requests get cached and only work once, as described at
|
||||
|
|
@ -67,6 +133,18 @@ $(function() {
|
|||
// the view model map is our basic look up table for dependencies that may be injected into other view models
|
||||
var viewModelMap = {};
|
||||
|
||||
// We put our tabTracking into the viewModelMap as a workaround until
|
||||
// our global OctoPrint object becomes available in 1.3.0. This way
|
||||
// we'll still be able to access it in our view models.
|
||||
//
|
||||
// NOTE TO DEVELOPERS: Do NOT depend on this dependency in your custom
|
||||
// view models. It is ONLY provided for the core application to be able
|
||||
// to backport a fix from the 1.3.0 development branch and WILL BE
|
||||
// REMOVED once 1.3.0 gets released without any fallback!
|
||||
//
|
||||
// TODO: Remove with release of 1.3.0
|
||||
viewModelMap.tabTracking = tabTracking;
|
||||
|
||||
// Fix Function#name on browsers that do not support it (IE):
|
||||
// see: http://stackoverflow.com/questions/6903762/function-name-not-supported-in-ie
|
||||
if (!(function f() {}).name) {
|
||||
|
|
@ -371,16 +449,22 @@ $(function() {
|
|||
$('.nav-pills, .nav-tabs').tabdrop();
|
||||
|
||||
// Allow components to react to tab change
|
||||
var tabs = $('#tabs a[data-toggle="tab"]');
|
||||
tabs.on('show', function (e) {
|
||||
var current = e.target.hash;
|
||||
var previous = e.relatedTarget.hash;
|
||||
var onTabChange = function(current, previous) {
|
||||
log.debug("Selected OctoPrint tab changed: previous = " + previous + ", current = " + current);
|
||||
tabTracking.selectedTab = current;
|
||||
|
||||
_.each(allViewModels, function(viewModel) {
|
||||
if (viewModel.hasOwnProperty("onTabChange")) {
|
||||
viewModel.onTabChange(current, previous);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var tabs = $('#tabs a[data-toggle="tab"]');
|
||||
tabs.on('show', function (e) {
|
||||
var current = e.target.hash;
|
||||
var previous = e.relatedTarget.hash;
|
||||
onTabChange(current, previous);
|
||||
});
|
||||
|
||||
tabs.on('shown', function (e) {
|
||||
|
|
@ -394,6 +478,8 @@ $(function() {
|
|||
});
|
||||
});
|
||||
|
||||
onTabChange(OCTOPRINT_INITIAL_TAB);
|
||||
|
||||
// Fix input element click problems on dropdowns
|
||||
$(".dropdown input, .dropdown label").click(function(e) {
|
||||
e.stopPropagation();
|
||||
|
|
@ -485,11 +571,22 @@ $(function() {
|
|||
});
|
||||
log.info("... binding done");
|
||||
|
||||
// startup complete
|
||||
_.each(allViewModels, function(viewModel) {
|
||||
if (viewModel.hasOwnProperty("onStartupComplete")) {
|
||||
viewModel.onStartupComplete();
|
||||
}
|
||||
});
|
||||
|
||||
// make sure we can track the browser tab visibility
|
||||
tabTracking.onBrowserVisibilityChange(function(status) {
|
||||
log.debug("Browser tab is now " + (status ? "visible" : "hidden"));
|
||||
_.each(allViewModels, function(viewModel) {
|
||||
if (viewModel.hasOwnProperty("onBrowserTabVisibilityChange")) {
|
||||
viewModel.onBrowserTabVisibilityChange(status);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (!_.has(viewModelMap, "settingsViewModel")) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ $(function() {
|
|||
self.loginState = parameters[0];
|
||||
self.settings = parameters[1];
|
||||
|
||||
// TODO remove with release of 1.3.0 and switch to OctoPrint.coreui usage
|
||||
self.tabTracking = parameters[2];
|
||||
|
||||
self._createToolEntry = function () {
|
||||
return {
|
||||
name: ko.observable(),
|
||||
|
|
@ -415,31 +418,51 @@ $(function() {
|
|||
|
||||
self.onSettingsBeforeSave = self.updateRotatorWidth;
|
||||
|
||||
self._disableWebcam = function() {
|
||||
// only disable webcam stream if tab is out of focus for more than 5s, otherwise we might cause
|
||||
// more load by the constant connection creation than by the actual webcam stream
|
||||
self.webcamDisableTimeout = setTimeout(function () {
|
||||
$("#webcam_image").attr("src", "");
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
self._enableWebcam = function() {
|
||||
if (self.tabTracking.selectedTab != "#control" || !self.tabTracking.browserTabVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.webcamDisableTimeout != undefined) {
|
||||
clearTimeout(self.webcamDisableTimeout);
|
||||
}
|
||||
var webcamImage = $("#webcam_image");
|
||||
var currentSrc = webcamImage.attr("src");
|
||||
if (currentSrc === undefined || currentSrc.trim() == "") {
|
||||
var newSrc = CONFIG_WEBCAM_STREAM;
|
||||
if (CONFIG_WEBCAM_STREAM.lastIndexOf("?") > -1) {
|
||||
newSrc += "&";
|
||||
} else {
|
||||
newSrc += "?";
|
||||
}
|
||||
newSrc += new Date().getTime();
|
||||
|
||||
self.updateRotatorWidth();
|
||||
webcamImage.attr("src", newSrc);
|
||||
}
|
||||
};
|
||||
|
||||
self.onTabChange = function (current, previous) {
|
||||
if (current == "#control") {
|
||||
if (self.webcamDisableTimeout != undefined) {
|
||||
clearTimeout(self.webcamDisableTimeout);
|
||||
}
|
||||
var webcamImage = $("#webcam_image");
|
||||
var currentSrc = webcamImage.attr("src");
|
||||
if (currentSrc === undefined || currentSrc.trim() == "") {
|
||||
var newSrc = CONFIG_WEBCAM_STREAM;
|
||||
if (CONFIG_WEBCAM_STREAM.lastIndexOf("?") > -1) {
|
||||
newSrc += "&";
|
||||
} else {
|
||||
newSrc += "?";
|
||||
}
|
||||
newSrc += new Date().getTime();
|
||||
|
||||
self.updateRotatorWidth();
|
||||
webcamImage.attr("src", newSrc);
|
||||
}
|
||||
self._enableWebcam();
|
||||
} else if (previous == "#control") {
|
||||
// only disable webcam stream if tab is out of focus for more than 5s, otherwise we might cause
|
||||
// more load by the constant connection creation than by the actual webcam stream
|
||||
self.webcamDisableTimeout = setTimeout(function () {
|
||||
$("#webcam_image").attr("src", "");
|
||||
}, 5000);
|
||||
self._disableWebcam();
|
||||
}
|
||||
};
|
||||
|
||||
self.onBrowserTabVisibilityChange = function(status) {
|
||||
if (status) {
|
||||
self._enableWebcam();
|
||||
} else {
|
||||
self._disableWebcam();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -565,7 +588,7 @@ $(function() {
|
|||
|
||||
OCTOPRINT_VIEWMODELS.push([
|
||||
ControlViewModel,
|
||||
["loginStateViewModel", "settingsViewModel"],
|
||||
["loginStateViewModel", "settingsViewModel", "tabTracking"],
|
||||
"#control"
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ $(function() {
|
|||
self.loginState = parameters[0];
|
||||
self.settings = parameters[1];
|
||||
|
||||
// TODO remove with release of 1.3.0 and switch to OctoPrint.coreui usage
|
||||
self.tabTracking = parameters[2];
|
||||
|
||||
self.ui_progress_percentage = ko.observable();
|
||||
self.ui_progress_type = ko.observable();
|
||||
self.ui_progress_text = ko.computed(function() {
|
||||
|
|
@ -358,7 +361,7 @@ $(function() {
|
|||
if(self.loadedFilename
|
||||
&& self.loadedFilename == data.job.file.name
|
||||
&& self.loadedFileDate == data.job.file.date) {
|
||||
if (self.currentlyPrinting && self.renderer_syncProgress() && !self.waitForApproval()) {
|
||||
if (self.tabTracking.browserTabVisible && self.tabActive && self.currentlyPrinting && self.renderer_syncProgress() && !self.waitForApproval()) {
|
||||
var cmdIndex = GCODE.gCodeReader.getCmdIndexForPercentage(data.progress.completion);
|
||||
if(cmdIndex){
|
||||
GCODE.renderer.render(cmdIndex.layer, 0, cmdIndex.cmd);
|
||||
|
|
@ -504,13 +507,16 @@ $(function() {
|
|||
|
||||
self.onBeforeBinding = function() {
|
||||
self.initialize();
|
||||
}
|
||||
};
|
||||
|
||||
self.onTabChange = function(current, previous) {
|
||||
self.tabActive = current == "#gcode";
|
||||
};
|
||||
}
|
||||
|
||||
OCTOPRINT_VIEWMODELS.push([
|
||||
GcodeViewModel,
|
||||
["loginStateViewModel", "settingsViewModel"],
|
||||
["loginStateViewModel", "settingsViewModel", "tabTracking"],
|
||||
"#gcode"
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,4 +33,12 @@
|
|||
var OCTOPRINT_VIEWMODELS = [];
|
||||
var ADDITIONAL_VIEWMODELS = [];
|
||||
var OCTOPRINT_ADDITIONAL_BINDINGS = [];
|
||||
|
||||
{% if templates.tab.order %}
|
||||
{% set first_tab = templates.tab.order[0] %}
|
||||
{% set entry, data = templates.tab.entries[first_tab] %}
|
||||
var OCTOPRINT_INITIAL_TAB = "#{{ data._div }}";
|
||||
{% else %}
|
||||
var OCTOPRINT_INITIAL_TAB = undefined;
|
||||
{% endif %}
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in a new issue