diff options
Diffstat (limited to 'www')
| -rw-r--r-- | www/css/style.css | 4 | ||||
| -rw-r--r-- | www/external/origjs/packery.pkgd.js | 4 | ||||
| -rw-r--r-- | www/external/packery.pkgd.min.js | 2 | ||||
| -rw-r--r-- | www/js/DataModel.js | 9 | ||||
| -rw-r--r-- | www/js/MontageCtrl.js | 232 | ||||
| -rw-r--r-- | www/lang/locale-en.json | 4 | ||||
| -rw-r--r-- | www/templates/montage.html | 45 |
7 files changed, 261 insertions, 39 deletions
diff --git a/www/css/style.css b/www/css/style.css index 1ff3ce8c..2b3fda9b 100644 --- a/www/css/style.css +++ b/www/css/style.css @@ -26,6 +26,10 @@ background-size:contain; } +.icon-save:before { + font-family: "fontawesome"; + content: "\f0c7"; +} diff --git a/www/external/origjs/packery.pkgd.js b/www/external/origjs/packery.pkgd.js index 7576576b..fa4e8308 100644 --- a/www/external/origjs/packery.pkgd.js +++ b/www/external/origjs/packery.pkgd.js @@ -3088,10 +3088,10 @@ proto._bindFitEvents = function( item ) { // -------------------------- resize -------------------------- // // debounced, layout on resize -proto.resize = function() { +proto.resize = function(force) { // don't trigger if size did not change // or if resize was unbound. See #285, outlayer#9 - if ( !this.isResizeBound || !this.needsResizeLayout() ) { + if ( !force && (!this.isResizeBound || !this.needsResizeLayout()) ) { return; } diff --git a/www/external/packery.pkgd.min.js b/www/external/packery.pkgd.min.js index f1ba5e03..0a072330 100644 --- a/www/external/packery.pkgd.min.js +++ b/www/external/packery.pkgd.min.js @@ -227,7 +227,7 @@ else{var o=this._getElementOffset(t) e=new i({x:this._getOption("originLeft")?o.left:o.right,y:this._getOption("originTop")?o.top:o.bottom})}this._setRectSize(t,e),this.packer.placed(e),this._setMaxXY(e)},u.sortItemsByPosition=function(){var t=this._getOption("horizontal")?r:s this.items.sort(t)},u.fit=function(t,e,i){var n=this.getItem(t) n&&(this.stamp(n.element),n.enablePlacing(),this.updateShiftTargets(n),e=void 0===e?n.rect.x:e,i=void 0===i?n.rect.y:i,this.shift(n,e,i),this._bindFitEvents(n),n.moveTo(n.rect.x,n.rect.y),this.shiftLayout(),this.unstamp(n.element),this.sortItemsByPosition(),n.disablePlacing())},u._bindFitEvents=function(t){function e(){n++,2==n&&i.dispatchEvent("fitComplete",null,[t])}var i=this,n=0 -t.once("layout",e),this.once("layoutComplete",e)},u.resize=function(){this.isResizeBound&&this.needsResizeLayout()&&(this.options.shiftPercentResize?this.resizeShiftPercentLayout():this.layout())},u.needsResizeLayout=function(){var e=t(this.element),i=this._getOption("horizontal")?"innerHeight":"innerWidth" +t.once("layout",e),this.once("layoutComplete",e)},u.resize=function(t){(t||this.isResizeBound&&this.needsResizeLayout())&&(this.options.shiftPercentResize?this.resizeShiftPercentLayout():this.layout())},u.needsResizeLayout=function(){var e=t(this.element),i=this._getOption("horizontal")?"innerHeight":"innerWidth" return e[i]!=this.size[i]},u.resizeShiftPercentLayout=function(){var e=this._getItemsForLayout(this.items),i=this._getOption("horizontal"),n=i?"y":"x",o=i?"height":"width",s=i?"rowHeight":"columnWidth",r=i?"innerHeight":"innerWidth",a=this[s] if(a=a&&a+this.gutter){this._getMeasurements() var h=this[s]+this.gutter diff --git a/www/js/DataModel.js b/www/js/DataModel.js index 5a837039..4c8be1a7 100644 --- a/www/js/DataModel.js +++ b/www/js/DataModel.js @@ -121,6 +121,7 @@ angular.module('zmApp.controllers') 'enableBlog': true, 'use24hr': false, 'packeryPositions': '', + 'packeryPositionsArray': {}, 'EHpackeryPositions': '', 'packerySizes': '', 'timelineModalGraphType': 'all', @@ -755,6 +756,14 @@ angular.module('zmApp.controllers') } + if (typeof loginData.packeryPositionsArray == 'undefined') + { + debug("packeryPositionsArray does not exist. Setting to empty"); + loginData.packeryPositionsArray = {}; + + } + + if (typeof loginData.packeryPositions == 'undefined') { debug("packeryPositions does not exist. Setting to empty"); diff --git a/www/js/MontageCtrl.js b/www/js/MontageCtrl.js index 294073f5..ffb265cf 100644 --- a/www/js/MontageCtrl.js +++ b/www/js/MontageCtrl.js @@ -4,7 +4,7 @@ /* global cordova,StatusBar,angular,console,ionic,Packery, Draggabilly, imagesLoaded, ConnectSDK, moment */ angular.module('zmApp.controllers') - .controller('zmApp.MontageCtrl', ['$scope', '$rootScope', 'NVRDataModel', 'message', '$ionicSideMenuDelegate', '$timeout', '$interval', '$ionicModal', '$ionicLoading', '$http', '$state', '$ionicPopup', '$stateParams', '$ionicHistory', '$ionicScrollDelegate', '$ionicPlatform', 'zm', '$ionicPopover', '$controller', 'imageLoadingDataShare', '$window', '$localstorage', '$translate', function($scope, $rootScope, NVRDataModel, message, $ionicSideMenuDelegate, $timeout, $interval, $ionicModal, $ionicLoading, $http, $state, $ionicPopup, $stateParams, $ionicHistory, $ionicScrollDelegate, $ionicPlatform, zm, $ionicPopover, $controller, imageLoadingDataShare, $window, $localstorage, $translate) + .controller('zmApp.MontageCtrl', ['$scope', '$rootScope', 'NVRDataModel', 'message', '$ionicSideMenuDelegate', '$timeout', '$interval', '$ionicModal', '$ionicLoading', '$http', '$state', '$ionicPopup', '$stateParams', '$ionicHistory', '$ionicScrollDelegate', '$ionicPlatform', 'zm', '$ionicPopover', '$controller', 'imageLoadingDataShare', '$window', '$localstorage', '$translate', 'SecuredPopups', function($scope, $rootScope, NVRDataModel, message, $ionicSideMenuDelegate, $timeout, $interval, $ionicModal, $ionicLoading, $http, $state, $ionicPopup, $stateParams, $ionicHistory, $ionicScrollDelegate, $ionicPlatform, zm, $ionicPopover, $controller, imageLoadingDataShare, $window, $localstorage, $translate, SecuredPopups) { //--------------------------------------------------------------------- @@ -175,7 +175,7 @@ angular.module('zmApp.controllers') columnWidth: '.grid-sizer', gutter: 0, initLayout: layouttype, - shiftPercentResize:true + shiftPercentResize: true }); @@ -186,9 +186,12 @@ angular.module('zmApp.controllers') NVRDataModel.debug('~~loaded image is ' + result + ' for ' + img.img.src); // lay out every image if a pre-arranged position has not been found - - $timeout (function(){if (layouttype) pckry.layout();},100); - + + $timeout(function() + { + if (layouttype) pckry.layout(); + }, 100); + progressCalled = true; // if (layouttype) $timeout (function(){layout(pckry);},100); @@ -207,7 +210,7 @@ angular.module('zmApp.controllers') if (!progressCalled) { NVRDataModel.log("*** PROGRESS WAS NOT CALLED"); - // pckry.reloadItems(); + // pckry.reloadItems(); } $timeout(function() @@ -250,14 +253,15 @@ angular.module('zmApp.controllers') { //NVRDataModel.log("Force calling resize"); ///pckry.reloadItems(); - pckry.initShiftLayout(positions,"data-item-id"); + pckry.initShiftLayout(positions, "data-item-id"); // now do a jiggle $timeout(function() { - pckry.shiftLayout(); + NVRDataModel.debug("doing the jiggle and dance..."); + pckry.resize(true); }, 300); - }, 20); + }, 100); //pckry.onresize(); @@ -919,28 +923,189 @@ angular.module('zmApp.controllers') function orientationChanged() { - /*NVRDataModel.debug("Detected orientation change, redoing packery resize"); - - $timeout(function () { - var positions = pckry.getShiftPositions('data-item-id'); - pckry.initShiftLayout(positions,'data-item-id'); - pckry.shiftLayout(); - }, zm.packeryTimer);*/ - - /* var positions = pckry.getShiftPositions('data-item-id'); - $timeout(function () { - NVRDataModel.log("init shift layout"); - pckry.initShiftLayout(positions,"data-item-id"); - $ionicScrollDelegate.$getByHandle("montage-delegate").scrollTop(); - }, 20);*/ - - //console.log ("POSITIONS MAP " + JSON.stringify(positions)); - // var ld = NVRDataModel.getLogin(); - // ld.packeryPositions = JSON.stringify(positions); - //console.log ("Saving " + ld.packeryPositions); - // NVRDataModel.setLogin(ld); + } + + // remove a saved montage profile + $scope.deleteMontageProfile = function() + { + var posArray; + + try + { + posArray = NVRDataModel.getLogin().packeryPositionsArray; + //console.log ("PA="+JSON.stringify(posArray)); + + } + catch (e) + { + NVRDataModel.debug("error parsing packery array positions"); + posArray = {}; + } + + //console.log ("posArray="+JSON.stringify(posArray)); + + $scope.listdata = []; + for (var key in posArray) + { + if (posArray.hasOwnProperty(key)) + { + $scope.listdata.push(key); + } + } + + if (!$scope.listdata.length) + { + + $rootScope.zmPopup = $ionicPopup.alert( + { + title: $translate.instant('kError'), + template: $translate.instant('kMontageNoSavedProfiles') + }); + return; + } + + $scope.data = { + 'selectedVal': '' + }; + + $rootScope.zmPopup = SecuredPopups.show('confirm', + { + template: '<ion-list> ' + + ' <ion-radio-fix ng-repeat="item in listdata" ng-value="item" ng-model="data.selectedVal"> ' + + ' {{item}} ' + + ' </ion-item> ' + + '</ion-list> ', + + title: $translate.instant('kSelect'), + scope: $scope, + + }).then(function(res) + { + NVRDataModel.debug("Deleting profile: " + $scope.data.selectedVal); + delete posArray[$scope.data.selectedVal]; + var ld = NVRDataModel.getLogin(); + ld.packeryPositionsArray = posArray; + NVRDataModel.setLogin(ld); + + }); + + }; + + // switch to another montage profile + $scope.switchMontageProfile = function() + { + var posArray; + + try + { + posArray = NVRDataModel.getLogin().packeryPositionsArray; + //console.log ("PA="+JSON.stringify(posArray)); + + } + catch (e) + { + NVRDataModel.debug("error parsing packery array positions"); + posArray = {}; + } + + //console.log ("posArray="+JSON.stringify(posArray)); + + $scope.listdata = []; + for (var key in posArray) + { + if (posArray.hasOwnProperty(key)) + { + $scope.listdata.push(key); + } + } + + if (!$scope.listdata.length) + { + + $rootScope.zmPopup = $ionicPopup.alert( + { + title: $translate.instant('kError'), + template: $translate.instant('kMontageNoSavedProfiles') + }); + return; + } + + $scope.data = { + 'selectedVal': '' + }; + + $rootScope.zmPopup = SecuredPopups.show('confirm', + { + template: '<ion-list> ' + + ' <ion-radio-fix ng-repeat="item in listdata" ng-value="item" ng-model="data.selectedVal"> ' + + ' {{item}} ' + + ' </ion-item> ' + + '</ion-list> ', + + title: $translate.instant('kSelect'), + scope: $scope, + + }).then(function(res) + { + if (res) + { + //console.log ("SELECTED " + $scope.data.selectedVal); + var ld = NVRDataModel.getLogin(); + //console.log ("OLD POS="+ld.packeryPositions); + ld.packeryPositions = ld.packeryPositionsArray[$scope.data.selectedVal]; + //console.log ("NEW POS="+ld.packeryPositions); + NVRDataModel.setLogin(ld); + NVRDataModel.reloadMonitorDisplayStatus(); + draggies.forEach(function(drag) + { + drag.destroy(); + }); + draggies = []; + pckry.destroy(); + initPackery(); + //pckry.reloadItems(); + } + + }); + + }; + + // save current configuration into a profile + $scope.saveMontageProfile = function() + { + $scope.data = { + montageName: "" + }; + $rootScope.zmPopup = SecuredPopups.show('confirm', + { + title: $translate.instant('kMontageSave'), + template: "<input autocapitalize='none' autocomplete='off' autocorrect='off' type='text' ng-model='data.montageName'>", + subTitle: $translate.instant('kMontageSaveSubtitle'), + scope: $scope, + + }).then(function(res) + { + console.log(res); + if (res) // ok + { + + var ld = NVRDataModel.getLogin(); + + if ($scope.data.montageName != '') + { + var pos = JSON.stringify(pckry.getShiftPositions('data-item-id')); + ld.packeryPositionsArray[$scope.data.montageName] = pos; + NVRDataModel.debug("Saving " + $scope.data.montageName + " with:" + pos); + NVRDataModel.setLogin(ld); + } + + } + }); + + }; + $scope.toggleSizeButtons = function() { @@ -1196,10 +1361,15 @@ angular.module('zmApp.controllers') ld.packeryPositions = JSON.stringify(positions); //console.log ("Saving " + ld.packeryPositions); NVRDataModel.setLogin(ld); + + $timeout(function() + { + NVRDataModel.debug("doing the jiggle and dance..."); + pckry.resize(true); + }, 300); + // $scope.slider.monsize = 2; }); - //layout(pckry); - pckry.layout(); }, 20); diff --git a/www/lang/locale-en.json b/www/lang/locale-en.json index 951edb38..33ecc8a8 100644 --- a/www/lang/locale-en.json +++ b/www/lang/locale-en.json @@ -203,6 +203,9 @@ "kMonitors" :"Monitors", "kMontage" :"Montage", "kMontageImageScale" :"Montage image scale", + "kMontageNoSavedProfiles" :"No saved montage profiles", + "kMontageSave" :"Save Montage Profile", + "kMontageSaveSubtitle" :"please enter a profile name to save current settings", "kMonth" :"Month", "kMore" :"more", "kNeedToKnow" :"I need to know your ZoneMinder login and path details to get started", @@ -284,6 +287,7 @@ "kSearch" :"search", "kSearchCancelled" :"search cancelled", "kSec" :"sec", + "kSelect" :"Please Select", "kSelectFallback" :"Select fallback", "kSelectLanguage" :"Select Language", "kSelectRunState" :"Select run state", diff --git a/www/templates/montage.html b/www/templates/montage.html index ceab34ae..3bb62104 100644 --- a/www/templates/montage.html +++ b/www/templates/montage.html @@ -3,7 +3,7 @@ <button class="button button-icon button-clear ion-navicon" ng-click="openMenu()"></button> <button class="button button-icon button-clear ion-eye" ng-click="hideUnhide();"> </button> - <button class="button button-icon button-clear ion-arrow-resize" ng-click="toggleSizeButtons();"> + <button class="button button-icon button-clear ion-android-more-vertical" ng-click="toggleSizeButtons();"> </button> <button data-badge="{{$root.alarmCount}}" class="animated infinite tada button button-icon button-clear ion-ios-bell notification-badge" ng-click="handleAlarms();" ng-if="$root.isAlarm"></button> </ion-nav-buttons> @@ -23,14 +23,49 @@ </button> </ion-nav-buttons> <ion-content scroll-sista ng-cloak has-bouncing="false" style="background-color:#444444" delegate-handle="montage-delegate" overflow-scroll="false"> - <span ng-if="!minimal && showSizeButtons"> + <div ng-if="!minimal && showSizeButtons" > <!-- this is header --> + <br/> + <div id="flyoutmenu" style="float:left"> + <ul> + <li> + <a href="" ng-click="sliderChanged(1)"> <i class="ion-plus-circled"></i></a> + </li> + <li> + <a href="" ng-click="sliderChanged(-1)"> <i class="ion-minus-circled"></i></a> + </li> + </ul> + </div> + + <div id="flyoutmenu" style="float:right"> + <ul> + <li> + <a href="" ng-click="switchMontageProfile()"> <i class="ion-navicon-round"></i></a> + </li> + + <li> + <a href="" ng-click="saveMontageProfile()"> <i class="ion-heart"></i></a> + </li> + + <li> + <a href="" ng-click="deleteMontageProfile()"> <i class="ion-trash-a"></i></a> + </li> + + + </ul> + </div> + <div style="clear: both;"></div> + + <!-- <span ng-click="sliderChanged(1)" style="float:right;margin-top:0px;padding-top:8px;background-color:#5c6767;color:#fff;font-size:25px;opacity:1;width:40px;height:36px;border-radius: 0px 0px 0px 5px;"> <i class="ion-plus-circled"> </i></span> + - <span ng-click="sliderChanged(1)" style="float:right;margin-top:0px;padding-top:8px;background-color:#5c6767;color:#fff;font-size:25px;opacity:1;width:40px;height:36px;border-radius: 0px 0px 0px 5px;"> <i class="ion-plus-circled"> </i></span> <span ng-click="sliderChanged(-1)" style="float:left;margin-top:0px;padding-top:8px;background-color:#5c6767;color:#fff;font-size:22px;opacity:1;width:40px;height:36px;border-radius: 0px 0px 5px 0px;"> <i class="ion-minus-circled"> </i></span> + + <span ng-click="" style="left:50%;margin-top:0px;padding-top:8px;background-color:#5c6767;color:#fff;font-size:11px;opacity:1;width:40px;height:36px;border-radius: 0px 0px 0px 5px;"> <i class="ion-plus-circled"> hello</i></span> + --> + <br/> - <br/> - </span> + </div> <!-- now lets draw the montage windows --> <div class="grid" id="mygrid"> <div class="grid-sizer grid-item-10"></div> |
