From 4e48939660f7bb70641b9bd0a59af186af5a9087 Mon Sep 17 00:00:00 2001 From: Matt N Date: Sat, 19 Jan 2019 06:41:53 -0800 Subject: [PATCH 01/23] Add a validateForm event listener and enforce CSP on some views (#2425) * Add a validateForm event listener and enforce CSP on the controlcap view * filter.php: Use .validateFormOnSubmit * server.php: Use .validateFormOnSubmit and fix makePopupButton condition check * Use .validateFormOnSubmit and enforce CSP on the storage view --- web/includes/functions.php | 4 +++- web/skins/classic/js/skin.js | 6 ++++++ web/skins/classic/views/controlcap.php | 2 +- web/skins/classic/views/filter.php | 2 +- web/skins/classic/views/js/server.js | 4 ++-- web/skins/classic/views/js/storage.js | 4 ++-- web/skins/classic/views/server.php | 2 +- web/skins/classic/views/storage.php | 2 +- 8 files changed, 17 insertions(+), 9 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index bf9ac06d7..862590b10 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -39,12 +39,14 @@ function CSPHeaders($view, $nonce) { switch ($view) { case 'bandwidth': case 'blank': + case 'controlcap': case 'function': case 'log': case 'login': case 'logout': case 'options': case 'privacy': + case 'storage': case 'version': { // Enforce script-src on pages where inline scripts and event handlers have been fixed. // 'unsafe-inline' is only for backwards compatibility with browsers which @@ -462,7 +464,7 @@ function makePopupButton( $url, $winName, $winSize, $buttonValue, $condition=1, } else { $string .= ' data-window-tag="' . htmlspecialchars($winSize) . '"'; } - if ($condition) { + if (!$condition) { $string .= ' disabled="disabled"'; } $string .= ($options ? (' ' . $options) : '') . '/>'; diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index bba02dd22..6a48eedf2 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -119,6 +119,12 @@ function createPopup( url, name, tag, width, height ) { } $j(document).ready(function() { + $j("form.validateFormOnSubmit").submit(function onSubmit(evt) { + if (!validateForm(this)) { + evt.preventDefault(); + } + }); + $j(".popup-link").click(function onClick(evt) { var el = this; var url; diff --git a/web/skins/classic/views/controlcap.php b/web/skins/classic/views/controlcap.php index 69a859cce..5d1920997 100644 --- a/web/skins/classic/views/controlcap.php +++ b/web/skins/classic/views/controlcap.php @@ -183,7 +183,7 @@ foreach ( $tabs as $name=>$value ) ?>
-
+ diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 98f086ee2..4c59b4362 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -180,7 +180,7 @@ if ( (null !== $filter->Concurrent()) and $filter->Concurrent() ) ?>
-
+ diff --git a/web/skins/classic/views/js/server.js b/web/skins/classic/views/js/server.js index 746ea41bb..1b40eb95b 100644 --- a/web/skins/classic/views/js/server.js +++ b/web/skins/classic/views/js/server.js @@ -1,5 +1,5 @@ -function validateForm( form, newServer ) { - var errors = new Array(); +function validateForm(form) { + var errors = []; if ( !form.elements['newServer[Name]'].value ) { errors[errors.length] = "You must supply a name"; } diff --git a/web/skins/classic/views/js/storage.js b/web/skins/classic/views/js/storage.js index 24ec3e759..36308e6e4 100644 --- a/web/skins/classic/views/js/storage.js +++ b/web/skins/classic/views/js/storage.js @@ -1,5 +1,5 @@ -function validateForm( form, newStorage ) { - var errors = new Array(); +function validateForm(form) { + var errors = []; if ( !form.elements['newStorage[Name]'].value ) { errors[errors.length] = "You must supply a name"; } diff --git a/web/skins/classic/views/server.php b/web/skins/classic/views/server.php index a4e60c3f2..64508995d 100644 --- a/web/skins/classic/views/server.php +++ b/web/skins/classic/views/server.php @@ -39,7 +39,7 @@ xhtmlHeaders(__FILE__, translate('Server').' - '.$Server->Name());

Name() ?>

- + diff --git a/web/skins/classic/views/storage.php b/web/skins/classic/views/storage.php index 49c8d4dec..7ec3a63cf 100644 --- a/web/skins/classic/views/storage.php +++ b/web/skins/classic/views/storage.php @@ -63,7 +63,7 @@ xhtmlHeaders(__FILE__, translate('Storage')." - ".$newStorage['Name'] );

- + From d3f8037e5868e51d53bf4c1d0b56773569f46df6 Mon Sep 17 00:00:00 2001 From: Matt N Date: Sat, 19 Jan 2019 06:42:12 -0800 Subject: [PATCH 02/23] Replace onclick='submitTab(...' with a click listener (#2424) --- web/skins/classic/js/skin.js | 6 +++++- web/skins/classic/views/controlcap.php | 2 +- web/skins/classic/views/monitor.php | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 6a48eedf2..338752966 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -143,6 +143,8 @@ $j(document).ready(function() { evt.preventDefault(); }); + $j(".tabList a").click(submitTab); + // 'data-on-click-this' calls the global function in the attribute value with the element when a click happens. document.querySelectorAll("a[data-on-click-this], button[data-on-click-this], input[data-on-click-this]").forEach(function attachOnClick(el) { var fnName = el.getAttribute("data-on-click-this"); @@ -309,11 +311,13 @@ function secsToTime( seconds ) { return( timeString ); } -function submitTab( tab ) { +function submitTab(evt) { + var tab = this.getAttribute("data-tab-name"); var form = $('contentForm'); form.action.value = ""; form.tab.value = tab; form.submit(); + evt.preventDefault(); } function submitThisForm() { diff --git a/web/skins/classic/views/controlcap.php b/web/skins/classic/views/controlcap.php index 5d1920997..13eabfcc9 100644 --- a/web/skins/classic/views/controlcap.php +++ b/web/skins/classic/views/controlcap.php @@ -176,7 +176,7 @@ foreach ( $tabs as $name=>$value ) else { ?> -
  • +
  • $value ) { -
  • +
  • Date: Sat, 19 Jan 2019 06:43:28 -0800 Subject: [PATCH 03/23] controlcap.php: Reflected xss fix with validHtmlStr (#2423) --- web/skins/classic/views/controlcap.php | 182 ++++++++++++------------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/web/skins/classic/views/controlcap.php b/web/skins/classic/views/controlcap.php index 13eabfcc9..7fdf2844a 100644 --- a/web/skins/classic/views/controlcap.php +++ b/web/skins/classic/views/controlcap.php @@ -160,7 +160,7 @@ xhtmlHeaders(__FILE__, translate('ControlCap')." - ".$newControl['Name'] );
      @@ -215,30 +215,30 @@ if ( $tab != 'pan' ) { ?> - - - - + + + + - - + + - + - - - - + + + + - - + + - + "/> - - - - + + + + - - + + "/> - - - - + + + + - - + + "/> - - - - + + + + - - + + "/> - - - - + + + + - - + + "/> - - - - + + + + - - + + - + checked="checked"> - - - - + + + + checked="checked"/> - - + + checked="checked"/> - + checked="checked"> - - - - + + + + checked="checked"/> - - + + checked="checked"/> - + checked="checked"/> checked="checked"/> checked="checked"/> - - - - + + + + checked="checked"/> - - + + checked="checked"/> checked="checked"/> checked="checked"/> - - - - + + + + checked="checked"/> - - + + checked="checked"/> checked="checked"/> checked="checked"/> - - - - + + + + checked="checked"/> - - + + checked="checked"/> checked="checked"/> checked="checked"/> - - - - + + + + checked="checked"/> - - + + checked="checked"/> checked="checked"/> checked="checked"/> - - - - + + + + checked="checked"/> - - + + checked="checked"/> - + checked="checked"/> checked="checked"/> Date: Sat, 19 Jan 2019 06:46:08 -0800 Subject: [PATCH 04/23] Fix ajax/status.php orderby sql injection (#2421) https://github.com/LoRexxar/CVE_Request/tree/master/zoneminder%20vul%20before%20v1.32.3#ajaxstatusphp-line-276-orderby-sql-injection --- web/ajax/status.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/web/ajax/status.php b/web/ajax/status.php index dbac0773b..671757831 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -259,13 +259,14 @@ function collectData() { $index = 0; $where = array(); $values = array(); - foreach( $entitySpec['selector'] as $selector ) { + foreach( $entitySpec['selector'] as $selIndex => $selector ) { + $selectorParamName = ':selector' . $selIndex; if ( is_array( $selector ) ) { - $where[] = $selector['selector'].' = ?'; - $values[] = validInt($id[$index]); + $where[] = $selector['selector'].' = '.$selectorParamName; + $values[$selectorParamName] = validInt($id[$index]); } else { - $where[] = $selector.' = ?'; - $values[] = validInt($id[$index]); + $where[] = $selector.' = '.$selectorParamName; + $values[$selectorParamName] = validInt($id[$index]); } $index++; } @@ -274,7 +275,8 @@ function collectData() { if ( $groupSql ) $sql .= ' GROUP BY '.join( ',', array_unique( $groupSql ) ); if ( !empty($_REQUEST['sort']) ) - $sql .= ' order by '.$_REQUEST['sort']; + $sql .= ' order by :sort'; + $values[':sort'] = $_REQUEST['sort']; if ( !empty($entitySpec['limit']) ) $limit = $entitySpec['limit']; elseif ( !empty($_REQUEST['count']) ) From c0a6e54d60d3a8f297cc5f2ef6a862f6f00d746e Mon Sep 17 00:00:00 2001 From: Matt N Date: Sat, 19 Jan 2019 06:46:21 -0800 Subject: [PATCH 05/23] skins/classic/views/control.php second order sqli (#2422) --- web/skins/classic/views/control.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/control.php b/web/skins/classic/views/control.php index d21a629ee..c40740bca 100644 --- a/web/skins/classic/views/control.php +++ b/web/skins/classic/views/control.php @@ -23,17 +23,18 @@ if ( !canView( 'Control' ) ) { return; } +$params = array(); $groupSql = ''; if ( !empty($_REQUEST['group']) ) { - $row = dbFetchOne( 'SELECT * FROM Groups WHERE Id = ?', NULL, array($_REQUEST['group']) ); - $groupSql = " and find_in_set( Id, '".$row['MonitorIds']."' )"; + $groupSql = " AND gm.GroupId = :groupid"; + $params[":groupid"] = $_REQUEST['group']; } $mid = !empty($_REQUEST['mid']) ? validInt($_REQUEST['mid']) : 0; -$sql = "SELECT * FROM Monitors WHERE Function != 'None' AND Controllable = 1$groupSql ORDER BY Sequence"; +$sql = "SELECT m.* FROM Monitors m INNER JOIN Groups_Monitors AS gm ON m.Id = gm.MonitorId WHERE m.Function != 'None' AND m.Controllable = 1$groupSql ORDER BY Sequence"; $mids = array(); -foreach( dbFetchAll( $sql ) as $row ) { +foreach( dbFetchAll( $sql, false, $params ) as $row ) { if ( !visibleMonitor( $row['Id'] ) ) { continue; } From 35fb4366b66128b5321378ed97b90747b4e1fcf9 Mon Sep 17 00:00:00 2001 From: Matt N Date: Sat, 19 Jan 2019 06:47:04 -0800 Subject: [PATCH 06/23] Fix recaptcha support with the CSP (#2420) --- web/includes/functions.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 862590b10..c33de8439 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -36,13 +36,22 @@ function noCacheHeaders() { } function CSPHeaders($view, $nonce) { + $additionalScriptSrc = ""; switch ($view) { + case 'login': { + if (defined('ZM_OPT_USE_GOOG_RECAPTCHA') + && defined('ZM_OPT_GOOG_RECAPTCHA_SITEKEY') + && defined('ZM_OPT_GOOG_RECAPTCHA_SECRETKEY') + && ZM_OPT_USE_GOOG_RECAPTCHA && ZM_OPT_GOOG_RECAPTCHA_SITEKEY && ZM_OPT_GOOG_RECAPTCHA_SECRETKEY) { + $additionalScriptSrc = "https://www.google.com"; + } + // fall through + } case 'bandwidth': case 'blank': case 'controlcap': case 'function': case 'log': - case 'login': case 'logout': case 'options': case 'privacy': @@ -51,12 +60,12 @@ function CSPHeaders($view, $nonce) { // Enforce script-src on pages where inline scripts and event handlers have been fixed. // 'unsafe-inline' is only for backwards compatibility with browsers which // only support CSP 1 (with no nonce-* support). - header("Content-Security-Policy: script-src 'unsafe-inline' 'self' 'nonce-$nonce'"); + header("Content-Security-Policy: script-src 'unsafe-inline' 'self' 'nonce-$nonce' $additionalScriptSrc"); break; } default: { // Use Report-Only mode on all other pages. - header("Content-Security-Policy-Report-Only: script-src 'unsafe-inline' 'self' 'nonce-$nonce'"); + header("Content-Security-Policy-Report-Only: script-src 'unsafe-inline' 'self' 'nonce-$nonce' $additionalScriptSrc"); break; } } From a1a42345e3cdd2ddb61427accc4d1c1d4c04c0c9 Mon Sep 17 00:00:00 2001 From: Matt N Date: Sat, 19 Jan 2019 07:32:40 -0800 Subject: [PATCH 07/23] More eslint fixes; eslint in php; add eslint to travis (#2419) * Add eslint to travis.yml * Update eslint package versions and apply new indent rules * Enable the brace-style and block-style eslint rules * Enable the 'curly' eslint rule * Enable the 'keyword-spacing' eslint rule * Enable the 'key-spacing' eslint rule * Enable the 'object-curly-spacing' eslint rule * Enable the 'no-new-object' eslint rule * Only disable the no-caller eslint rule in the one affected file * Enable the 'no-unused-vars' eslint rule for local variables * Add linting of JS in .php files --- .eslintignore | 6 +- .eslintrc.js | 32 ++- .travis.yml | 29 +- web/js/Server.js | 16 +- web/js/logger.js | 142 +++++----- web/js/mootools.ext.js | 18 +- web/js/overlay.js | 231 ++++++++-------- .../classic/includes/export_functions.php | 6 +- web/skins/classic/includes/functions.php | 6 +- web/skins/classic/js/base.js | 94 +++---- web/skins/classic/js/classic.js | 96 +++---- web/skins/classic/js/skin.js | 157 ++++++----- web/skins/classic/views/js/add_monitors.js | 74 ++--- web/skins/classic/views/js/console.js | 38 +-- web/skins/classic/views/js/control.js | 15 +- web/skins/classic/views/js/controlcap.js | 4 +- web/skins/classic/views/js/donate.js | 5 +- web/skins/classic/views/js/download.js | 7 +- web/skins/classic/views/js/event.js | 208 ++++++++------ web/skins/classic/views/js/events.js | 9 +- web/skins/classic/views/js/export.js | 12 +- web/skins/classic/views/js/filter.js | 27 +- web/skins/classic/views/js/frame.js | 4 +- web/skins/classic/views/js/log.js | 183 +++++++------ web/skins/classic/views/js/monitor.js | 14 +- web/skins/classic/views/js/montage.js | 172 ++++++------ web/skins/classic/views/js/montagereview.js | 255 ++++++++++-------- web/skins/classic/views/js/onvifprobe.js | 2 +- web/skins/classic/views/js/plugin.js | 4 +- web/skins/classic/views/js/privacy.js | 5 +- .../classic/views/js/report_event_audit.js | 44 +-- web/skins/classic/views/js/server.js | 4 +- web/skins/classic/views/js/state.js | 102 +++---- web/skins/classic/views/js/storage.js | 1 + web/skins/classic/views/js/timeline.js | 24 +- web/skins/classic/views/js/user.js | 7 +- web/skins/classic/views/js/video.js | 7 +- web/skins/classic/views/js/watch.js | 227 ++++++++++------ web/skins/classic/views/js/zone.js | 138 ++++++---- web/skins/classic/views/js/zones.js | 5 +- 40 files changed, 1335 insertions(+), 1095 deletions(-) diff --git a/.eslintignore b/.eslintignore index 0fb9f18e5..4682851df 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,7 +2,7 @@ # libraries web/api/lib -web/includes/csrf/csrf-magic.js +web/includes/csrf/ web/js/videojs.zoomrotate.js web/skins/classic/js/bootstrap.js web/skins/classic/js/chosen @@ -13,3 +13,7 @@ web/skins/classic/js/jquery.js web/skins/classic/js/moment.js web/skins/classic/js/video.js web/tools/mootools + +# Cannot be parsed as JS +web/skins/classic/includes/export_functions.php +web/skins/classic/views/events.php diff --git a/.eslintrc.js b/.eslintrc.js index dd1f9a779..64950ee0d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,26 +5,46 @@ module.exports = { "browser": true, }, "extends": ["google"], + "overrides": [{ + // eslint-plugin-html handles eol-last slightly different - it applies to + // each set of script tags, so we turn it off here. + "files": "**/*.*php", + "rules": { + "eol-last": "off", + "indent": "off", + }, + }], + "plugins": [ + "html", + "php-markup", + ], "rules": { - "brace-style": "off", "camelcase": "off", "comma-dangle": "off", "guard-for-in": "off", - "key-spacing": "off", "max-len": "off", "new-cap": ["error", { capIsNewExceptions: ["Error", "Warning", "Debug", "Polygon_calcArea", "Play", "Stop"], newIsCapExceptionPattern: "^Asset\.." }], "no-array-constructor": "off", - "no-caller": "off", - "no-new-object": "off", - "no-unused-vars": "off", + "no-unused-vars": ["error", { + "vars": "local", + "args": "none", + "ignoreRestSiblings": false + }], "no-var": "off", - "object-curly-spacing": "off", "prefer-rest-params": "off", "quotes": "off", "require-jsdoc": "off", "spaced-comment": "off", }, + "settings": { + "php/php-extensions": [".php"], + "php/markup-replacement": {"php": "", "=": "0"}, + "php/keep-eol": false, + "php/remove-whitespace": false, + "php/remove-empty-line": false, + "php/remove-php-lint": false + }, }; diff --git a/.travis.yml b/.travis.yml index d46e0fc85..6c41f1123 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,24 +32,28 @@ install: - update-binfmts --enable qemu-arm env: - global: - - SMPFLAGS=-j4 - matrix: - - OS=el DIST=7 - - OS=fedora DIST=27 DOCKER_REPO=knnniggett/packpack - - OS=fedora DIST=28 DOCKER_REPO=knnniggett/packpack - - OS=fedora DIST=29 DOCKER_REPO=knnniggett/packpack - - OS=ubuntu DIST=trusty - - OS=ubuntu DIST=xenial - - OS=ubuntu DIST=trusty ARCH=i386 - - OS=ubuntu DIST=xenial ARCH=i386 - - OS=raspbian DIST=stretch ARCH=armhf DOCKER_REPO=knnniggett/packpack + - SMPFLAGS=-j4 OS=el DIST=7 + - SMPFLAGS=-j4 OS=fedora DIST=27 DOCKER_REPO=knnniggett/packpack + - SMPFLAGS=-j4 OS=fedora DIST=28 DOCKER_REPO=knnniggett/packpack + - SMPFLAGS=-j4 OS=fedora DIST=29 DOCKER_REPO=knnniggett/packpack + - SMPFLAGS=-j4 OS=ubuntu DIST=trusty + - SMPFLAGS=-j4 OS=ubuntu DIST=xenial + - SMPFLAGS=-j4 OS=ubuntu DIST=trusty ARCH=i386 + - SMPFLAGS=-j4 OS=ubuntu DIST=xenial ARCH=i386 + - SMPFLAGS=-j4 OS=raspbian DIST=stretch ARCH=armhf DOCKER_REPO=knnniggett/packpack compiler: - gcc services: - mysql - docker + +jobs: + include: + - name: eslint + install: npm install -g eslint@5.12.0 eslint-config-google@0.11.0 eslint-plugin-html@5.0.0 eslint-plugin-php-markup@0.2.5 + script: eslint --ext .php,.js . + script: - utils/packpack/startpackpack.sh @@ -65,4 +69,3 @@ deploy: script: utils/packpack/rsync_xfer.sh on: branch: master - diff --git a/web/js/Server.js b/web/js/Server.js index 73524e673..d9ab937e6 100644 --- a/web/js/Server.js +++ b/web/js/Server.js @@ -1,8 +1,20 @@ 'use strict'; -var _createClass = function() { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function(Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +var _createClass = function() { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); + } + } return function(Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; + }; +}(); -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} var Server = function() { function Server(json) { diff --git a/web/js/logger.js b/web/js/logger.js index 6bd465c8a..fb7995165 100644 --- a/web/js/logger.js +++ b/web/js/logger.js @@ -17,105 +17,103 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -if ( !window.console ) -{ - window.console = +if ( !window.console ) { + window.console = { - init:function() {}, - log:function() {}, - debug:function() {}, - info:function() {}, - warn:function() {}, - error:function() {} + init: function() {}, + log: function() {}, + debug: function() {}, + info: function() {}, + warn: function() {}, + error: function() {} }; } -if ( !console.debug )//IE8 has console but doesn't have console.debug so lets alias it. - console.debug = console.log; +if ( !console.debug ) { + // IE8 has console but doesn't have console.debug so lets alias it. + console.debug = console.log; +} var reportLogs = true; var debugParms; var debugReq; -function logReport( level, message, file, line ) -{ - if ( !reportLogs ) - return; +function logReport( level, message, file, line ) { + if ( !reportLogs ) { + return; + } - if ( typeof(MooTools) == "undefined" ) - return; + if ( typeof(MooTools) == "undefined" ) { + return; + } + /* eslint-disable no-caller */ + if ( arguments && arguments.callee && arguments.callee.caller && arguments.callee.caller.name ) { + message += ' - '+arguments.callee.caller.caller.name+'()'; + } + /* eslint-enable no-caller */ - if ( arguments && arguments.callee && arguments.callee.caller && arguments.callee.caller.name ) - message += ' - '+arguments.callee.caller.caller.name+'()'; - - if ( !debugReq ) - { - if ( Browser ) - debugParms = "view=request&request=log&task=create&browser[name]="+Browser.name+"&browser[version]="+Browser.version+"&browser[platform]="+(Browser.Platform?Browser.Platform.name:'unknown'); - else - debugParms = "view=request&request=log&task=create&browser[name]=unknown&browser[version]=unknown&browser[platform]=unknown"; - debugReq = new Request.JSON( { url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'chain' } ); + if ( !debugReq ) { + if ( Browser ) { + debugParms = "view=request&request=log&task=create&browser[name]="+Browser.name+"&browser[version]="+Browser.version+"&browser[platform]="+(Browser.Platform?Browser.Platform.name:'unknown'); + } else { + debugParms = "view=request&request=log&task=create&browser[name]=unknown&browser[version]=unknown&browser[platform]=unknown"; } - var requestParms = debugParms; - requestParms += "&level="+level+"&message="+encodeURIComponent(message); - if ( file ) - requestParms += "&file="+file; - else if ( location.search ) { - //location.search is the querystring part, so ?blah=blah but there is almost never any value to this - requestParms += "&file="+location.search; - } - if ( line ) - requestParms += "&line="+line; - debugReq.send( requestParms ); + debugReq = new Request.JSON( {url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'chain'} ); + } + var requestParms = debugParms; + requestParms += "&level="+level+"&message="+encodeURIComponent(message); + if ( file ) { + requestParms += "&file="+file; + } else if ( location.search ) { + //location.search is the querystring part, so ?blah=blah but there is almost never any value to this + requestParms += "&file="+location.search; + } + if ( line ) { + requestParms += "&line="+line; + } + debugReq.send( requestParms ); } -function Panic( message ) -{ - console.error( message ); - logReport( "PNC", message ); - alert( "PANIC: "+message ); +function Panic( message ) { + console.error( message ); + logReport( "PNC", message ); + alert( "PANIC: "+message ); } -function Fatal( message ) -{ - console.error( message ); - logReport( "FAT", message ); - alert( "FATAL: "+message ); +function Fatal( message ) { + console.error( message ); + logReport( "FAT", message ); + alert( "FATAL: "+message ); } -function Error( message ) -{ - console.error( message ); - logReport( "ERR", message ); +function Error( message ) { + console.error( message ); + logReport( "ERR", message ); } -function Warning( message ) -{ - console.warn( message ); - logReport( "WAR", message ); +function Warning( message ) { + console.warn( message ); + logReport( "WAR", message ); } -function Info( message ) -{ - console.info( message ); - logReport( "INF", message ); +function Info( message ) { + console.info( message ); + logReport( "INF", message ); } -function Debug( message ) -{ - console.debug( message ); - //logReport( "DBG", message ); +function Debug( message ) { + console.debug( message ); + //logReport( "DBG", message ); } -function Dump( value, label ) -{ - if ( label ) - console.debug( label+" => " ); - console.debug( value ); +function Dump( value, label ) { + if ( label ) { + console.debug( label+" => " ); + } + console.debug( value ); } window.onerror = - function( message, url, line ) - { - logReport( "ERR", message, url, line ); + function( message, url, line ) { + logReport( "ERR", message, url, line ); }; diff --git a/web/js/mootools.ext.js b/web/js/mootools.ext.js index bc2f276e3..76c55fb38 100644 --- a/web/js/mootools.ext.js +++ b/web/js/mootools.ext.js @@ -6,15 +6,11 @@ var zmMooToolsVersion = '1.3.2'; /* * Firstly, lets check that mootools has been included and thus is present */ -if ( typeof(MooTools) == "undefined" ) -{ - alert( "MooTools not found! Please check that it was installed correctly in ZoneMinder web root." ); -} -else -{ - /* Version check */ - if ( MooTools.version < zmMooToolsVersion ) - { - alert( "MooTools version "+MooTools.version+" found.\nVersion "+zmMooToolsVersion+" required, please check that it was installed correctly in ZoneMinder web root." ); - } +if ( typeof(MooTools) == "undefined" ) { + alert( "MooTools not found! Please check that it was installed correctly in ZoneMinder web root." ); +} else { + /* Version check */ + if ( MooTools.version < zmMooToolsVersion ) { + alert( "MooTools version "+MooTools.version+" found.\nVersion "+zmMooToolsVersion+" required, please check that it was installed correctly in ZoneMinder web root." ); + } } diff --git a/web/js/overlay.js b/web/js/overlay.js index 9738487b0..e3714d05f 100644 --- a/web/js/overlay.js +++ b/web/js/overlay.js @@ -1,133 +1,122 @@ var Overlay = new Class({ - Implements: [Options, Events], - initialize: function( id, options ) - { - this.setOptions( options ); + Implements: [Options, Events], + initialize: function( id, options ) { + this.setOptions( options ); - this.mask = new Mask( document.body, { 'maskMargins': false, 'class': 'overlayMask' } ); + this.mask = new Mask( document.body, {'maskMargins': false, 'class': 'overlayMask'} ); - this.id = id?id:'overlay'; - if ( typeOf(this.id) == 'string' ) - { - if ( $(this.id) ) - this.element = $(this.id); - } - else - { - this.element = this.id; - this.id = this.element.get('id'); - } - if ( !this.element ) - { - this.element = new Element( 'div', { 'id': this.id, 'class': 'overlay', 'styles': { 'display': 'none' } } ); - if ( this.options.title || this.options.buttons ) - { - var overlayHeader = new Element( 'div', { 'class': 'overlayHeader' } ); - if ( this.options.title ) - { - var overlayTitle = new Element( 'div', { 'class': 'overlayTitle', 'text': this.options.title } ); - overlayHeader.grab( overlayTitle ); - } - if ( this.options.buttons ) - { - var overlayToolbar = new Element( 'div', { 'class': 'overlayToolbar' } ); - this.options.buttons.each( - function( button ) - { - var overlayButton = new Element( 'button', { 'text': button.text } ); - if ( button.id ) - overlayButton.setProperty( 'id', button.id ); - if ( button.events ) - overlayButton.set( 'events', events ); - overlayToolbar.grab( overlayButton ); - } - ); - overlayHeader.grab( overlayTitle ); - } - this.element.grab( overlayHeader ); - var overlayBody = new Element( 'div', { 'class': 'overlayBody' } ); - var overlayContent = new Element( 'div', { 'class': 'overlayContent' } ); - overlayContent.grab( this.options.content ); - overlayBody.grab( overlayContent ); - this.element.grab( overlayBody ); - } - this.target = document.id(this.options.target) || document.id(document.body); - this.element.inject( this.target ); - } - }, - show: function() - { - this.mask.show(); - $(window).addEvent( 'resize', this.update.bind(this) ); - $(window).addEvent( 'scroll', this.update.bind(this) ); - this.element.tween( 'opacity', [0, 1.0] ); - this.element.show(); - this.element.position(); - this.mask.position(); - }, - hideComplete: function() - { - $(window).removeEvent( 'resize', this.update.bind(this) ); - $(window).removeEvent( 'scroll', this.update.bind(this) ); - this.element.hide(); - this.mask.hide(); - }, - hide: function() - { - new Fx.Tween( this.element, { duration: 400, transition: Fx.Transitions.Sine, onComplete: this.hideComplete.bind(this) } ).start( 'opacity', 1.0, 0 ); - }, - update: function() - { - this.element.position(); - this.mask.position(); - }, - showAnimation:function() - { - showOverlay(); - - //console.log( "Showing overlay loading" ); - if ( !this.loading ) - { - this.loading = new Element( 'div', { 'id': 'loading'+this.key, 'styles': { 'display':'none' } } ); - this.loading.grab( this.loadingImage ); - document.body.grab( this.loading ); - } - updateOverlayLoading(); - this.loading.setStyle( 'display', 'block' ); - $(window).addEvent( 'resize', this.update.bind(this) ); - $(window).addEvent( 'scroll', this.update.bind(this) ); - }, - hideAnimation:function() - { - $(window).removeEvent( 'resize', this.update.bind(this) ); - $(window).removeEvent( 'scroll', this.update.bind(this) ); - if ( this.loading ) - this.loading.setStyle( 'display', 'none' ); + this.id = id?id:'overlay'; + if ( typeOf(this.id) == 'string' ) { + if ( $(this.id) ) { + this.element = $(this.id); + } + } else { + this.element = this.id; + this.id = this.element.get('id'); } + if ( !this.element ) { + this.element = new Element( 'div', {'id': this.id, 'class': 'overlay', 'styles': {'display': 'none'}} ); + if ( this.options.title || this.options.buttons ) { + var overlayHeader = new Element( 'div', {'class': 'overlayHeader'} ); + if ( this.options.title ) { + var overlayTitle = new Element( 'div', {'class': 'overlayTitle', 'text': this.options.title} ); + overlayHeader.grab( overlayTitle ); + } + if ( this.options.buttons ) { + var overlayToolbar = new Element( 'div', {'class': 'overlayToolbar'} ); + this.options.buttons.each( + function( button ) { + var overlayButton = new Element( 'button', {'text': button.text} ); + if ( button.id ) { + overlayButton.setProperty( 'id', button.id ); + } + if ( button.events ) { + overlayButton.set( 'events', events ); + } + overlayToolbar.grab( overlayButton ); + } + ); + overlayHeader.grab( overlayTitle ); + } + this.element.grab( overlayHeader ); + var overlayBody = new Element( 'div', {'class': 'overlayBody'} ); + var overlayContent = new Element( 'div', {'class': 'overlayContent'} ); + overlayContent.grab( this.options.content ); + overlayBody.grab( overlayContent ); + this.element.grab( overlayBody ); + } + this.target = document.id(this.options.target) || document.id(document.body); + this.element.inject( this.target ); + } + }, + show: function() { + this.mask.show(); + $(window).addEvent( 'resize', this.update.bind(this) ); + $(window).addEvent( 'scroll', this.update.bind(this) ); + this.element.tween( 'opacity', [0, 1.0] ); + this.element.show(); + this.element.position(); + this.mask.position(); + }, + hideComplete: function() { + $(window).removeEvent( 'resize', this.update.bind(this) ); + $(window).removeEvent( 'scroll', this.update.bind(this) ); + this.element.hide(); + this.mask.hide(); + }, + hide: function() { + new Fx.Tween( this.element, {duration: 400, transition: Fx.Transitions.Sine, onComplete: this.hideComplete.bind(this)} ).start( 'opacity', 1.0, 0 ); + }, + update: function() { + this.element.position(); + this.mask.position(); + }, + showAnimation: function() { + showOverlay(); + + //console.log( "Showing overlay loading" ); + if ( !this.loading ) { + this.loading = new Element( 'div', {'id': 'loading'+this.key, 'styles': {'display': 'none'}} ); + this.loading.grab( this.loadingImage ); + document.body.grab( this.loading ); + } + updateOverlayLoading(); + this.loading.setStyle( 'display', 'block' ); + $(window).addEvent( 'resize', this.update.bind(this) ); + $(window).addEvent( 'scroll', this.update.bind(this) ); + }, + hideAnimation: function() { + $(window).removeEvent( 'resize', this.update.bind(this) ); + $(window).removeEvent( 'scroll', this.update.bind(this) ); + if ( this.loading ) { + this.loading.setStyle( 'display', 'none' ); + } + } }); -function setupOverlays() -{ - try { +function setupOverlays() { + try { $$('.overlay').each( - function( overlay ) - { - overlay.element = new Overlay( overlay.get('id') ); - overlay.getElements('.overlayCloser').each( - function( closer ) - { - closer.addEvent( 'click', function() { overlay.element.hide(); } ); - } - ); - overlay.overlayShow = function() { overlay.element.show(); }; - overlay.overlayHide = function() { overlay.element.hide(); }; + function( overlay ) { + overlay.element = new Overlay( overlay.get('id') ); + overlay.getElements('.overlayCloser').each( + function( closer ) { + closer.addEvent( 'click', function() { + overlay.element.hide(); + } ); + } + ); + overlay.overlayShow = function() { + overlay.element.show(); + }; + overlay.overlayHide = function() { + overlay.element.hide(); + }; } ); - } - catch ( e ) - { - alert( e ); - } + } catch ( e ) { + alert( e ); + } } window.addEvent( 'domready', setupOverlays ); diff --git a/web/skins/classic/includes/export_functions.php b/web/skins/classic/includes/export_functions.php index 5981664e3..7e3427606 100644 --- a/web/skins/classic/includes/export_functions.php +++ b/web/skins/classic/includes/export_functions.php @@ -286,9 +286,9 @@ function exportEventImages( $event, $exportDetail, $exportFrames, $myfilelist ) * Visit http://www.dynamicdrive.com/ for full source code ***********************************************/ -var eventWidth = Width()?>; -var eventHeight = Height()?>; -var variableslide=[]; +var eventWidth = Width(); ?>; +var eventHeight = Height(); ?>; +var variableslide=[]; //configure the below 3 variables to set the dimension/background color of the slideshow diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 535d8ba31..c5c98c8e6 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -121,11 +121,11 @@ echo output_link_if_exists( array(