Introduced floating panel with options on element click instead of the double-click-to-play logic on media elements
This commit is contained in:
parent
434bc8a5eb
commit
cd49f22d5c
4 changed files with 161 additions and 67 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue