diff --git a/definitions/en_CA.js b/definitions/en_CA.js
index d1dd1a60..738e49b2 100644
--- a/definitions/en_CA.js
+++ b/definitions/en_CA.js
@@ -7608,6 +7608,11 @@ module.exports = function(s,config,lang){
`,
pageOpen: 'monitorsList',
},
+ {
+ icon: 'map-marker',
+ label: `${lang['Power Viewer']}`,
+ pageOpen: 'powerVideo',
+ },
{
icon: 'wrench',
label: `${lang['Monitor Settings']}`,
@@ -7792,5 +7797,203 @@ module.exports = function(s,config,lang){
}
}
},
+ "Power Viewer": {
+ "section": lang["Power Viewer"],
+ "blocks": {
+ "Search Settings": {
+ id: "powerVideoTabs",
+ "color": "blue",
+ noHeader: true,
+ attribute: `tab-chooser-parent`,
+ "section-pre-class": "col-md-4",
+ "info": [
+ {
+ "color": "blue",
+ noHeader: true,
+ isSection: true,
+ isFormGroupGroup: true,
+ "info": [
+ {
+ "fieldType": "btn-group",
+ "btns": [
+ {
+ "fieldType": "btn",
+ "class": `btn-primary btn-sm`,
+ "attribute": `tab-chooser="monitors"`,
+ "btnContent": `${lang['Monitors']}`,
+ },
+ {
+ "fieldType": "btn",
+ "class": `btn-primary btn-sm`,
+ "attribute": `tab-chooser="settings"`,
+ "btnContent": `${lang['Search Settings']}`,
+ },
+ ],
+ },
+ ]
+ },
+ {
+ "name": lang["Monitors"],
+ "color": "blue",
+ noId: true,
+ isFormGroupGroup: true,
+ attribute: `tab-section="monitors"`,
+ "info": [
+ {
+ "id": "powerVideoMonitorsList",
+ "fieldType": "div",
+ "class": "list-group",
+ },
+ ]
+ },
+ {
+ hidden: true,
+ "name": lang["Search Settings"],
+ "color": "blue",
+ noId: true,
+ isFormGroupGroup: true,
+ attribute: `tab-section="settings"`,
+ "info": [
+ {
+ "id": "powerVideoDateRange",
+ "field": lang['Date Range'],
+ },
+ {
+ "id": "powerVideoVideoLimit",
+ "field": lang['Video Limit'] + ` (${lang['Per Monitor']})`,
+ "placeholder": "0",
+ },
+ {
+ "id": "powerVideoEventLimit",
+ "field": lang['Event Limit'] + ` (${lang['Per Monitor']})`,
+ "placeholder": "500",
+ },
+ {
+ id:'powerVideoSet',
+ field: lang['Video Set'],
+ default:'h264',
+ "fieldType": "select",
+ possible:[
+ {
+ "name": lang.Local,
+ "value": "local"
+ },
+ {
+ "name": lang.Cloud,
+ "value": "cloud"
+ },
+ ]
+ },
+ ]
+ },
+ ]
+ },
+ "Video Playback": {
+ id: "powerVideoVideoPlayback",
+ noHeader: true,
+ "color": "green",
+ "section-pre-class": "col-md-8 search-parent",
+ "info": [
+ {
+ "id": "powerVideoMonitorViews",
+ "fieldType": "div",
+ },
+ {
+ "id": "powerVideoMonitorControls",
+ "color": "blue",
+ noHeader: true,
+ isSection: true,
+ isFormGroupGroup: true,
+ 'section-class': 'text-center',
+ "info": [
+ {
+ "fieldType": "btn-group",
+ "btns": [
+ {
+ "fieldType": "btn",
+ "class": `btn-default btn-sm`,
+ "attribute": `powerVideo-control="toggleZoom" title="${lang['Zoom In']}"`,
+ "btnContent": ``,
+ },
+ ],
+ },
+ {
+ "fieldType": "btn-group",
+ "btns": [
+ {
+ "fieldType": "btn",
+ "class": `btn-default btn-sm`,
+ "attribute": `powerVideo-control="previousVideoAll" title="${lang['Previous Video']}"`,
+ "btnContent": ``,
+ },
+ {
+ "fieldType": "btn",
+ "class": `btn-danger btn-sm`,
+ "attribute": `powerVideo-control="playAll" title="${lang['Play']}"`,
+ "btnContent": ``,
+ },
+ {
+ "fieldType": "btn",
+ "class": `btn-default btn-sm`,
+ "attribute": `powerVideo-control="pauseAll" title="${lang['Pause']}"`,
+ "btnContent": ``,
+ },
+ {
+ "fieldType": "btn",
+ "class": `btn-default btn-sm`,
+ "attribute": `powerVideo-control="nextVideoAll" title="${lang['Next Video']}"`,
+ "btnContent": ``,
+ },
+ ],
+ },
+ {
+ "fieldType": "btn-group",
+ "style": "font-family: monospace;",
+ "btns": [
+ {
+ "fieldType": "btn",
+ "class": `btn-default btn-sm`,
+ "attribute": `powerVideo-control="playSpeedAll" data-speed="1"`,
+ "btnContent": `1`,
+ },
+ {
+ "fieldType": "btn",
+ "class": `btn-default btn-sm`,
+ "attribute": `powerVideo-control="playSpeedAll" data-speed="5"`,
+ "btnContent": `5`,
+ },
+ {
+ "fieldType": "btn",
+ "class": `btn-default btn-sm`,
+ "attribute": `powerVideo-control="playSpeedAll" data-speed="10"`,
+ "btnContent": `10`,
+ },
+ {
+ "fieldType": "btn",
+ "class": `btn-default btn-sm`,
+ "attribute": `powerVideo-control="playSpeedAll" data-speed="15"`,
+ "btnContent": `15`,
+ },
+ ],
+ },
+ ]
+ },
+ ]
+ },
+ "Time Strip": {
+ id: "powerVideoTimelineStripsContainer",
+ noHeader: true,
+ "color": "green",
+ "section-pre-class": "col-md-12 mt-3",
+ "info": [
+ {
+ "id": "powerVideoTimelineStrips",
+ "fieldType": "div",
+ "divContent": `
${lang['Select a Monitor']}
`,
+ },
+ ]
+ }
+ }
+ },
})
}
diff --git a/languages/en_CA.json b/languages/en_CA.json
index b4a8dab1..4c1232b6 100644
--- a/languages/en_CA.json
+++ b/languages/en_CA.json
@@ -1241,5 +1241,6 @@
"Motion Threshold":"Motion Threshold",
"Attach Snapshot": "Attach Snapshot",
"Invalid Settings": "Invalid Settings",
- "Detection": "Detection"
+ "Detection": "Detection",
+ "Cloud": "Cloud"
}
diff --git a/web/assets/css/bs5.powerVideo.css b/web/assets/css/bs5.powerVideo.css
new file mode 100644
index 00000000..59973929
--- /dev/null
+++ b/web/assets/css/bs5.powerVideo.css
@@ -0,0 +1,177 @@
+#powerVideo .videoPlayer {
+ text-align: center;
+ display: inline-block;
+ position: relative;
+}
+#powerVideo .videoPlayer video{
+ max-width: 100%;
+ height: 300px;
+ object-fit: fill;
+}
+
+#powerVideo .videoPlayer:fullscreen video{
+ height: 100%;
+ max-height: 100%;
+}
+
+#powerVideoMonitorControls{
+ border-radius: 0 0 5px 5px;
+ padding: 5px;
+ background: #222;
+ margin: 0;
+}
+
+#powerVideoMonitorsList{
+ margin: 0;
+}
+
+#powerVideoMonitorsList .list-item{
+ cursor: pointer;
+}
+
+#powerVideoMonitorViews {
+ text-align: center;
+ min-height: 300px;
+ background: #444;
+ border-radius: 5px 5px 0 0;
+ overflow: hidden;
+}
+
+#powerVideo .videoPlayer .videoPlayer-detection-info {
+ position: absolute;
+ padding: 20px 10px 20px 10px;
+ height: 100%;
+ width: 100%;
+ top: 0;
+ left: 0;
+ margin: auto;
+ z-index: 11;
+ opacity: 0;
+ background: rgba(0,0,0,0.7);
+ color: #fff;
+ font-family: monospace;
+ overflow: auto;
+ text-align: left;
+}
+
+#powerVideo .videoPlayer:hover .videoPlayer-detection-info,
+#powerVideo .videoPlayer.show-detection-info .videoPlayer-detection-info {
+ opacity: 1
+}
+
+#powerVideo .videoPlayer .videoPlayer-stream-objects {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ right: 0;
+ margin: auto;
+ z-index: 10;
+}
+
+#powerVideo .videoPlayer .videoPlayer-detection-info-object div {
+ padding-left: 5px;
+}
+
+#powerVideo .videoPlayer .videoPlayer-detection-info-object {
+ text-align: left
+}
+
+.videoPlayer-stream-objects .tag {
+ position: absolute;
+ bottom: 100%;
+ left: 0;
+ background: red;
+ color: #fff;
+ font-family: monospace;
+ font-size: 80%;
+ border-radius: 5px 5px 0 0;
+ padding: 3px 5px;
+}
+
+.videoPlayer-stream-objects .stream-detected-object {
+ position: absolute;
+ top: 0;
+ left: 0;
+ border: 3px solid red;
+ background: transparent;
+ border-radius: 5px
+}
+
+.videoPlayer-stream-objects .stream-detected-point {
+ position: absolute;
+ top: 0;
+ left: 0;
+ border: 3px solid yellow;
+ background: transparent;
+ border-radius: 5px
+}
+
+.videoPlayer-stream-objects .point {
+ position: absolute;
+ top: 0;
+ left: 0;
+ border: 3px solid red;
+ border-radius: 50%
+}
+
+/* loading */
+#powerVideo .loading {
+ font-size: 20pt;
+ text-align: center;
+}
+#powerVideo .loading > div {
+ margin-top: 5px
+}
+
+/* VIS.js */
+
+#powerVideo video {
+ width: 100%;
+ padding: 6px 0 0 0
+}
+
+#powerVideo .videoAfter,
+#powerVideo .videoBefore {
+ display: none;
+}
+
+#powerVideo .vis-timeline {
+ font-family: monospace;
+ border-radius: 5px;
+ border-color: #172b4d;
+}
+#powerVideo .vis-item {
+ border-color: #347af1;
+ background-color: #4d87d0;
+ color: #fff;
+}
+#powerVideo .vis-item.vis-selected {
+ border-color: #f5365c;
+ background-color: #f5365c;
+ color: #fff;
+}
+#powerVideo .vis-panel.vis-bottom {
+ border: 1px #17294b;
+}
+#powerVideo .vis-time-axis .vis-grid.vis-minor{
+ border-color: #1a539a;
+}
+#powerVideo .vis-time-axis .vis-grid.vis-major {
+ border-color: #4d87d0;
+}
+#powerVideo .vis-time-axis .vis-text {
+ color: #fff;
+}
+
+[timeline-video-file] .progress{
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 3px;
+ opacity: 0;
+}
+.vis-selected [timeline-video-file] .progress{
+ opacity: 1;
+}
diff --git a/web/assets/js/bs5.dashboard-base.js b/web/assets/js/bs5.dashboard-base.js
index f78a800b..4540a71a 100644
--- a/web/assets/js/bs5.dashboard-base.js
+++ b/web/assets/js/bs5.dashboard-base.js
@@ -851,6 +851,17 @@ $(document).ready(function(){
else
$(this).show();
});
+ })
+ .on('click','[tab-chooser]',function(){
+ var el = $(this)
+ var parent = el.parents('[tab-chooser-parent]')
+ var tabName = el.attr('tab-chooser')
+ var allTabChoosersInParent = parent.find('[tab-chooser]')
+ var allTabsInParent = parent.find('[tab-section]')
+ allTabsInParent.hide()
+ allTabChoosersInParent.removeClass('active')
+ el.addClass('active')
+ parent.find(`[tab-section="${tabName}"]`).show()
});
$('.logout').click(function(e){
$.get(getApiPrefix() + '/logout/' + $user.ke + '/' + $user.uid,function(data){
diff --git a/web/assets/js/bs5.monitorsUtils.js b/web/assets/js/bs5.monitorsUtils.js
index a0d5d463..f834902f 100644
--- a/web/assets/js/bs5.monitorsUtils.js
+++ b/web/assets/js/bs5.monitorsUtils.js
@@ -553,6 +553,120 @@ function buildDefaultMonitorMenuItems(){
${lang['Watch-Only']}
${lang.Record}`
}
+function magnifyStream(options){
+ if(!options.p && !options.parent){
+ var el = $(this),
+ parent = el.parents('[mid]')
+ }else{
+ parent = options.p || options.parent
+ }
+ if(!options.attribute){
+ options.attribute = ''
+ }
+ if(options.animate === true){
+ var zoomGlassAnimate = 'animate'
+ }else{
+ var zoomGlassAnimate = 'css'
+ }
+ if(!options.magnifyOffsetElement){
+ options.magnifyOffsetElement = '.stream-block'
+ }
+ if(!options.targetForZoom){
+ options.targetForZoom = '.stream-element'
+ }
+ if(options.auto === true){
+ var streamBlockOperator = 'position'
+ }else{
+ var streamBlockOperator = 'offset'
+ }
+ var magnifiedElement
+ if(!options.videoUrl){
+ if(options.useCanvas === true){
+ magnifiedElement = 'canvas'
+ }else{
+ magnifiedElement = 'iframe'
+ }
+ }else{
+ magnifiedElement = 'video'
+ }
+ if(!options.mon && !options.monitor){
+ var groupKey = parent.attr('ke')//group key
+ var monitorId = parent.attr('mid')//monitor id
+ var sessionKey = parent.attr('auth')//authkey
+ var monitor = $.ccio.mon[groupKey + monitorId + sessionKey]//monitor configuration
+ }else{
+ var monitor = options.mon || options.monitor
+ var groupKey = monitor.ke//group key
+ var monitorId = monitor.mid//monitor id
+ var sessionKey = monitor.auth//authkey
+ }
+ if(options.zoomAmount)zoomAmount = 3
+ if(!zoomAmount)zoomAmount = 3
+ var realHeight = parent.attr('realHeight')
+ var realWidth = parent.attr('realWidth')
+ var height = parseFloat(realHeight) * zoomAmount//height of stream
+ var width = parseFloat(realWidth) * zoomAmount//width of stream
+ var targetForZoom = parent.find(options.targetForZoom)
+ zoomGlass = parent.find(".zoomGlass")
+ var zoomFrame = function(){
+ var magnify_offset = parent.find(options.magnifyOffsetElement)[streamBlockOperator]()
+ var mx = options.pageX - magnify_offset.left
+ var my = options.pageY - magnify_offset.top
+ var rx = Math.round(mx/targetForZoom.width()*width - zoomGlass.width()/2)*-1
+ var ry = Math.round(my/targetForZoom.height()*height - zoomGlass.height()/2)*-1
+ var px = mx - zoomGlass.width()/2
+ var py = my - zoomGlass.height()/2
+ zoomGlass[zoomGlassAnimate]({left: px, top: py}).find(magnifiedElement)[zoomGlassAnimate]({left: rx, top: ry})
+ }
+ var commit = function(height,width){
+ zoomGlass.find(magnifiedElement).css({
+ height: height,
+ width: width
+ })
+ zoomFrame()
+ }
+ if(!height || !width || zoomGlass.length === 0){
+ zoomGlass = parent.find(".zoomGlass")
+ var zoomGlassShell = function(contents){return `${contents}
`}
+ if(!options.videoUrl){
+ $.ccio.snapshot(monitor,function(url,buffer,w,h){
+ parent.attr('realWidth',w)
+ parent.attr('realHeight',h)
+ if(zoomGlass.length === 0){
+ if(options.useCanvas === true){
+ parent.append(zoomGlassShell(''))
+ }else{
+ parent.append(zoomGlassShell(''))
+ }
+ zoomGlass = parent.find(".zoomGlass")
+ }
+ commit(h,w)
+ })
+ }else{
+ if(zoomGlass.length === 0){
+ parent.append(zoomGlassShell(``))
+ }
+ if(options.setTime){
+ var video = zoomGlass.find('video')[0]
+ video.currentTime = options.setTime
+ height = video.videoHeight
+ width = video.videoWidth
+ parent.attr('realWidth',width)
+ parent.attr('realHeight',height)
+ }
+ commit(height,width)
+ }
+ }else{
+ if(options.setTime){
+ var video = zoomGlass.find('video')
+ var src = video.attr('src')
+ video[0].currentTime = options.setTime
+ if(options.videoUrl !== src)zoomGlass.html(``)
+ }
+ commit(height,width)
+ }
+}
+
$(document).ready(function(){
$('body')
.on('click','[system]',function(){
diff --git a/web/assets/js/bs5.powerVideo.js b/web/assets/js/bs5.powerVideo.js
new file mode 100644
index 00000000..d8e4fc4b
--- /dev/null
+++ b/web/assets/js/bs5.powerVideo.js
@@ -0,0 +1,679 @@
+$(document).ready(function(e){
+ var powerVideoWindow = $('#powerVideo')
+ var powerVideoMonitorsListElement = $('#powerVideoMonitorsList')
+ var powerVideoMonitorViewsElement = $('#powerVideoMonitorViews')
+ var powerVideoTimelineStripsContainer = $('#powerVideoTimelineStrips')
+ var powerVideoDateRangeElement = $('#powerVideoDateRange')
+ var powerVideoVideoLimitElement = $('#powerVideoVideoLimit')
+ var powerVideoEventLimitElement = $('#powerVideoEventLimit')
+ var powerVideoSet = $('#powerVideoSet')
+ var powerVideoLoadedVideos = {}
+ var powerVideoLoadedEvents = {}
+ var powerVideoLoadedChartData = {}
+ var loadedTableGroupIds = {}
+ var eventsLabeledByTime = {}
+ var monitorSlotPlaySpeeds = {}
+ var currentlyPlayingVideos = {}
+ var extenders = {
+ onVideoPlayerTimeUpdateExtensions: [],
+ onVideoPlayerTimeUpdate: function(extender){
+ extenders.onVideoPlayerTimeUpdateExtensions.push(extender)
+ },
+ onVideoPlayerCreateExtensions: [],
+ onVideoPlayerCreate: function(extender){
+ extenders.onVideoPlayerCreateExtensions.push(extender)
+ },
+ }
+ var activeTimeline = null
+ // fix utc/localtime translation (use timelapseJpeg as guide, it works as expected) >
+ powerVideoDateRangeElement.daterangepicker({
+ startDate: moment().subtract(moment.duration("24:00:00")),
+ endDate: moment().add(moment.duration("24:00:00")),
+ timePicker: true,
+ timePicker24Hour: true,
+ timePickerSeconds: true,
+ timePickerIncrement: 30,
+ locale: {
+ format: 'DD/MM/YYYY h:mm A'
+ }
+ },function(start, end, label){
+ // $.pwrvid.drawTimeline()
+ powerVideoDateRangeElement.focus()
+ getSelectedMonitors().each(function(n,activeElement){
+ var monitorId = $(activeElement).attr('data-monitor')
+ requestTableData(monitorId)
+ })
+ });
+ // fix utc/localtime translation (use timelapseJpeg as guide, it works as expected) />
+ var loadVideosToTimeLineMemory = function(monitorId,videos,events){
+ powerVideoLoadedVideos[monitorId] = videos
+ powerVideoLoadedEvents[monitorId] = events
+ }
+ var drawMonitorsList = function(){
+ var html = ''
+ $.each(loadedMonitors,function(n,monitor){
+ html += `${monitor.name}
`
+ })
+ powerVideoMonitorsListElement.html(html)
+ }
+ var requestTableData = function(monitorId,user){
+ if(!user)user = $user
+ var dateData = powerVideoDateRangeElement.data('daterangepicker')
+ mainSocket.f({
+ f: 'monitor',
+ ff: 'get',
+ fff: 'videos&events',
+ videoSet: powerVideoSet.val() || '',
+ videoLimit: parseInt(powerVideoVideoLimitElement.val()) || 0,
+ eventLimit: parseInt(powerVideoEventLimitElement.val()) || 500,
+ startDate: dateData.startDate.clone().utc().format('YYYY-MM-DDTHH:mm:ss'),
+ endDate: dateData.endDate.clone().utc().format('YYYY-MM-DDTHH:mm:ss'),
+ ke: user.ke,
+ mid: monitorId
+ })
+ }
+ var unloadTableData = function(monitorId,user){
+ if(!user)user = $user
+ delete(powerVideoLoadedVideos[monitorId])
+ delete(powerVideoLoadedEvents[monitorId])
+ delete(loadedTableGroupIds[monitorId])
+ delete(loadedTableGroupIds[monitorId + '_events'])
+ powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid="${monitorId}"]`).remove()
+ drawLoadedTableData()
+ }
+ var checkEventsAgainstVideo = function(video,events){
+ var videoStartTime = new Date(video.time)
+ var videoEndTime = new Date(video.end)
+ var eventsToCheck = events
+ video.detections = {}
+ var newSetOfEventsWithoutChecked = {}
+ $.each(eventsToCheck,function(n,event){
+ var eventTime = new Date(event.time)
+ var seekPosition = (eventTime - videoStartTime) / 1000
+ if (videoStartTime <= eventTime && eventTime <= videoEndTime) {
+ if(!video.details.confidence)video.details.confidence = 0
+ video.detections[seekPosition] = event
+ eventsLabeledByTime[video.mid][video.time][seekPosition] = event
+ }else{
+ newSetOfEventsWithoutChecked[n] = video
+ }
+ })
+ eventsToCheck = newSetOfEventsWithoutChecked
+ }
+ var prepareVideosAndEventsForTable = function(monitorId,videos,events){
+ var chartData = []
+ eventsLabeledByTime[monitorId] = {}
+ $.each(videos,function(n,video){
+ eventsLabeledByTime[monitorId][video.time] = {}
+ if(videos[n - 1])video.videoAfter = videos[n - 1]
+ if(videos[n + 1])video.videoBefore = videos[n + 1]
+ checkEventsAgainstVideo(video,events)
+ chartData.push({
+ group: loadedTableGroupIds[monitorId],
+ content: ``,
+ start: video.time,
+ end: video.end,
+ videoInfo: video
+ })
+ })
+ $.each(events,function(n,event){
+ var eventReason = event.details && event.details.reason ? event.details.reason.toUpperCase() : "UNKNOWN"
+ var eventSlotTag = eventReason
+ if(eventReason === 'OBJECT' && event.details.matrices && event.details.matrices[0]){
+ eventSlotTag = []
+ event.details.matrices.forEach(function(matrix){
+ eventSlotTag.push(matrix.tag)
+ })
+ eventSlotTag = eventSlotTag.join(', ')
+ }
+ chartData.push({
+ group: loadedTableGroupIds[monitorId + '_events'],
+ content: `${eventSlotTag}
`,
+ start: event.time,
+ eventInfo: event
+ })
+ })
+ return chartData
+ }
+ var getMiniEventsChartConfig = function(video){
+ var monitorId = video.mid
+ var labels = []
+ var chartData = []
+ var events = video.detections
+ $.each(events,function(n,v){
+ if(!v.details.confidence){v.details.confidence=0}
+ var time = moment(v.time).format('MM/DD/YYYY HH:mm:ss')
+ labels.push(time)
+ chartData.push(v.details.confidence)
+ })
+ var timeFormat = 'MM/DD/YYYY HH:mm:ss';
+ Chart.defaults.global.defaultFontColor = '#fff';
+ var config = {
+ type: 'bar',
+ data: {
+ labels: labels,
+ datasets: [{
+ type: 'line',
+ label: 'Motion Confidence',
+ backgroundColor: window.chartColors.blue,
+ borderColor: window.chartColors.red,
+ data: chartData,
+ }]
+ },
+ options: {
+ maintainAspectRatio: false,
+ title: {
+ fontColor: "white",
+ text:"Events in this video"
+ },
+ scales: {
+ xAxes: [{
+ type: "time",
+ display: true,
+ time: {
+ format: timeFormat,
+ }
+ }],
+ },
+ }
+ };
+ return config
+ }
+ var drawMiniEventsChart = function(video,chartConfig){
+ var videoContainer = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${video.mid}]`)
+ var canvas = videoContainer.find('canvas')
+ var ctx = canvas[0].getContext("2d")
+ var miniChart = new Chart(ctx, chartConfig)
+ canvas.click(function(f) {
+ var target = miniChart.getElementsAtEvent(f)[0];
+ if(!target){return false}
+ var event = video.detections[target._index]
+ var video1 = videoContainer.find('video')[0]
+ video1.currentTime = moment(event.time).diff(moment(video.time),'seconds')
+ video1.play()
+ })
+ }
+ var getAllChartDataForLoadedVideos = function(){
+ var chartData = []
+ Object.keys(powerVideoLoadedVideos).forEach(function(monitorId,n){
+ var videos = powerVideoLoadedVideos[monitorId]
+ var events = powerVideoLoadedEvents[monitorId]
+ var parsedVideos = prepareVideosAndEventsForTable(monitorId,videos,events)
+ powerVideoLoadedChartData[monitorId] = parsedVideos
+ chartData = chartData.concat(parsedVideos)
+ })
+ return chartData
+ }
+ var visuallySelectItemInRow = function(video){
+ powerVideoTimelineStripsContainer.find(`[timeline-video-file="${video.mid}${video.time}"]`).parents('.vis-item').addClass('vis-selected')
+ }
+ var visuallyDeselectItemInRow = function(video){
+ powerVideoTimelineStripsContainer.find(`[timeline-video-file="${video.mid}${video.time}"]`).parents('.vis-item').removeClass('vis-selected')
+ }
+ var drawTableTimeout = null
+ var drawLoadedTableData = function(){
+ // destroy old
+ try{
+ if(activeTimeline && activeTimeline.destroy){
+ activeTimeline.destroy()
+ }
+ }catch(err){
+
+ }
+ //
+ powerVideoTimelineStripsContainer.html(`${lang['Please Wait...']}
`)
+ clearTimeout(drawTableTimeout)
+ drawTableTimeout = setTimeout(function(){
+ var container = powerVideoTimelineStripsContainer[0]
+ var groupsDataSet = new vis.DataSet()
+ var groups = []
+ var groupId = 1
+ Object.keys(powerVideoLoadedVideos).forEach(function(monitorId,n){
+ groups.push({
+ id: groupId,
+ content: monitorId
+ })
+ groupId += 1
+ groups.push({
+ id: groupId,
+ content: lang.Events
+ })
+ groupId += 1
+ loadedTableGroupIds[monitorId] = groupId - 2
+ loadedTableGroupIds[monitorId + '_events'] = groupId - 1
+ })
+ groupsDataSet.add(groups)
+ var chartData = getAllChartDataForLoadedVideos()
+ if(chartData.length > 0){
+ var items = new vis.DataSet(chartData)
+ var options = {
+ selectable: false,
+ stack: false,
+ showCurrentTime: false,
+ }
+ // Create a Timeline
+ var timeline = new vis.Timeline(container, items, groupsDataSet, options)
+ powerVideoTimelineStripsContainer.find('.loading').remove()
+ var timeChanging = false
+ timeline.on('rangechange', function(properties){
+ timeChanging = true
+ })
+ timeline.on('rangechanged', function(properties){
+ setTimeout(function(){
+ timeChanging = false
+ },300)
+ })
+ timeline.on('click', function(properties){
+ if(!timeChanging){
+ var selectedTime = properties.time
+ var videosAtSameTime = findAllVideosAtTime(selectedTime)
+ powerVideoTimelineStripsContainer.find('.vis-item').removeClass('vis-selected')
+ $.each(videosAtSameTime,function(monitorId,videos){
+ var selectedVideo = videos[0]
+ if(selectedVideo){
+ loadVideoIntoMonitorSlot(selectedVideo,selectedTime)
+ visuallySelectItemInRow(selectedVideo)
+ }
+ })
+ }
+ })
+ activeTimeline = timeline
+ }else{
+ powerVideoTimelineStripsContainer.html(``)
+ }
+ },1000)
+ }
+ var drawMatrices = function(event,options){
+ var streamObjectsContainer = options.streamObjectsContainer
+ var height = options.height
+ var width = options.width
+ var monitorId = options.mid
+ var widthRatio = width / event.details.imgWidth
+ var heightRatio = height / event.details.imgHeight
+
+ streamObjectsContainer.find('.stream-detected-object[name="'+event.details.name+'"]').remove()
+ var html = ''
+ $.each(event.details.matrices,function(n,matrix){
+ html += ``
+ if(matrix.tag)html += `${matrix.tag}`
+ html += '
'
+ })
+ streamObjectsContainer.append(html)
+ }
+ var attachEventsToVideoActiveElement = function(video){
+ var monitorId = video.mid
+ var videoPlayerContainer = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${monitorId}]`)
+ var videoElement = videoPlayerContainer.find(`video.videoNow`)
+ var streamObjectsContainer = videoPlayerContainer.find(`.videoPlayer-stream-objects`)
+ var detectionInfoContainerMotion = videoPlayerContainer.find(`.videoPlayer-detection-info-motion`)
+ var detectionInfoContainerObject = videoPlayerContainer.find(`.videoPlayer-detection-info-object`)
+ var detectionInfoContainerRaw = videoPlayerContainer.find(`.videoPlayer-detection-info-raw`)
+ var motionMeterProgressBar = videoPlayerContainer.find(`.videoPlayer-motion-meter .progress-bar`)
+ var motionMeterProgressBarTextBox = videoPlayerContainer.find(`.videoPlayer-motion-meter .progress-bar span`)
+ var videoCurrentTimeProgressBar = powerVideoTimelineStripsContainer.find(`[timeline-video-file="${video.mid}${video.time}"] .progress-bar`)[0]
+ var preloadedNext = false
+ var reinitializeStreamObjectsContainer = function(){
+ height = videoElement.height()
+ width = videoElement.width()
+ }
+ reinitializeStreamObjectsContainer()
+ $(videoElement)
+ .resize(reinitializeStreamObjectsContainer)
+ // .off('loadeddata').on('loadeddata', function() {
+ // reinitializeStreamObjectsContainer()
+ // var allLoaded = true
+ // getAllActiveVideosInSlots().each(function(n,videoElement){
+ // if(!videoElement.readyState === 4)allLoaded = false
+ // })
+ // setTimeout(function(){
+ // if(allLoaded){
+ // playAllSlots()
+ // }
+ // },1500)
+ // })
+ // .off("pause").on("pause",function(){
+ // console.log(monitorId,'pause')
+ // })
+ // .off("play").on("play",function(){
+ // console.log(monitorId,'play')
+ // })
+ .off("timeupdate").on("timeupdate",function(){
+ var event = eventsLabeledByTime[monitorId][video.time][parseInt(this.currentTime)]
+ if(event){
+ if(event.details.matrices){
+ drawMatrices(event,{
+ streamObjectsContainer: streamObjectsContainer,
+ monitorId: monitorId,
+ height: height,
+ width: width,
+ })
+ detectionInfoContainerObject.html(jsonToHtmlBlock(event.details.matrices))
+ }
+ if(event.details.confidence){
+ motionMeterProgressBar.css('width',event.details.confidence+'%')
+ motionMeterProgressBarTextBox.text(event.details.confidence)
+ var html = `${lang['Region']} : ${event.details.name}
+ ${lang['Confidence']} : ${event.details.confidence}
+ ${lang['Plugin']} : ${event.details.plug}
`
+ detectionInfoContainerMotion.html(html)
+ // detectionInfoContainerRaw.html(jsonToHtmlBlock({`${lang['Plug']}`:event.details.plug}))
+ }
+ }
+ var currentTime = this.currentTime;
+ var watchPoint = Math.floor((currentTime/this.duration) * 100)
+ if(!preloadedNext && watchPoint >= 75){
+ preloadedNext = true
+ var videoAfter = videoPlayerContainer.find(`video.videoAfter`)[0]
+ videoAfter.setAttribute('preload',true)
+ }
+ if(videoCurrentTimeProgressBar)videoCurrentTimeProgressBar.style.width = `${watchPoint}%`
+ extenders.onVideoPlayerTimeUpdateExtensions.forEach(function(extender){
+ extender(videoElement,watchPoint)
+ })
+ })
+ var onEnded = function() {
+ visuallyDeselectItemInRow(video)
+ if(video.videoAfter){
+ visuallySelectItemInRow(video.videoAfter)
+ loadVideoIntoMonitorSlot(video.videoAfter)
+ }
+ }
+ videoElement[0].onended = onEnded
+ videoElement[0].onerror = onEnded
+ }
+ var dettachEventsToVideoActiveElement = function(monitorId){
+ var videoElement = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${monitorId}] video.videoNow`)
+ $(videoElement)
+ // .off('loadeddata')
+ .off("pause")
+ .off("play")
+ .off("timeupdate")
+ }
+ var findAllVideosAtTime = function(selectedTime){
+ var time = new Date(selectedTime)
+ var parsedVideos = {}
+ $.each(powerVideoLoadedVideos,function(monitorId,videos){
+ var videosFilteredByTime = videos.filter(function(video){
+ return (
+ (new Date(video.time)) <= time && time < (new Date(video.end))
+ )
+ });
+ parsedVideos[monitorId] = videosFilteredByTime
+ })
+ return parsedVideos
+ }
+ var resetVisualDetectionDataForMonitorSlot = function(monitorId){
+ var videoPlayerContainer = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${monitorId}]`)
+ var streamObjectsContainer = videoPlayerContainer.find(`.videoPlayer-stream-objects`)
+ var detectionInfoContainerObject = videoPlayerContainer.find(`.videoPlayer-detection-info-object`)
+ var detectionInfoContainerMotion = videoPlayerContainer.find(`.videoPlayer-detection-info-motion`)
+ var motionMeterProgressBar = videoPlayerContainer.find(`.videoPlayer-motion-meter .progress-bar`)
+ var motionMeterProgressBarTextBox = videoPlayerContainer.find(`.videoPlayer-motion-meter .progress-bar span`)
+ detectionInfoContainerObject.empty()
+ detectionInfoContainerMotion.empty()
+ streamObjectsContainer.empty()
+ motionMeterProgressBar.css('width','0')
+ motionMeterProgressBarTextBox.text('0')
+ }
+ var loadVideoIntoMonitorSlot = function(video,selectedTime){
+ if(!video)return
+ resetVisualDetectionDataForMonitorSlot(video.mid)
+ currentlyPlayingVideos[video.mid] = video
+ var timeToStartAt = selectedTime - new Date(video.time)
+ var numberOfMonitors = Object.keys(powerVideoLoadedVideos).length
+ // if(numberOfMonitors > 3)numberOfMonitors = 3 //start new row after 3
+ if(numberOfMonitors == 1)numberOfMonitors = 2 //make single monitor not look like a doofus
+ if(timeToStartAt < 0)timeToStartAt = 0
+ var widthOfBlock = 100 / numberOfMonitors
+ var videoContainer = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${video.mid}] .videoPlayer-buffers`)
+ if(videoContainer.length === 0){
+ if(!monitorSlotPlaySpeeds)monitorSlotPlaySpeeds[video.mid] = {}
+ powerVideoMonitorViewsElement.append(``)
+ videoContainer = powerVideoMonitorViewsElement.find(`.videoPlayer[data-mid=${video.mid}] .videoPlayer-buffers`)
+ }else{
+ powerVideoMonitorViewsElement.find('.videoPlayer').css('width',`${widthOfBlock}%`)
+ }
+ var videoCurrentNow = videoContainer.find('.videoNow')
+ var videoCurrentAfter = videoContainer.find('.videoAfter')
+ // var videoCurrentBefore = videoContainer.find('.videoBefore')
+ dettachEventsToVideoActiveElement(video.mid)
+ videoContainer.find('video').each(function(n,v){
+ v.pause()
+ })
+ var videoIsSame = (video.href == videoCurrentNow.attr('video'))
+ var videoIsAfter = (video.href == videoCurrentAfter.attr('video'))
+ // var videoIsBefore = (video.href == videoCurrentBefore.attr('video'))
+ var drawVideoHTML = function(position){
+ var videoData
+ var exisitingElement = videoContainer.find('.' + position)
+ if(position){
+ videoData = video[position]
+ }else{
+ position = 'videoNow'
+ videoData = video
+ }
+ if(videoData){
+ videoContainer.append('')
+ }
+ }
+ if(
+ videoIsSame ||
+ videoIsAfter
+ // || videoIsBefore
+ ){
+ switch(true){
+ case videoIsSame:
+ var videoNow = videoContainer.find('video.videoNow')[0]
+ if(!videoNow.paused)videoNow.pause()
+ videoNow.currentTime = timeToStartAt / 1000
+ if(videoNow.paused)videoNow.play()
+ return
+ break;
+ case videoIsAfter:
+ // videoCurrentBefore.remove()
+ videoCurrentNow.remove()
+ videoCurrentAfter.removeClass('videoAfter').addClass('videoNow')
+ // videoCurrentNow.removeClass('videoNow').addClass('videoBefore')
+ drawVideoHTML('videoAfter')
+ break;
+ // case videoIsBefore:
+ // videoCurrentAfter.remove()
+ // videoCurrentBefore.removeClass('videoBefore').addClass('videoNow')
+ // videoCurrentNow.removeClass('videoNow').addClass('videoAfter')
+ // drawVideoHTML('videoBefore')
+ // break;
+ }
+ }else{
+ videoContainer.empty()
+ drawVideoHTML()//videoNow
+ // drawVideoHTML('videoBefore')
+ drawVideoHTML('videoAfter')
+ }
+ var videoNow = videoContainer.find('video.videoNow')[0]
+ attachEventsToVideoActiveElement(video)
+ //
+ videoNow.setAttribute('preload',true)
+ videoNow.muted = true
+ videoNow.playbackRate = monitorSlotPlaySpeeds[video.mid] || 1
+ videoNow.currentTime = timeToStartAt / 1000
+ videoNow.play()
+ extenders.onVideoPlayerCreateExtensions.forEach(function(extender){
+ extender(videoElement,watchPoint)
+ })
+ drawMiniEventsChart(video,getMiniEventsChartConfig(video))
+ }
+ var getSelectedMonitors = function(){
+ return powerVideoMonitorsListElement.find('.active')
+ }
+ var getAllActiveVideosInSlots = function(){
+ return powerVideoMonitorViewsElement.find('video.videoNow')
+ }
+ var pauseAllSlots = function(){
+ getAllActiveVideosInSlots().each(function(n,video){
+ if(!video.paused)video.pause()
+ })
+ }
+ var toggleZoomAllSlots = function(){
+ powerVideoMonitorViewsElement.find(`.videoPlayer`).each(function(n,videoContainer){
+ var streamWindow = $(videoContainer)
+ var monitorId = streamWindow.attr('data-mid')
+ var enabled = streamWindow.attr('zoomEnabled')
+ if(enabled === '1'){
+ streamWindow
+ .attr('zoomEnabled','0')
+ .off('mouseover')
+ .off('mouseout')
+ .off('mousemove')
+ .off('touchmove')
+ .find('.zoomGlass').remove()
+ }else{
+ const magnifyStream = function(e){
+ var videoElement = streamWindow.find('video.videoNow')
+ console.log(videoElement[0].currentTime)
+ magnifyStream({
+ p: streamWindow,
+ videoUrl: streamWindow.find('video.videoNow').find('source').attr('src'),
+ setTime: videoElement[0].currentTime,
+ monitor: loadedMonitors[monitorId],
+ targetForZoom: 'video.videoNow',
+ magnifyOffsetElement: '.videoPlayer-buffers',
+ zoomAmount: 1,
+ auto: false,
+ animate: false,
+ pageX: e.pageX,
+ pageY: e.pageY
+ },$user)
+ }
+ streamWindow
+ .attr('zoomEnabled','1')
+ .on('mouseover', function(){
+ streamWindow.find(".zoomGlass").show()
+ })
+ .on('mouseout', function(){
+ streamWindow.find(".zoomGlass").hide()
+ })
+ .on('mousemove', magnifyStream)
+ .on('touchmove', magnifyStream)
+ }
+ })
+ }
+ var playAllSlots = function(){
+ getAllActiveVideosInSlots().each(function(n,video){
+ if(video.paused)video.play()
+ })
+ }
+ var setPlaySpeedOnAllSlots = function(playSpeed){
+ Object.keys(powerVideoLoadedVideos).forEach(function(monitorId){
+ monitorSlotPlaySpeeds[monitorId] = playSpeed
+ })
+ getAllActiveVideosInSlots().each(function(n,video){
+ video.playbackRate = playSpeed
+ })
+ }
+ var nextVideoAllSlots = function(){
+ Object.keys(currentlyPlayingVideos).forEach(function(monitorId){
+ var video = currentlyPlayingVideos[monitorId]
+ visuallyDeselectItemInRow(video)
+ visuallySelectItemInRow(video.videoAfter)
+ loadVideoIntoMonitorSlot(video.videoAfter,0)
+ })
+ }
+ var previousVideoAllSlots = function(){
+ Object.keys(currentlyPlayingVideos).forEach(function(monitorId){
+ var video = currentlyPlayingVideos[monitorId]
+ visuallyDeselectItemInRow(video)
+ visuallySelectItemInRow(video.videoBefore)
+ loadVideoIntoMonitorSlot(video.videoBefore,0)
+ })
+ }
+ onWebSocketEvent(function (d){
+ switch(d.f){
+ case'videos&events':
+ if(tabTree.name === 'powerVideo'){
+ var videos = d.videos.videos
+ var events = d.events
+ loadVideosToTimeLineMemory(d.id,videos,events)
+ drawLoadedTableData()
+ }
+ break;
+ }
+ })
+ $('body')
+ .on('dblclick','.videoPlayer',function(){
+ var el = $(this)
+ $('.videoPlayer-detection-info').addClass('hide')
+ fullScreenInit(this)
+ })
+ .on('click','[data-monitor]',function(){
+ var el = $(this)
+ var monitorId = el.attr('data-monitor')
+ el.toggleClass('active')
+ if(el.hasClass('active')){
+ requestTableData(monitorId)
+ }else{
+ unloadTableData(monitorId)
+ }
+ })
+ .on('click','[powerVideo-control]',function(){
+ var el = $(this)
+ var controlType = el.attr('powerVideo-control')
+ switch(controlType){
+ case'toggleZoom':
+ toggleZoomAllSlots()
+ break;
+ case'playAll':
+ playAllSlots()
+ break;
+ case'pauseAll':
+ pauseAllSlots()
+ break;
+ case'playSpeedAll':
+ var playSpeed = el.attr('data-speed')
+ setPlaySpeedOnAllSlots(playSpeed)
+ break;
+ case'previousVideoAll':
+ playAllSlots()
+ previousVideoAllSlots()
+ break;
+ case'nextVideoAll':
+ playAllSlots()
+ nextVideoAllSlots()
+ break;
+ }
+ });
+
+ addOnTabOpen('powerVideo', function () {
+ drawMonitorsList()
+ })
+ // addOnTabReopen('powerVideo', function () {
+ // drawMonitorsList()
+ // })
+ $.powerVideoViewer = {
+ window: powerVideoWindow,
+ drawMonitorsList: drawMonitorsList,
+ activeTimeline: activeTimeline,
+ monitorListElement: powerVideoMonitorsListElement,
+ monitorViewsElement: powerVideoMonitorViewsElement,
+ timelineStripsElement: powerVideoTimelineStripsContainer,
+ dateRangeElement: powerVideoDateRangeElement,
+ loadedVideos: powerVideoLoadedVideos,
+ loadedEvents: powerVideoLoadedEvents,
+ loadedChartData: powerVideoLoadedChartData,
+ loadedTableGroupIds: loadedTableGroupIds,
+ extenders: extenders
+ }
+})
diff --git a/web/pages/blocks/home.ejs b/web/pages/blocks/home.ejs
index 250649d3..15c4cbdf 100644
--- a/web/pages/blocks/home.ejs
+++ b/web/pages/blocks/home.ejs
@@ -19,6 +19,7 @@
'home/timelapseViewer',
'home/eventFilters',
'home/cameraProbe',
+ 'home/powerVideo',
'home/onvifScanner',
'home/configFinder',
'home/logViewer',
diff --git a/web/pages/blocks/home/fieldBuilders.ejs b/web/pages/blocks/home/fieldBuilders.ejs
index 24ba17b1..4e22903b 100644
--- a/web/pages/blocks/home/fieldBuilders.ejs
+++ b/web/pages/blocks/home/fieldBuilders.ejs
@@ -37,11 +37,11 @@ drawBlock = function(monitorSettings){
if(monitorSettings.attribute){
attributes.push(monitorSettings.attribute)
}
- if(!monitorSettings.id){
+ if(!monitorSettings.noId && !monitorSettings.id && monitorSettings.name){
var userSettingsId = monitorSettings.name.replace(/[^a-zA-Z ]/g, '').replace(/[^a-zA-Z ]/g, '').replace(/ /g, '')
monitorSettings.id = userSettingsId
}
- attributes.push(`id="${monitorSettings.id}"`)
+ if(monitorSettings.id)attributes.push(`id="${monitorSettings.id}"`);
if(monitorSettings.color){
sectionClass.push(monitorSettings.color)
}
@@ -97,197 +97,213 @@ drawBlock = function(monitorSettings){
drawBlock(settingsBlock)
})
}
- if(monitorSettings.info){
- monitorSettings.info.forEach(function(field){
- let evaluation = `${field.evaluation || ''}`
- if(field.ejs){
- try{ %>
- <%- include(`${__dirname}/${field.ejs}.ejs`) %>
- <% }catch(err){
- console.log(err)
+ if(monitorSettings.info){
+ function drawInfoItem(field){
+ let evaluation = `${field.evaluation || ''}`
+ if(field.ejs){
+ try{ %>
+ <%- include(`${__dirname}/${field.ejs}.ejs`) %>
+ <% }catch(err){
+ console.log(err)
+ }
+ }else if(field.isFormGroupGroup === true){
+ drawBlock(field)
+ }else{
+ if(field.notForSubAccount === true){
+ var notForSubAccount = '!details.sub'
+ if(!field.evaluation){
+ evaluation = notForSubAccount
+ }else{
+ evaluation += ' && ' + notForSubAccount
}
- }else if(field.isFormGroupGroup === true){
- drawBlock(field)
- }else{
- if(field.notForSubAccount === true){
- var notForSubAccount = '!details.sub'
- if(!field.evaluation){
- evaluation = notForSubAccount
- }else{
- evaluation += ' && ' + notForSubAccount
- }
- }
- if(evaluation && !eval(evaluation)){
- return
- }
- var hidden = ''
- if(field.hidden === true){
- hidden = 'style="display:none"'
- }
- var fieldClass = []
- var attributes = []
- if(field.name && field.name.indexOf('=') > -1){
- attributes.push(field.name)
- }else if(field.name){
- attributes.push("name=" + field.name)
- }
- if(field.placeholder || field.default){
- attributes.push(`placeholder="${field.placeholder || field.default}"`)
- }else if(field.example){
- attributes.push(`placeholder="Example : ${field.example}"`)
- }
- if(field.default){
- attributes.push(`data-default="${field.default}"`)
- }
- if(field.attribute){
- attributes.push(field.attribute)
- }
- if(field.selector){
- attributes.push(`selector="${field.selector}"`)
- }
- if(field.id){
- attributes.push(`id="${field.id}"`)
- }
- if(field.class){
- fieldClass.push(`${field.class}`)
- }
- var possiblities = field.possible || []
- var fieldType = field.fieldType || 'text'
- var fieldElement = ''
- var preFill = field.preFill || ''
- switch(fieldType){
- case'btn-group':
- let fieldBtnContent = ``
- field.btns.forEach((btn) => {
- let btnClass = []
- let btnAttributes = []
- const btnBaseElement = btn.forForm || field.forForm ? 'button' : 'a'
- if(btn.class){
- btnClass.push(`${btn.class}`)
- }
- if(btn.attribute){
- btnAttributes.push(btn.attribute)
- }
- fieldBtnContent += `<${btnBaseElement} class="btn ${btnClass.join(' ')}" ${btnAttributes.join(' ')}>${btn.btnContent}${btnBaseElement}>`
- })
- fieldElement = `${fieldBtnContent}
`
- break;
- case'btn':
- baseElement = field.forForm ? 'button' : 'a'
- fieldElement = `<${baseElement} class="btn btn-block ${fieldClass.join(' ')}" ${attributes.join(' ')}>${field.btnContent}${baseElement}>`
- break;
- case'ul':
- fieldElement = ``
- break;
- case'div':
- fieldElement = `${field.divContent || ''}
`
- break;
- case'iconCard':
- fieldElement = `
-
-
${field.label}
-
-
${field.text}
-
-
-
-
`
- break;
- case'indicatorBar':
- fieldElement = `
-
-
-
-
-
- ${field.label}
-
-
-
-
-
-
-
`
- break;
- case'form':
- fieldElement = ``
- break;
- case'table':
- fieldElement = ``
- break;
- case'number':
- if(field.numberMin){
- attributes.push(`min="${field.numberMin}"`)
- }
- if(field.numberMax){
- attributes.push(`max="${field.numberMax}"`)
- }
- fieldElement = `'
- break;
- case'password':
- fieldElement = `'
- break;
- case'text':
- fieldElement = ``
- break;
- case'range':
- fieldElement = ``
- break;
- case'textarea':
- fieldElement = `'
- break;
- case'select':
- fieldElement = `'
- break;
- }
- if(field['form-group-class-pre-pre-layer']){ %>
-
<%- monitorSettings.isForm ? 'form' : 'div' %>>
diff --git a/web/pages/blocks/home/powerVideo.ejs b/web/pages/blocks/home/powerVideo.ejs
new file mode 100644
index 00000000..d12e3189
--- /dev/null
+++ b/web/pages/blocks/home/powerVideo.ejs
@@ -0,0 +1,19 @@
+
+
+ <%
+ var drawBlock
+ var buildOptions
+ %>
+ <%
+ include fieldBuilders.ejs
+ %>
+ <% Object.keys(define['Power Viewer'].blocks).forEach(function(blockKey){
+ var theBlock = define['Power Viewer'].blocks[blockKey]
+ drawBlock(theBlock)
+ }) %>
+
+
+
+
+
+