var basePath = null;
var signatureRegExp = new RegExp('[^a-zA-Z0-9/?_.=&{}\\[\\]":, _-]', 'g');
var initialConfigFetched = false; /* used to workaround browser extensions that trigger stupid change events */
+var pageContainer = null;
- /* utils */
+ /* Object utilities */
+
+Object.keys = Object.keys || (function () {
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
+ var hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString');
+ var dontEnums = [
+ 'toString',
+ 'toLocaleString',
+ 'valueOf',
+ 'hasOwnProperty',
+ 'isPrototypeOf',
+ 'propertyIsEnumerable',
+ 'constructor'
+ ];
+ var dontEnumsLength = dontEnums.length;
+
+ return function (obj) {
+ if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) {
+ return [];
+ }
+
+ var result = [];
+ for (var prop in obj) {
+ if (hasOwnProperty.call(obj, prop)) {
+ result.push(prop);
+ }
+ }
+
+ if (hasDontEnumBug) {
+ for (var i = 0; i < dontEnumsLength; i++) {
+ if (hasOwnProperty.call(obj, dontEnums[i])) {
+ result.push(dontEnums[i]);
+ }
+ }
+ }
+
+ return result;
+ };
+})();
+
+Object.update = function (dest, source) {
+ for (var key in source) {
+ if (!source.hasOwnProperty(key)) {
+ continue;
+ }
+
+ dest[key] = source[key];
+ }
+};
+
+
+ /* Array utilities */
+
+Array.prototype.indexOf = Array.prototype.indexOf || function (obj) {
+ for (var i = 0; i < this.length; i++) {
+ if (this[i] === obj) {
+ return i;
+ }
+ }
+
+ return -1;
+};
+
+Array.prototype.forEach = Array.prototype.forEach || function (callback, thisArg) {
+ for (var i = 0; i < this.length; i++) {
+ callback.call(thisArg, this[i], i, this);
+ }
+};
+
+Array.prototype.every = Array.prototype.every || function (callback, thisArg) {
+ for (var i = 0; i < this.length; i++) {
+ if (!callback.call(thisArg, this[i], i, this)) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+Array.prototype.some = Array.prototype.some || function (callback, thisArg) {
+ for (var i = 0; i < this.length; i++) {
+ if (callback.call(thisArg, this[i], i, this)) {
+ return true;
+ }
+ }
+
+ return false;
+};
+
+Array.prototype.unique = function (callback, thisArg) {
+ var uniqueElements = [];
+ this.forEach(function (element) {
+ if (uniqueElements.indexOf(element, Utils.equals) === -1) {
+ uniqueElements.push(element);
+ }
+ });
+
+ return uniqueElements;
+};
+
+Array.prototype.filter = function (func, thisArg) {
+ var filtered = [];
+ for (var i = 0; i < this.length; i++) {
+ if (func.call(thisArg, this[i], i, this)) {
+ filtered.push(this[i]);
+ }
+ }
+
+ return filtered;
+};
+
+Array.prototype.map = function (func, thisArg) {
+ var mapped = [];
+ for (var i = 0; i < this.length; i++) {
+ mapped.push(func.call(thisArg, this[i], i, this));
+ }
+
+ return mapped;
+};
+
+Array.prototype.sortKey = function (keyFunc, reverse) {
+ this.sort(function (e1, e2) {
+ var k1 = keyFunc(e1);
+ var k2 = keyFunc(e2);
+
+ if ((k1 < k2 && !reverse) || (k1 > k2 && reverse)) {
+ return -1;
+ }
+ else if ((k1 > k2 && !reverse) || (k1 < k2 && reverse)) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+ });
+};
+
+
+ /* String utilities */
+
+String.prototype.startsWith = String.prototype.startsWith || function (str) {
+ return (this.substr(0, str.length) === str);
+};
+
+String.prototype.endsWith = String.prototype.endsWith || function (str) {
+ return (this.substr(this.length - str.length) === str);
+};
+
+String.prototype.trim = String.prototype.trim || function () {
+ return this.replace(new RegExp('^\\s*'), '').replace(new RegExp('\\s*$'), '');
+};
+
+String.prototype.replaceAll = String.prototype.replaceAll || function (oldStr, newStr) {
+ var p, s = this;
+ while ((p = s.indexOf(oldStr)) >= 0) {
+ s = s.substring(0, p) + newStr + s.substring(p + oldStr.length, s.length);
+ }
+
+ return s.toString();
+};
+
+String.prototype.format = function () {
+ var text = this;
+
+ var rex = new RegExp('%[sdf]');
+ var match, i = 0;
+ while (match = text.match(rex)) {
+ text = text.substring(0, match.index) + arguments[i] + text.substring(match.index + 2);
+ i++;
+ }
+
+ if (i) { /* %s format used */
+ return text;
+ }
+
+ var keywords = arguments[0];
+
+ for (var key in keywords) {
+ text = text.replace('%(' + key + ')s', "" + keywords[key]);
+ text = text.replace('%(' + key + ')d', "" + keywords[key]);
+ text = text.replace('%(' + key + ')f', "" + keywords[key]);
+ }
+
+ return text;
+};
+
+
+ /* misc utilities */
var sha1 = (function () {
- function hash(msg) {
- var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
+ var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
+ var P = Math.pow(2, 32);
+ function hash(msg) {
msg += String.fromCharCode(0x80);
var l = msg.length / 4 + 2;
(msg.charCodeAt(i * 64 + j * 4 + 2) << 8) | (msg.charCodeAt(i * 64 + j * 4 + 3));
}
}
- M[N-1][14] = ((msg.length-1) * 8) / Math.pow(2, 32);
- M[N-1][14] = Math.floor(M[N-1][14]);
- M[N-1][15] = ((msg.length-1) * 8) & 0xffffffff;
+ M[N - 1][14] = Math.floor(((msg.length - 1) * 8) / P);
+ M[N - 1][15] = ((msg.length - 1) * 8) & 0xffffffff;
var H0 = 0x67452301;
var H1 = 0xefcdab89;
var W = new Array(80);
var a, b, c, d, e;
- for (var i = 0; i < N; i++) {
+ for (i = 0; i < N; i++) {
for (var t = 0; t < 16; t++) W[t] = M[i][t];
- for (var t = 16; t < 80; t++) W[t] = ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
+ for (t = 16; t < 80; t++) W[t] = ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
a = H0; b = H1; c = H2; d = H3; e = H4;
url += '_username=' + window.username;
if (window._loginDialogSubmitted) {
url += '&_login=true';
- delete _loginDialogSubmitted;
+ _loginDialogSubmitted = false;
}
var signature = computeSignature(method, url, body);
url += '&_signature=' + signature;
}
function getCookie(name) {
- if (document.cookie.length <= 0) {
+ var cookie = document.cookie.substring();
+
+ if (cookie.length <= 0) {
return null;
}
- var start = document.cookie.indexOf(name + '=');
+ var start = cookie.indexOf(name + '=');
if (start == -1) {
return null;
}
var start = start + name.length + 1;
- var end = document.cookie.indexOf(';', start);
+ var end = cookie.indexOf(';', start);
if (end == -1) {
- end = document.cookie.length;
+ end = cookie.length;
}
- return unescape(document.cookie.substring(start, end));
+ return cookie.substring(start, end);
}
function setCookie(name, value, days) {
window.location.reload(true);
}
-
- /* Object utilities */
-
-Object.keys = Object.keys || (function () {
- var hasOwnProperty = Object.prototype.hasOwnProperty;
- var hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString');
- var dontEnums = [
- 'toString',
- 'toLocaleString',
- 'valueOf',
- 'hasOwnProperty',
- 'isPrototypeOf',
- 'propertyIsEnumerable',
- 'constructor'
- ];
- var dontEnumsLength = dontEnums.length;
-
- return function (obj) {
- if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) {
- return [];
- }
-
- var result = [];
- for (var prop in obj) {
- if (hasOwnProperty.call(obj, prop)) {
- result.push(prop);
- }
- }
-
- if (hasDontEnumBug) {
- for (var i = 0; i < dontEnumsLength; i++) {
- if (hasOwnProperty.call(obj, dontEnums[i])) {
- result.push(dontEnums[i]);
- }
- }
- }
-
- return result;
- };
-})();
-
-Object.update = function (dest, source) {
- for (var key in source) {
- if (!source.hasOwnProperty(key)) {
- continue;
- }
-
- dest[key] = source[key];
- }
-};
-
-
- /* Array utilities */
-
-Array.prototype.indexOf = Array.prototype.indexOf || function (obj) {
- for (var i = 0; i < this.length; i++) {
- if (this[i] === obj) {
- return i;
- }
- }
-
- return -1;
-};
-
-Array.prototype.forEach = Array.prototype.forEach || function (callback, thisArg) {
- for (var i = 0; i < this.length; i++) {
- callback.call(thisArg, this[i], i, this);
- }
-};
-
-Array.prototype.every = Array.prototype.every || function (callback, thisArg) {
- for (var i = 0; i < this.length; i++) {
- if (!callback.call(thisArg, this[i], i, this)) {
- return false;
- }
- }
-
- return true;
-};
-
-Array.prototype.some = Array.prototype.some || function (callback, thisArg) {
- for (var i = 0; i < this.length; i++) {
- if (callback.call(thisArg, this[i], i, this)) {
- return true;
- }
- }
-
- return false;
-};
-
-Array.prototype.unique = function (callback, thisArg) {
- var uniqueElements = [];
- this.forEach(function (element) {
- if (uniqueElements.indexOf(element, Utils.equals) === -1) {
- uniqueElements.push(element);
- }
- });
-
- return uniqueElements;
-};
-
-Array.prototype.filter = function (func, thisArg) {
- var filtered = [];
- for (var i = 0; i < this.length; i++) {
- if (func.call(thisArg, this[i], i, this)) {
- filtered.push(this[i]);
- }
- }
-
- return filtered;
-};
-
-Array.prototype.map = function (func, thisArg) {
- var mapped = [];
- for (var i = 0; i < this.length; i++) {
- mapped.push(func.call(thisArg, this[i], i, this));
- }
-
- return mapped;
-};
-
-Array.prototype.sortKey = function (keyFunc, reverse) {
- this.sort(function (e1, e2) {
- var k1 = keyFunc(e1);
- var k2 = keyFunc(e2);
-
- if ((k1 < k2 && !reverse) || (k1 > k2 && reverse)) {
- return -1;
- }
- else if ((k1 > k2 && !reverse) || (k1 < k2 && reverse)) {
- return 1;
- }
- else {
- return 0;
- }
- });
-};
-
-
- /* String utilities */
-
-String.prototype.startsWith = String.prototype.startsWith || function (str) {
- return (this.substr(0, str.length) === str);
-};
-
-String.prototype.endsWith = String.prototype.endsWith || function (str) {
- return (this.substr(this.length - str.length) === str);
-};
-
-String.prototype.trim = String.prototype.trim || function () {
- return this.replace(new RegExp('^\\s*'), '').replace(new RegExp('\\s*$'), '');
-};
-
-String.prototype.replaceAll = String.prototype.replaceAll || function (oldStr, newStr) {
- var p, s = this;
- while ((p = s.indexOf(oldStr)) >= 0) {
- s = s.substring(0, p) + newStr + s.substring(p + oldStr.length, s.length);
- }
-
- return s.toString();
-};
-
-String.prototype.format = function () {
- var text = this;
-
- var rex = new RegExp('%[sdf]');
- var match, i = 0;
- while (match = text.match(rex)) {
- text = text.substring(0, match.index) + arguments[i] + text.substring(match.index + 2);
- i++;
- }
-
- if (i) { /* %s format used */
- return text;
- }
-
- var keywords = arguments[0];
-
- for (var key in keywords) {
- text = text.replace('%(' + key + ')s', "" + keywords[key]);
- text = text.replace('%(' + key + ')d', "" + keywords[key]);
- text = text.replace('%(' + key + ')f', "" + keywords[key]);
- }
-
- return text;
-};
-
-
- /* various */
-
function authorizeUpload() {
var service = $('#uploadServiceSelect').val();
var cameraId = $('#cameraSelect').val();
window.open(url, '_blank');
}
-
- /* UI initialization */
+
+ /* UI */
function initUI() {
/* checkboxes */
});
}
+function getPageContainer() {
+ if (!pageContainer) {
+ pageContainer = $('div.page-container');
+ }
+
+ return pageContainer;
+}
+
+function getCameraFrames() {
+ return getPageContainer().children('div.camera-frame');
+}
+
+function getCameraFrame(cameraId) {
+ var frame = getPageContainer().children('div.camera-frame#camera' + cameraId);
+ if (!frame.length) {
+ /* look for camera frames detached from page container */
+ frame = $('div.camera-frame#camera' + cameraId);
+ }
+
+ return frame;
+}
+
+function getCameraProgresses() {
+ return getCameraFrames().find('div.camera-progress');
+}
+
+function getCameraProgress(cameraId) {
+ return getCameraFrame(cameraId).find('div.camera-progress');
+}
+
/* settings */
}
$('div.settings').addClass('open').removeClass('closed');
- $('div.page-container').addClass('stretched');
+ getPageContainer().addClass('stretched');
$('div.settings-top-bar').addClass('open').removeClass('closed');
updateConfigUI();
pushConfigReboot = false;
$('div.settings').removeClass('open').addClass('closed');
- $('div.page-container').removeClass('stretched');
+ getPageContainer().removeClass('stretched');
$('div.settings-top-bar').removeClass('open').addClass('closed');
}
/* show the camera progress indicators */
if (cameraIds) {
cameraIds.forEach(function (cameraId) {
- $('div.camera-frame#camera' + cameraId + ' div.camera-progress').addClass('visible');
+ getCameraProgress(cameraId).addClass('visible');
});
}
else {
- $('div.camera-progress').addClass('visible');
+ getCameraProgresses().addClass('visible');
}
/* remove the settings progress lock */
$('div.settings-progress').css('opacity', '0');
/* hide the camera progress indicator */
- $('div.camera-progress').removeClass('visible');
+ getCameraProgresses().removeClass('visible');
setTimeout(function () {
$('div.settings-progress').css('width', '0px');
}
/* add a progress indicator */
- $('div.page-container').append('<img class="main-loading-progress" src="' + staticPath + 'img/main-loading-progress.gif">');
+ getPageContainer().append('<img class="main-loading-progress" src="' + staticPath + 'img/main-loading-progress.gif">');
if (isAdmin()) {
/* fetch the main configuration */
/* camera frames */
function addCameraFrameUi(cameraConfig) {
- var pageContainer = $('div.page-container');
-
if (cameraConfig == null) {
var cameraFrameDivPlaceHolder = $('<div class="camera-frame-place-holder"></div>');
- pageContainer.append(cameraFrameDivPlaceHolder);
+ getPageContainer().append(cameraFrameDivPlaceHolder);
return;
}
/* insert the new camera frame at the right position,
* with respect to the camera id */
- var cameraFrames = pageContainer.find('div.camera-frame');
+ var cameraFrames = getPageContainer().find('div.camera-frame');
var cameraIds = cameraFrames.map(function () {return parseInt(this.id.substring(6));});
cameraIds.sort();
}
if (index < cameraIds.length) {
- var beforeCameraFrame = pageContainer.find('div.camera-frame#camera' + cameraIds[index]);
+ var beforeCameraFrame = getPageContainer().find('div.camera-frame#camera' + cameraIds[index]);
cameraFrameDiv.insertAfter(beforeCameraFrame);
}
else {
- pageContainer.append(cameraFrameDiv);
+ getPageContainer().append(cameraFrameDiv);
}
/* fade in */
}(cameraId));
/* error and load handlers */
- cameraImg.error(function () {
+ cameraImg[0].onerror = function () {
this.error = true;
this.loading = 0;
- cameraImg.addClass('error').removeClass('loading');
+ cameraImg.addClass('error').removeClass('initializing');
cameraImg.height(Math.round(cameraImg.width() * 0.75));
cameraPlaceholder.css('opacity', 1);
cameraProgress.removeClass('visible');
cameraFrameDiv.removeClass('motion-detected');
- });
- cameraImg.load(function () {
+ };
+ cameraImg[0].onload = function () {
if (refreshDisabled[cameraId]) {
return; /* refresh temporarily disabled for updating */
}
- this.error = false;
+ if (this.error) {
+ cameraImg.removeClass('error');
+ cameraPlaceholder.css('opacity', 0);
+ cameraImg.css('height', '');
+ this.error = false;
+ }
+
this.loading = 0;
- cameraImg.removeClass('error').removeClass('loading');
- cameraImg.css('height', '');
- cameraPlaceholder.css('opacity', 0);
- cameraProgress.removeClass('visible');
-
+ if (this.initializing) {
+ cameraProgress.removeClass('visible');
+ cameraImg.removeClass('initializing');
+ cameraImg.css('height', '');
+ this.initializing = false;
+ }
+
/* there's no point in looking for a cookie update more often than once every second */
var now = new Date().getTime();
if ((!this.lastCookieTime || now - this.lastCookieTime > 1000) && (cameraFrameDiv[0].config['proto'] != 'mjpeg')) {
/* update the modal dialog position when image is loaded */
updateModalDialogPosition();
}
- });
+ };
- cameraImg.addClass('loading');
+ cameraImg.addClass('initializing');
+ cameraImg[0].initializing = true;
cameraImg.height(Math.round(cameraImg.width() * 0.75));
}
function remCameraFrameUi(cameraId) {
- var pageContainer = $('div.page-container');
- var cameraFrameDiv = pageContainer.find('div.camera-frame#camera' + cameraId);
+ var cameraFrameDiv = getPageContainer().find('div.camera-frame#camera' + cameraId);
cameraFrameDiv.animate({'opacity': 0}, 100, function () {
cameraFrameDiv.remove();
});
}
function recreateCameraFrames(cameras) {
- var pageContainer = $('div.page-container');
-
function updateCameras(cameras) {
cameras = cameras.filter(function (camera) {return camera.enabled;});
var i, camera;
/* remove everything on the page */
- pageContainer.children().remove();
+ getPageContainer().children().remove();
/* add camera frames */
for (i = 0; i < cameras.length; i++) {
/* invite the user to add a camera */
var addCameraLink = $('<div class="add-camera-message">' +
'<a href="javascript:runAddCameraDialog()">You have not configured any camera yet. Click here to add one...</a></div>');
- pageContainer.append(addCameraLink);
+ getPageContainer().append(addCameraLink);
}
}
fullScreenCameraId = -1; /* avoids successive fast toggles of fullscreen */
- var cameraFrameDiv = $('#camera' + cameraId);
+ var cameraFrameDiv = getCameraFrame(cameraId);
var cameraName = cameraFrameDiv.find('span.camera-name').text();
- var frameImg = cameraFrameDiv.find('img.camera');
- var aspectRatio = frameImg.width() / frameImg.height();
+ var cameraImg = cameraFrameDiv.find('img.camera');
+ var aspectRatio = cameraImg.width() / cameraImg.height();
var windowWidth = $(window).width();
var windowHeight = $(window).height();
var windowAspectRatio = windowWidth / windowHeight;
var frameIndex = cameraFrameDiv.index();
- var pageContainer = $('div.page-container');
- if (frameImg.hasClass('error')) {
+ cameraImg.addClass('initializing');
+ cameraImg[0].initializing = true;
+
+ if (cameraImg.hasClass('error')) {
return; /* no full screen for erroneous cameras */
}
onClose: function () {
fullScreenCameraId = null;
cameraFrameDiv.css('width', '');
- var nextFrame = pageContainer.children('div:eq(' + frameIndex + ')');
+ var nextFrame = getPageContainer().children('div:eq(' + frameIndex + ')');
if (nextFrame.length) {
nextFrame.before(cameraFrameDiv);
}
else {
- pageContainer.append(cameraFrameDiv);
+ getPageContainer().append(cameraFrameDiv);
}
}
});
}
function refreshCameraFrames() {
+ var timestamp = new Date().getTime();
+
function refreshCameraFrame(cameraId, img, serverSideResize) {
if (refreshDisabled[cameraId]) {
/* camera refreshing disabled, retry later */
}
}
- var timestamp = new Date().getTime();
var path = basePath + 'picture/' + cameraId + '/current/?_=' + timestamp;
if (serverSideResize) {
path += '&width=' + img.width;
var cameraFrames;
if (fullScreenCameraId != null && fullScreenCameraId >= 0) {
- cameraFrames = $('#camera' + fullScreenCameraId);
+ cameraFrames = getCameraFrame(fullScreenCameraId);
}
else {
- cameraFrames = $('div.page-container').find('div.camera-frame');
+ cameraFrames = getCameraFrames();
}
cameraFrames.each(function () {
function checkCameraErrors() {
/* properly triggers the onerror event on the cameras whose imgs were not successfully loaded,
* but the onerror event hasn't been triggered, for some reason (seems to happen in Chrome) */
- var cameraFrames = $('div.page-container').find('img.camera');
+ var cameraFrames = getPageContainer().find('img.camera');
cameraFrames.each(function () {
if (this.complete === true && this.naturalWidth === 0 && !this.error && this.src) {