Introduced floating panel with options on element click instead of the double-click-to-play logic on media elements

This commit is contained in:
Fabio Manganiello 2019-02-09 01:53:14 +01:00
parent 434bc8a5eb
commit cd49f22d5c
4 changed files with 161 additions and 67 deletions

View file

@ -77,18 +77,12 @@ form#video-ctrl {
100% { background: #d4ffe3; } 100% { background: #d4ffe3; }
} }
button.remote[data-panel-toggle="#media-devices-panel"] { button.remote[data-panel="#media-devices-panel"] {
color: #34b868; color: #34b868;
} }
button.selected[data-panel-toggle="#media-devices-panel"] { #media-devices-panel,
box-shadow: inset 0 2px 0 rgba(0,0,0,0.1), #media-item-panel {
inset 3px 0 0 rgba(0,0,0,0.1),
inset 0 0 2px rgba(0,0,0,0.1),
inset 0 0 0 1px rgba(0,0,0,0.1);
}
#media-devices-panel {
display: none; display: none;
position: absolute; position: absolute;
padding: 1rem; padding: 1rem;
@ -112,7 +106,8 @@ form#video-ctrl {
right: .5rem; right: .5rem;
} }
#media-devices-panel * > .cast-device { #media-devices-panel * > .cast-device,
#media-item-panel > .media-item-action {
padding: 0.5rem; padding: 0.5rem;
cursor: pointer; cursor: pointer;
} }
@ -128,16 +123,19 @@ form#video-ctrl {
} }
#media-devices-panel * > .cast-device.disabled, #media-devices-panel * > .cast-device.disabled,
#media-devices-panel * > .refresh-devices.disabled { #media-devices-panel * > .refresh-devices.disabled,
#media-item-panel > .media-item-action.disabled {
cursor: default; cursor: default;
color: #999 !important; color: #999 !important;
} }
#media-devices-panel * > .cast-device:hover { #media-devices-panel * > .cast-device:hover,
#media-item-panel > .media-item-action:hover {
background-color: #daf8e2 !important; background-color: #daf8e2 !important;
} }
#media-devices-panel * > .cast-device-icon { #media-devices-panel * > .cast-device-icon
#media-item-panel > .media-item-item {
color: #666; color: #666;
} }

View file

@ -184,16 +184,49 @@ $(document).ready(function() {
}); });
}; };
var initPanelOpenBindings = function() {
$('body').on('mouseup touchend', '[data-panel]', function(event) {
var $source = $(event.target);
var $panel = $($source.data('panel'));
setTimeout(() => {
$panel.show();
}, 200);
});
};
var initPanelCloseBindings = function() {
$('body').on('mouseup touchend', function(event) {
var $source = $(event.target);
if ($source.data('panel') || $source.parents('[data-panel]').length) {
var $panel = $source.data('panel') ? $($source.data('panel')) :
$($source.parents('[data-panel]').data('panel'));
$panel.toggle();
return;
}
if (!$source.parents('.panel').length
&& !$source.data('panel')) {
$('.panel').filter(':visible').hide();
}
});
};
var initModals = function() { var initModals = function() {
initModalOpenBindings(); initModalOpenBindings();
initModalCloseBindings(); initModalCloseBindings();
}; };
var initPanels = function() {
initPanelOpenBindings();
initPanelCloseBindings();
};
var init = function() { var init = function() {
initWebsocket(); initWebsocket();
initElements(); initElements();
initDateTime(); initDateTime();
initModals(); initModals();
initPanels();
}; };
window.registerEventListener = registerEventListener; window.registerEventListener = registerEventListener;

View file

@ -6,12 +6,14 @@ $(document).ready(function() {
$ctrlForm = $('#video-ctrl'), $ctrlForm = $('#video-ctrl'),
$devsPanel = $('#media-devices-panel'), $devsPanel = $('#media-devices-panel'),
$devsList = $devsPanel.find('.devices-list'), $devsList = $devsPanel.find('.devices-list'),
$devsBtn = $('button[data-panel-toggle="#media-devices-panel"]'), $devsBtn = $('button[data-panel="#media-devices-panel"]'),
$devsBtnIcon = $('#media-devices-panel-icon'), $devsBtnIcon = $('#media-devices-panel-icon'),
$devsRefreshBtn = $devsPanel.find('.refresh-devices'), $devsRefreshBtn = $devsPanel.find('.refresh-devices'),
$searchBarContainer = $('#media-search-bar-container'), $searchBarContainer = $('#media-search-bar-container'),
$mediaBtnsContainer = $('#media-btns-container'), $mediaBtnsContainer = $('#media-btns-container'),
prevVolume = undefined; $mediaItemPanel = $('#media-item-panel'),
prevVolume = undefined,
selectedResource = undefined;
var updateVideoResults = function(videos) { var updateVideoResults = function(videos) {
$videoResults.html(''); $videoResults.html('');
@ -19,6 +21,7 @@ $(document).ready(function() {
var $videoResult = $('<div></div>') var $videoResult = $('<div></div>')
.addClass('video-result') .addClass('video-result')
.attr('data-url', video['url']) .attr('data-url', video['url'])
.attr('data-panel', '#media-item-panel')
.html('title' in video ? video['title'] : video['url']); .html('title' in video ? video['title'] : video['url']);
var $icon = getVideoIconByUrl(video['url']); var $icon = getVideoIconByUrl(video['url']);
@ -132,6 +135,67 @@ $(document).ready(function() {
}); });
}; };
var play = function(resource) {
return new Promise((resolve, reject) => {
var results = $videoResults.html();
var onVideoLoading = function() {
$videoResults.text('Loading video...');
};
var onVideoReady = function() {
$videoResults.html(results);
};
var requestArgs = {
type: 'request',
action: 'media.play',
args: { resource: resource },
};
var selectedDevice = getSelectedDevice();
if (selectedDevice.isBrowser) {
onVideoLoading();
startStreaming(resource)
.then((url) => {
window.open(url, '_blank');
resolve(url);
})
.catch((xhr, status, error) => {
reject(xhr.responseText);
})
.finally(() => {
onVideoReady();
});
return;
}
if (selectedDevice.isRemote) {
requestArgs.action = 'media.chromecast.play';
requestArgs.args.chromecast = selectedDevice.name;
}
onVideoLoading();
execute(
requestArgs,
function(response) {
$videoResults.html(results);
resolve(resource);
},
function(xhr, status, error) {
onVideoReady();
reject(xhr.responseText);
}
);
});
};
var download = function(resource) {
// TODO
};
var initBindings = function() { var initBindings = function() {
$searchForm.on('submit', function(event) { $searchForm.on('submit', function(event) {
var $input = $(this).find('input[name=video-search-text]'); var $input = $(this).find('input[name=video-search-text]');
@ -221,66 +285,29 @@ $(document).ready(function() {
); );
}); });
$videoResults.on('click touch', '.video-result', function(evt) { $videoResults.on('mousedown touchstart', '.video-result', function() {
var results = $videoResults.html(); selectedResource = $(this).data('url');
});
$videoResults.on('mouseup touchend', '.video-result', function(event) {
var $item = $(this); var $item = $(this);
if (!$item.hasClass('selected')) { var resource = $item.data('url');
$item.siblings().removeClass('selected'); if (resource !== selectedResource) {
$item.addClass('selected'); return; // Did not really click this item
return false;
} }
var onVideoLoading = function() { $item.siblings().removeClass('selected');
$videoResults.text('Loading video...'); $item.addClass('selected');
};
var onVideoReady = function() { $mediaItemPanel.css('top', (event.clientY + $(window).scrollTop()) + 'px');
$videoResults.html(results); $mediaItemPanel.css('left', (event.clientX + $(window).scrollLeft()) + 'px');
}; $mediaItemPanel.data('resource', resource);
var resource = $item.data('url')
var requestArgs = {
type: 'request',
action: 'media.play',
args: { resource: resource },
};
var selectedDevice = getSelectedDevice();
if (selectedDevice.isBrowser) {
onVideoLoading();
startStreaming(resource)
.then((url) => { window.open(url, '_blank'); })
.finally(() => { onVideoReady(); });
return;
}
if (selectedDevice.isRemote) {
requestArgs.action = 'media.chromecast.play';
requestArgs.args.chromecast = selectedDevice.name;
}
onVideoLoading();
execute(
requestArgs,
function() {
$videoResults.html(results);
$item.siblings().removeClass('active');
$item.addClass('active');
},
function() {
onVideoReady();
}
);
}); });
$devsBtn.on('click touch', function() { $devsBtn.on('click touch', function() {
$(this).toggleClass('selected'); $(this).toggleClass('selected');
$devsPanel.css('top', ($(this).position().top + $(this).outerHeight()) + 'px'); $devsPanel.css('top', ($(this).position().top + $(this).outerHeight()) + 'px');
$devsPanel.css('left', ($(this).position().left) + 'px'); $devsPanel.css('left', ($(this).position().left) + 'px');
$devsPanel.toggle();
return false; return false;
}); });
@ -318,6 +345,26 @@ $(document).ready(function() {
$(this).addClass('disabled'); $(this).addClass('disabled');
initRemoteDevices(); initRemoteDevices();
}); });
$mediaItemPanel.on('click', '[data-action]', function() {
if ($(this).hasClass('disabled')) {
return;
}
var action = $(this).data('action');
var resource = $mediaItemPanel.data('resource');
if (!resource) {
return;
}
$mediaItemPanel.hide();
$mediaItemPanel.find('[data-action]').addClass('disabled');
eval(action)($mediaItemPanel.data('resource'))
.finally(() => {
$mediaItemPanel.find('[data-action]').removeClass('disabled');
});
});
}; };
var initRemoteDevices = function() { var initRemoteDevices = function() {

View file

@ -17,13 +17,13 @@
<button type="submit"> <button type="submit">
<i class="fa fa-search"></i> <i class="fa fa-search"></i>
</button> </button>
<button data-panel-toggle="#media-devices-panel"> <button data-panel="#media-devices-panel">
<i id="media-devices-panel-icon" class="fa fa-desktop"></i> <i id="media-devices-panel-icon" class="fa fa-desktop"></i>
</button> </button>
</div> </div>
</div> </div>
<div class="row" id="media-devices-panel"> <div class="row panel" id="media-devices-panel">
<div class="refresh-devices-container"> <div class="refresh-devices-container">
<div class="row refresh-devices disabled"> <div class="row refresh-devices disabled">
<i class="fa fa-retweet"></i> <i class="fa fa-retweet"></i>
@ -98,6 +98,22 @@
</div> </div>
</form> </form>
<div class="row panel" id="media-item-panel">
<div class="row media-item-action" data-action="play">
<div class="two columns media-item-icon">
<i class="fa fa-play"></i>
</div>
<div class="ten columns">Play</div>
</div>
<div class="row media-item-action" data-action="download">
<div class="two columns">
<i class="fa fa-download"></i>
</div>
<div class="ten columns">Download</div>
</div>
</div>
<div class="row" id="video-results-container"> <div class="row" id="video-results-container">
<div id="video-results"></div> <div id="video-results"></div>
</div> </div>