Merge branch 'SouthRidge_video_app'
|
@ -0,0 +1,33 @@
|
|||
# South Ridge Video (video app)
|
||||
|
||||
[![SouthRidge](http://imgur.com/3lSmSJd.png)](https://www.youtube.com/watch?v=6kv3qyCdc1E)
|
||||
|
||||
South Ridge Video, an open source video app developed as a hosted web application built with React.js, and hosted on a web server. South Ridge can easily be converted to a UWP application that takes advantage of native platform capabilities and can be distributed through the Windows Store as any other UWP app.
|
||||
|
||||
Read the [full blog post](https://blogs.windows.com/buildingapps/2016/09/30/uwp-hosted-web-app-on-xbox-one-app-dev-on-xbox-series) or visit the [App Dev on Xbox landing page](http://aka.ms/xboxappdev) for more videos and blogs.
|
||||
|
||||
## Setup
|
||||
|
||||
The app is hosted at [http://southridge.azurewebsites.net](http://southridge.azurewebsites.net) for this example but you can deploy it yourself to any backend you choose. Once the app is hosted, all you need is the url to create app packages.
|
||||
|
||||
1. Use [manifoldJS](http://manifoldjs.com/) from the command line on any platform npm is supported, or through the [web](http://manifoldjs.com/generator). In this example, we are using the npm generator from the command line.
|
||||
|
||||
*install manifoldjs*
|
||||
```
|
||||
npm install -g manifoldjs
|
||||
```
|
||||
|
||||
*generate package*
|
||||
```
|
||||
manifoldjs http://southridge.azurewebsites.net/
|
||||
```
|
||||
|
||||
2. To deploy the package to the Xbox, first make sure your Xbox is in [Dev Mode](https://msdn.microsoft.com/en-us/windows/uwp/xbox-apps/devkit-activation). You can then use the [Windows Device Portal (WDP)](https://msdn.microsoft.com/en-us/windows/uwp/debug-test-perf/device-portal) through a web browser to configure and manage the Xbox. [Follow these steps to enable WDP on your Xbox](https://msdn.microsoft.com/en-us/windows/uwp/debug-test-perf/device-portal-xbox?f=255&MSPPError=-2147217396). Launch WDP in your favourite browser and navigate to the Apps tab.
|
||||
|
||||
3. Under the *Install app* section, click on *Browse* next to *pick a loose folder*
|
||||
|
||||
4. Navigate to the *windows10* folder from the packages you generated with manifoldJS and select the *manifest* folder
|
||||
|
||||
5. Click the *Go* button to upload the loose files and install the app. Once this is complete, you will be able to find and launch the app on your Xbox
|
||||
|
||||
6. Enjoy!
|
|
@ -0,0 +1,377 @@
|
|||
/*this is phone size */
|
||||
@media screen and (min-width:300px) and (max-width:799px) {
|
||||
@-ms-viewport {
|
||||
width: 360px;
|
||||
}
|
||||
.movieListing .movieSection{
|
||||
|
||||
padding: 12px 0 12px 16px;
|
||||
}
|
||||
|
||||
/*player part */
|
||||
#page .playMovie {
|
||||
padding: 72px 16px 12px 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
#page #videoContainer{
|
||||
xwidth: 100%;
|
||||
}
|
||||
#page .movieText{
|
||||
margin-left: 0px;
|
||||
}
|
||||
#page .movieText h2{
|
||||
margin: 12px 0;
|
||||
}
|
||||
.movieTextWrapper{
|
||||
height: 100px;
|
||||
overflow: scroll;
|
||||
}
|
||||
#page .lowerDetailsWrapper{
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
#page .additionalDetailWrapper{
|
||||
margin: 12px 16px;
|
||||
}
|
||||
#page .additionalDetailWrapper .detailBlock{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
#page .additionalDetailWrapper h4{
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
#page .moviePlayer{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#page .overArrow {
|
||||
display: none;
|
||||
}
|
||||
#page .movieBox{
|
||||
width: 198px;
|
||||
height: 100px;
|
||||
|
||||
}
|
||||
#page .movieBoxContainer{
|
||||
margin-top: 4px;
|
||||
|
||||
}
|
||||
.logoBox .logo { display: none}
|
||||
.controls button {
|
||||
width: 120px;
|
||||
height: 32px;
|
||||
}
|
||||
#page .controls h1{
|
||||
font-size: 24px;
|
||||
}
|
||||
#page .logoBox {
|
||||
padding: 40px 16px;
|
||||
}
|
||||
#page .topSection{
|
||||
height: 424px;
|
||||
|
||||
}
|
||||
#page .heroBox{
|
||||
height: 296px;
|
||||
padding: 64px 16px;
|
||||
}
|
||||
|
||||
}
|
||||
/*end phone size */
|
||||
|
||||
|
||||
/*this is tablet size */
|
||||
@media screen and (min-width:800px) and (max-width:1279px) {
|
||||
@-ms-viewport {
|
||||
width: 1024px;
|
||||
}
|
||||
.movieListing .movieSection{
|
||||
padding-right: 126px;
|
||||
}
|
||||
|
||||
#page .topSection{
|
||||
height: 424px;
|
||||
|
||||
}
|
||||
#page .heroBox{
|
||||
height: 296px;
|
||||
}
|
||||
#page .moviePlayer{
|
||||
height: 260px;
|
||||
width: 520px;
|
||||
}
|
||||
}
|
||||
/*end tablet size */
|
||||
|
||||
|
||||
/*this is Xbox size */
|
||||
@media screen and (min-width:1280px) and (max-width:1365px){
|
||||
@-ms-viewport {
|
||||
width: 1280px;
|
||||
}
|
||||
.movieListing .movieSection{
|
||||
padding-right: 0;
|
||||
}
|
||||
#page .overArrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body{
|
||||
xmargin:-400px;
|
||||
}
|
||||
}
|
||||
|
||||
/*end Xbox size */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*this is the desktoop size */
|
||||
@media screen and (min-width:1366px) {
|
||||
@-ms-viewport {
|
||||
width: 1366px;
|
||||
}
|
||||
.movieListing .movieSection{
|
||||
padding-right: 146px;
|
||||
}
|
||||
}
|
||||
/*END desktoop size */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
body{
|
||||
background-color: #1F213A;
|
||||
color: white;
|
||||
font-family: 'SegoeUIMonoW01-Regular', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
touch-action: pan-y;
|
||||
-ms-overflow-style: none;
|
||||
overflow-x:hidden;
|
||||
|
||||
}
|
||||
|
||||
.logoBox{
|
||||
position: absolute;
|
||||
width:100%;
|
||||
padding: 64px;
|
||||
display: flex;
|
||||
z-index: 11;
|
||||
}
|
||||
.logoBox div{
|
||||
margin-right: 40px;
|
||||
}
|
||||
.logoBox .logo{
|
||||
margin-right: 68px;
|
||||
height: 56px;
|
||||
margin-top: -30px;
|
||||
}
|
||||
|
||||
#page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap ;
|
||||
align-items: stretch;
|
||||
align-content: space-between;
|
||||
}
|
||||
.topSection{
|
||||
height: 564px;
|
||||
margin-bottom:0em;
|
||||
background: linear-gradient(to bottom, rgba(65,102,97,0) 0%,rgba(65,102,97,0) 32%,rgba(65,102,97,1) 99%,rgba(65,102,97,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
|
||||
}
|
||||
.heroBox {
|
||||
height: 436px;
|
||||
padding: 64px;
|
||||
opacity:.7;
|
||||
background-image:url('http://adx.metulev.com/video/Images/Clean/Large/FeaturedImage_2x1_Image04.jpg');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.movieListing{
|
||||
display: flex;
|
||||
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
.movieBoxContainer{
|
||||
margin:16px 16px 0 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
.movieBox {
|
||||
width: 276px;
|
||||
height: 140px;
|
||||
background-color:#32474F;
|
||||
margin-bottom: 8px;
|
||||
flex-shrink:0;
|
||||
background-size: cover;
|
||||
border: 0;
|
||||
display: block;
|
||||
padding:0;
|
||||
}
|
||||
.movieBox:focus span, .movieBox:active span{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('/images/play.png');
|
||||
background-size: cover;
|
||||
display: inline-block;
|
||||
background-position: center center;
|
||||
opacity: .5;
|
||||
margin:0;
|
||||
padding:0;
|
||||
|
||||
|
||||
}
|
||||
.heroBox .controls{
|
||||
width:29em;
|
||||
margin-bottom:30px;
|
||||
}
|
||||
.controls h1{
|
||||
margin-bottom:20px;
|
||||
font-size: 34px;
|
||||
}
|
||||
.controls span{
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.bottomSection{
|
||||
flex-grow: 1;
|
||||
xheight:100%;
|
||||
xpadding: 40px 68px;
|
||||
}
|
||||
.movieSection{
|
||||
overflow:hidden;
|
||||
padding: 40px 68px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.movieSection .list{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow-x: scroll;
|
||||
overflow-y:hidden;
|
||||
xwidth:2000px;
|
||||
justify-content: left;
|
||||
margin-top:8px;
|
||||
}
|
||||
.movieSection h4{
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.movieSection:nth-of-type(2), .movieSection:nth-of-type(5) {
|
||||
background-color:#283444;
|
||||
}
|
||||
.movieSection:nth-of-type(4){
|
||||
background-color:#2f404b;
|
||||
}
|
||||
|
||||
.movieSection:nth-of-type(2) .movieBoxContainer:first-child .movieBox, .movieSection:nth-of-type(5) .movieBoxContainer:first-child .movieBox{
|
||||
width: 568px;
|
||||
height: 320px;
|
||||
}
|
||||
.movieSection:nth-of-type(2) .list, .movieSection:nth-of-type(5) .list{
|
||||
flex-direction: column;
|
||||
max-height:450px;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
|
||||
}
|
||||
.movieBoxContainer:last-child { padding-right: 200px;}
|
||||
|
||||
.playMovie {
|
||||
padding-bottom: 44px;
|
||||
padding-top: 140px;
|
||||
padding: 140px 100px 44px 64px;
|
||||
xheight: 25em;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.moviePlayer{
|
||||
height:380px;
|
||||
width:760px;
|
||||
background-color: black;
|
||||
flex-shrink:0;
|
||||
background-size: contain;
|
||||
|
||||
}
|
||||
.movieText {
|
||||
margin: 0 0 0 56px;
|
||||
font-size: 12px;
|
||||
|
||||
}
|
||||
|
||||
.movieText h2{
|
||||
margin-bottom:24px;
|
||||
}
|
||||
|
||||
.movieText p {
|
||||
margin-bottom: 20px;
|
||||
xtext-align: justify;
|
||||
}
|
||||
.movieText .playInfo {
|
||||
text-align: left;
|
||||
}
|
||||
.controls button{
|
||||
|
||||
font-family: 'SegoeMDL2';
|
||||
}
|
||||
.controls button:focus{
|
||||
outline: none;
|
||||
background-color: #32474F;
|
||||
}
|
||||
|
||||
.additionalDetailWrapper{
|
||||
margin:40px 64px;
|
||||
|
||||
}
|
||||
.additionalDetailWrapper h4{
|
||||
font-size: 15px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.additionalDetailWrapper .lowerDetailsWrapper {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
line-height: 20px;
|
||||
font-size: 12px;
|
||||
|
||||
}
|
||||
.detailBlock {
|
||||
margin-right: 84px;
|
||||
width: 230px;
|
||||
}
|
||||
|
||||
.overArrow{
|
||||
position: absolute;
|
||||
top: 48%;
|
||||
right:24px;
|
||||
border: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
*webkit scroll bars */
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
|
||||
}
|
|
@ -0,0 +1,405 @@
|
|||
|
||||
|
||||
|
||||
var data = [
|
||||
{section:"recently released", id:"A", movies:[
|
||||
{title:"Movie 1", id:1, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image09.jpg"},
|
||||
{title:"Movie 1", id:2, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image14.jpg"},
|
||||
{title:"Movie 1", id:3, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image19.jpg"},
|
||||
{title:"Movie 1", id:4, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image26.jpg"},
|
||||
{title:"Movie 1", id:5, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image21.jpg"},
|
||||
{title:"Movie 1", id:6, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image29.jpg"},
|
||||
{title:"Movie 1", id:7, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image39.jpg"},
|
||||
{title:"Movie 1", id:8, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image27.jpg"},
|
||||
{title:"Movie 1", id:9, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image15.jpg"},
|
||||
{title:"Movie 1", id:10, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image11.jpg"},
|
||||
]},
|
||||
{section:"Adventures", id:"B",movies:[
|
||||
{title:"Movie 1", id:11, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image06.jpg"},
|
||||
{title:"Movie 1", id:12, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image40.jpg"},
|
||||
{title:"Movie 1", id:13, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image32.jpg"},
|
||||
{title:"Movie 1", id:14, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image28.jpg"},
|
||||
{title:"Movie 1", id:15, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image49.jpg"},
|
||||
{title:"Movie 1", id:16, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeaturedImage_2x1_Image03.jpg"},
|
||||
{title:"Movie 1", id:17, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image10.jpg"},
|
||||
{title:"Movie 1", id:18, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image19.jpg"},
|
||||
{title:"Movie 1", id:19, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image22.jpg"},
|
||||
{title:"Movie 1", id:20, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image09.jpg"}
|
||||
|
||||
]},
|
||||
{section:"People",id:"C", movies:[
|
||||
{title:"Movie 1", id:21, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image13.jpg"},
|
||||
{title:"Movie l", id:22, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image16.jpg"},
|
||||
{title:"Movie k", id:23, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image17.jpg"},
|
||||
{title:"Movie l", id:24, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image22.jpg"},
|
||||
{title:"Movie k", id:25, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image07.jpg"},
|
||||
{title:"Movie a", id:26, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image19.jpg"},
|
||||
{title:"Movie b", id:27, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image14.jpg"},
|
||||
{title:"Movie c", id:28, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image08.jpg"},
|
||||
{title:"Movie d", id:29, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image28.jpg"},
|
||||
{title:"Movie e", id:30, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image27.jpg"}
|
||||
]},
|
||||
{section:"The Great Outdoors",id:"D", movies:[
|
||||
{title:"Movie k", id:31, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image48.jpg"},
|
||||
{title:"Movie l", id:32, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image34.jpg"},
|
||||
{title:"Movie k", id:33, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image22.jpg"},
|
||||
{title:"Movie l", id:34, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image08.jpg"},
|
||||
{title:"Movie k", id:35, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image18.jpg"},
|
||||
{title:"Movie a", id:36, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image25.jpg"},
|
||||
{title:"Movie b", id:37, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image26.jpg"},
|
||||
{title:"Movie c", id:38, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image09.jpg"},
|
||||
{title:"Movie d", id:39, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image27.jpg"},
|
||||
{title:"Movie e", id:40, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image28.jpg"}
|
||||
]},
|
||||
{section:"Kids",id:"E", movies:[
|
||||
{title:"Movie k", id:41, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image37.jpg"},
|
||||
{title:"Movie l", id:42, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image45.jpg"},
|
||||
{title:"Movie k", id:43, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image12.jpg"},
|
||||
{title:"Movie l", id:44, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image59.jpg"},
|
||||
{title:"Movie k", id:45, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image24.jpg"},
|
||||
{title:"Movie a", id:46, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image13.jpg"},
|
||||
{title:"Movie b", id:47, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image21.jpg"},
|
||||
{title:"Movie c", id:48, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image22.jpg"},
|
||||
{title:"Movie d", id:49, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image23.jpg"},
|
||||
{title:"Movie e", id:50, imgUrl:"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image24.jpg"}
|
||||
]}
|
||||
]
|
||||
|
||||
//custom events
|
||||
var loadMoviePage = new CustomEvent('loadMoviePage');
|
||||
var playMovieFullScreen = new CustomEvent('playMovieFullScreen');
|
||||
var currentPlayObj = {title:'Galaxy Explorer', imgUrl:'http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image04.jpg'};
|
||||
|
||||
var initStateObj = { state: "frontPage" };
|
||||
history.pushState(initStateObj, "page 2", "#frontPage");
|
||||
|
||||
|
||||
var loadMovieState = function(a){
|
||||
|
||||
var stateObj = { state: "playMovie" };
|
||||
history.pushState(stateObj, "page 2", "#playMovie");
|
||||
document.dispatchEvent(loadMoviePage)
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var HeroBox = React.createClass({
|
||||
handleClick() {
|
||||
currentPlayObj = this.props;
|
||||
loadMovieState()
|
||||
},
|
||||
handleFocus(){
|
||||
// window.scrollTo(0,0)
|
||||
//console.log('should be focusing top')
|
||||
$("html, body").animate({ scrollTop: 0 }, 300);
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div className="heroBox">
|
||||
<div className="controls">
|
||||
<h1>Galaxy Adorer</h1>
|
||||
<button onFocus={this.handleFocus} onClick={this.handleClick} ><span className="arrow-right">▷</span></button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var MovieBox = React.createClass({
|
||||
handleClick: function() {
|
||||
currentPlayObj = this.props.data;
|
||||
loadMovieState()
|
||||
},
|
||||
render: function(){
|
||||
var makeId = "m"+this.props.id
|
||||
return(
|
||||
<div className="movieBoxContainer">
|
||||
<button className="movieBox" id={makeId} data-tv-focus-right={this.props.focusData} title={this.props.title} onClick={this.handleClick} style={{backgroundImage: 'url('+this.props.imgUrl+')'}}><span></span></button>
|
||||
{this.props.title}
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var MovieSection = React.createClass({
|
||||
handleClick(e){
|
||||
var maxPos = $(e.currentTarget).siblings()[1].scrollWidth-$( e.currentTarget).siblings()[1].clientWidth;
|
||||
var curPos = $(e.currentTarget).siblings()[1].scrollLeft;
|
||||
var distance = $( e.currentTarget).siblings()[1].clientWidth-200;
|
||||
if(curPos >= maxPos) distance = (curPos+distance)*-1;
|
||||
$(e.currentTarget).siblings().animate({ scrollLeft: curPos+distance }, 600);
|
||||
|
||||
},
|
||||
render: function(){
|
||||
var i =0;
|
||||
var leng = this.props.data.length;
|
||||
var movieSectionNodes = this.props.data.map(function(data) {
|
||||
i++;
|
||||
if(leng == i){
|
||||
leng = leng-1;
|
||||
var pin = "#m"+(data.id-leng);
|
||||
console.log("leng", leng);
|
||||
console.log('data.id', data.id)
|
||||
return (
|
||||
|
||||
<MovieBox id={data.id} key={data.id} title={data.title} data={data} imgUrl={data.imgUrl} focusData={pin}/>
|
||||
|
||||
);
|
||||
}else{
|
||||
|
||||
return (
|
||||
|
||||
<MovieBox id={data.id} key={data.id} title={data.title} data={data} imgUrl={data.imgUrl} />
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
return(
|
||||
<div className="movieSection" id={this.props.id}>
|
||||
<h4>{this.props.section}</h4>
|
||||
<div className="list">
|
||||
{movieSectionNodes}
|
||||
</div>
|
||||
<button onClick={this.handleClick} className="overArrow">❯</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var MovieListing = React.createClass({
|
||||
render: function() {
|
||||
var num = 0;
|
||||
var movieSectionNodes = this.props.data.map(function(data) {
|
||||
return (
|
||||
|
||||
<MovieSection title={data.title} key={data.id} section={data.section} data={data.movies} />
|
||||
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="movieListing">
|
||||
{movieSectionNodes}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
class MoviePlayer extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
};
|
||||
componentDidMount(){
|
||||
|
||||
initializePlayer()
|
||||
|
||||
}
|
||||
render(){
|
||||
return(
|
||||
<div id="videoContainer" className="moviePlayer">
|
||||
<video id="myVideo" controls="true" width="100%" height="100%" autoPlay>
|
||||
<source src="http://video.ch9.ms/ch9/2f52/44b36f3c-0822-40b1-9926-6771225a2f52/mjsNapol01_high.mp4" type="video/mp4"></source>
|
||||
</video>
|
||||
<div id="videoControls" className="controls">
|
||||
|
||||
<div className="col span-12 center-content">
|
||||
<input id="seekSlider" type="range" min="0" max="100" defaultValue="0" step="1" />
|
||||
</div>
|
||||
|
||||
<div className="col span-12 center-content">
|
||||
<div className="col span-6 left-controls">
|
||||
<span id="curTimeText">0:00:00</span>
|
||||
</div>
|
||||
<div className="col span-6 right-controls">
|
||||
<span id="remTimeText">-0:00:00</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="col span-12 center-controls">
|
||||
<button id="closeCaptionBtn" className="iconfont"></button>
|
||||
<button id="aspRatioBtn" className="iconfont"></button>
|
||||
<button id="playPauseBtn" className="iconfont"></button>
|
||||
<button id="volumeBtn" className="iconfont"></button>
|
||||
<button id="fullscreenBtn" className="iconfont"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="volumeModal">
|
||||
<button id="muteBtn" className="iconfont"></button>
|
||||
<input id="volumeSlider" className="iconfont" type="range" min="0" max="100" defaultValue="100" step="1" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)}
|
||||
};
|
||||
|
||||
var PlayMovie = React.createClass({
|
||||
render: function(){
|
||||
//<div className="moviePlayer" style={{backgroundImage: 'url('+this.props.data.imgUrl+')'}}></div>
|
||||
|
||||
return(
|
||||
<div className="playMovie">
|
||||
<MoviePlayer />
|
||||
<div className="movieText">
|
||||
<h2>{this.props.data.title}</h2>
|
||||
<div className="movieTextWrapper">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fermentum ipsum sit amet porta faucibus. Cras ullamcorper a odio non rutrum.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fermentum ipsum sit amet porta faucibus. Quisque a diam id tellus placerat euismod.</p>
|
||||
|
||||
<p className="playInfo">2008 | 1 hr 51 min</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
var PlayMovieDetails = React.createClass({
|
||||
render:function(){
|
||||
// console.log('movie obj', this.props)
|
||||
return(
|
||||
<div className="movieText">
|
||||
<h2>{this.props.data.title}</h2>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fermentum ipsum sit amet porta faucibus. Quisque a diam id tellus placerat euismod. Cras ullamcorper a odio non rutrum.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fermentum ipsum sit amet porta faucibus. Quisque a diam id tellus placerat euismod.</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
var PlayMoveAdditional = React.createClass({
|
||||
render: function(){
|
||||
return(
|
||||
<div className="additionalDetailWrapper">
|
||||
<h4>Additional Details</h4>
|
||||
<div className="lowerDetailsWrapper">
|
||||
<div className="detailBlock">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fermentum ipsum sit amet porta faucibus</div>
|
||||
<div className="detailBlock">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fermentum ipsum sit amet porta faucibus</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
|
||||
class TopSection extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
viewer: 'frontPage'
|
||||
};
|
||||
};
|
||||
componentDidMount(){
|
||||
var that = this;
|
||||
window.addEventListener('popstate', function(e){
|
||||
var stateObj = e.state;
|
||||
window.scrollTo(0, 0);
|
||||
that.setState({viewer: stateObj.state});
|
||||
|
||||
});
|
||||
document.addEventListener('loadMoviePage', function(){
|
||||
that.setState({viewer: 'playMovie'});
|
||||
// console.log(currentPlayObj)
|
||||
})
|
||||
}
|
||||
render() {
|
||||
if (this.state.viewer === 'frontPage'){
|
||||
return(
|
||||
<div className="topSection" >
|
||||
<HeroBox title={"Galaxy Explorer"} id={0} imgUrl={"http://adx.azureedge.net/Images/Clean/Small/FeatureImage_2x1_Image04.jpg"} />
|
||||
</div>
|
||||
)
|
||||
}else{
|
||||
return(
|
||||
<div className="topSection" >
|
||||
<PlayMovie data={currentPlayObj} />
|
||||
</div>
|
||||
)}
|
||||
}};
|
||||
|
||||
class BottomSection extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
viewer: 'frontPage'
|
||||
};
|
||||
};
|
||||
|
||||
componentDidMount(){
|
||||
var that = this;
|
||||
window.addEventListener('popstate', function(e){
|
||||
var stateObj = e.state;
|
||||
window.scrollTo(0, 0);
|
||||
that.setState({viewer: stateObj.state});
|
||||
|
||||
});
|
||||
document.addEventListener('loadMoviePage', function(){
|
||||
window.scrollTo(0, 0);
|
||||
that.setState({viewer: 'playMovie'});
|
||||
})
|
||||
}
|
||||
render() {
|
||||
|
||||
|
||||
if (this.state.viewer === 'frontPage'){
|
||||
return(
|
||||
<div className="bottomSection" >
|
||||
<MovieListing data={this.props.data} />
|
||||
</div>
|
||||
)
|
||||
}else{
|
||||
return(
|
||||
<div className="bottomSection">
|
||||
<PlayMoveAdditional data={currentPlayObj} />
|
||||
</div>
|
||||
)}
|
||||
}};
|
||||
|
||||
|
||||
|
||||
var LogoBox = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div className="logoBox">
|
||||
<img src="http://adx.metulev.com/video/Logo/Logo_NoText.png" className="logo" />
|
||||
<div>Film</div>
|
||||
<div>Broadcast</div>
|
||||
<div>Commercials</div>
|
||||
<img src="" className="search" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var PageWrapper = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div className="pageWrapper">
|
||||
<LogoBox />
|
||||
<div className="topSection">
|
||||
<TopSection />
|
||||
</div>
|
||||
<BottomSection data={this.props.data} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
ReactDOM.render(
|
||||
<PageWrapper data={data} />,
|
||||
document.getElementById('page')
|
||||
);
|
После Ширина: | Высота: | Размер: 3.2 KiB |
После Ширина: | Высота: | Размер: 4.6 KiB |
После Ширина: | Высота: | Размер: 864 B |
После Ширина: | Высота: | Размер: 16 KiB |
После Ширина: | Высота: | Размер: 1.4 KiB |
После Ширина: | Высота: | Размер: 2.0 KiB |
Двоичные данные
apps/video/SouthRidgeVideo/images/chrome-extensionmanagementpage-48-48.png
Normal file
После Ширина: | Высота: | Размер: 864 B |
После Ширина: | Высота: | Размер: 286 B |
После Ширина: | Высота: | Размер: 2.9 KiB |
После Ширина: | Высота: | Размер: 2.9 KiB |
После Ширина: | Высота: | Размер: 286 B |
После Ширина: | Высота: | Размер: 6.4 KiB |
После Ширина: | Высота: | Размер: 556 B |
После Ширина: | Высота: | Размер: 864 B |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 1.8 KiB |
После Ширина: | Высота: | Размер: 2.9 KiB |
После Ширина: | Высота: | Размер: 16 KiB |
После Ширина: | Высота: | Размер: 686 KiB |
После Ширина: | Высота: | Размер: 38 KiB |
После Ширина: | Высота: | Размер: 2.7 KiB |
После Ширина: | Высота: | Размер: 3.5 KiB |
После Ширина: | Высота: | Размер: 4.2 KiB |
После Ширина: | Высота: | Размер: 1.5 KiB |
После Ширина: | Высота: | Размер: 37 KiB |
После Ширина: | Высота: | Размер: 56 KiB |
После Ширина: | Высота: | Размер: 52 KiB |
После Ширина: | Высота: | Размер: 76 KiB |
После Ширина: | Высота: | Размер: 115 KiB |
После Ширина: | Высота: | Размер: 121 KiB |
После Ширина: | Высота: | Размер: 22 KiB |
После Ширина: | Высота: | Размер: 21 KiB |
После Ширина: | Высота: | Размер: 26 KiB |
После Ширина: | Высота: | Размер: 26 KiB |
После Ширина: | Высота: | Размер: 1.9 KiB |
После Ширина: | Высота: | Размер: 427 B |
После Ширина: | Высота: | Размер: 513 B |
После Ширина: | Высота: | Размер: 702 B |
После Ширина: | Высота: | Размер: 976 B |
После Ширина: | Высота: | Размер: 32 KiB |
После Ширина: | Высота: | Размер: 23 KiB |
После Ширина: | Высота: | Размер: 15 KiB |
После Ширина: | Высота: | Размер: 23 KiB |
После Ширина: | Высота: | Размер: 2.7 KiB |
После Ширина: | Высота: | Размер: 3.4 KiB |
После Ширина: | Высота: | Размер: 5.2 KiB |
После Ширина: | Высота: | Размер: 6.9 KiB |
После Ширина: | Высота: | Размер: 887 B |
После Ширина: | Высота: | Размер: 1.3 KiB |
После Ширина: | Высота: | Размер: 1.8 KiB |
После Ширина: | Высота: | Размер: 2.3 KiB |
После Ширина: | Высота: | Размер: 772 B |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 3.4 KiB |
После Ширина: | Высота: | Размер: 5.2 KiB |
После Ширина: | Высота: | Размер: 9.8 KiB |
После Ширина: | Высота: | Размер: 3.9 KiB |
После Ширина: | Высота: | Размер: 1.3 KiB |
После Ширина: | Высота: | Размер: 2.1 KiB |
После Ширина: | Высота: | Размер: 2.7 KiB |
После Ширина: | Высота: | Размер: 887 B |
После Ширина: | Высота: | Размер: 1.3 KiB |
|
@ -0,0 +1,232 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>South Ridge Video</title>
|
||||
<link href="manifest.json" rel="manifest">
|
||||
<link href="//db.onlinewebfonts.com/c/88bdc70ec292cc29451932f9875b378a?family=SegoeUIMonoW01-Regular" rel="stylesheet" type="text/css"/> <link href="reset.css" rel="stylesheet" type="text/css" />
|
||||
<link href="app.css" rel="stylesheet" type="text/css" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<script>
|
||||
if(window.Windows && window.Windows.UI && window.Windows.UI.ViewManagement){
|
||||
var applicationView = Windows.UI.ViewManagement.ApplicationView.getForCurrentView();
|
||||
applicationView.setDesiredBoundsMode(Windows.UI.ViewManagement.ApplicationViewBoundsMode.useCoreWindow);
|
||||
}
|
||||
</script>
|
||||
<script src="build/react.js"></script>
|
||||
<script src="build/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="page"></div>
|
||||
<script type="text/babel" src="frontpage.js"></script>
|
||||
<script src="directionalnavigation-1.0.0.0.js"></script>
|
||||
<script>
|
||||
TVJS.DirectionalNavigation.focusableSelectors.push(".movieBox") ;
|
||||
TVJS.DirectionalNavigation.focusableSelectors.push(".controls .iconfont") ;
|
||||
// We set up two boundaries. This means that if the focused element is not at least 200 pixels from
|
||||
|
||||
// the edge of the screen, then we will scroll the viewport so that it is.
|
||||
|
||||
var leftBoundaryToTriggerScrollIntoView = 200;
|
||||
|
||||
var rightBoundaryToTriggerScrollIntoView = document.body.offsetWidth - 200;
|
||||
|
||||
var topBoundaryToTriggerScrollIntoView = 100
|
||||
|
||||
var bottomBoundaryToTriggerScrollIntoView = document.body.offsetHeight - 100;
|
||||
|
||||
var scrollableList = document.body;
|
||||
|
||||
var bodyScroll = document.body
|
||||
|
||||
|
||||
|
||||
// Adjust the left and right boundaries if the window is resized.
|
||||
|
||||
function handleWindowResize() {
|
||||
|
||||
leftBoundaryToTriggerScrollIntoView = 200;
|
||||
|
||||
rightBoundaryToTriggerScrollIntoView = document.body.offsetWidth - 200;
|
||||
|
||||
topBoundaryToTriggerScrollIntoView = 100
|
||||
|
||||
bottomBoundaryToTriggerScrollIntoView = document.body.offsetHeight - 100;
|
||||
|
||||
};
|
||||
|
||||
window.addEventListener("resize", handleWindowResize, false);
|
||||
|
||||
// This function handles the core logic for scrolling content into view.
|
||||
|
||||
function handleFocusChanging(ev) {
|
||||
// console.log(ev)
|
||||
scrollableList = ev.detail.nextFocusElement.parentNode.parentNode;
|
||||
// console.log('scrollableList', scrollableList)
|
||||
var keyCode = ev.detail.keyCode;
|
||||
|
||||
var nextFocusElement = ev.detail.nextFocusElement;
|
||||
|
||||
if (nextFocusElement) {
|
||||
|
||||
var nextFocusElementRect = nextFocusElement.getBoundingClientRect();
|
||||
|
||||
var newScrollLeft = -1;
|
||||
var xScrollPos = 20;
|
||||
var yScrollPos = 20;
|
||||
|
||||
switch (keyCode) {
|
||||
|
||||
case 37: // Left arrow
|
||||
|
||||
case 205: // Gamepad DPad left
|
||||
|
||||
case 214: // Gamepad left thumbstick left:
|
||||
|
||||
// Figure out if focus is about to move past the left boundary and we
|
||||
|
||||
// need to scroll the next element into view.
|
||||
|
||||
if (nextFocusElementRect.left < leftBoundaryToTriggerScrollIntoView) {
|
||||
|
||||
// If yes, figure out how much to move scroll the viewport.
|
||||
|
||||
var xScrollAmount = -1 * (leftBoundaryToTriggerScrollIntoView - nextFocusElementRect.left);
|
||||
|
||||
newScrollLeft = Math.max(0, scrollableList.scrollLeft + xScrollAmount);
|
||||
|
||||
// console.log('nextFocusElementRect.left', nextFocusElementRect.left)
|
||||
// console.log('leftBoundaryToTriggerScrollIntoView', leftBoundaryToTriggerScrollIntoView);
|
||||
console.log('newScrollLeft', newScrollLeft)
|
||||
scrollableList.scrollLeft = newScrollLeft;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 39: // Right arrow
|
||||
|
||||
case 206: // Gamepad DPad right
|
||||
|
||||
case 213: // Gamepad left thumbstick right
|
||||
|
||||
// Figure out if focus is about to move past the right boundary and we
|
||||
|
||||
// need to scroll the next element into view.
|
||||
|
||||
if (nextFocusElementRect.right > rightBoundaryToTriggerScrollIntoView) {
|
||||
|
||||
// If yes, figure out how much to move scroll the viewport.
|
||||
|
||||
var xScrollAmount = nextFocusElementRect.right - rightBoundaryToTriggerScrollIntoView;
|
||||
|
||||
xScrollPos = Math.max(0, scrollableList.scrollLeft + xScrollAmount);
|
||||
|
||||
// console.log('nextFocusElementRect.right', nextFocusElementRect.right)
|
||||
// console.log('rightBoundaryToTriggerScrollIntoView', rightBoundaryToTriggerScrollIntoView);
|
||||
console.log('xScrollPos', xScrollPos)
|
||||
scrollableList.scrollLeft = xScrollPos;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 38: // up arrow
|
||||
|
||||
case 203: // Gamepad DPad up
|
||||
|
||||
case 211: // Gamepad left thumbstick up
|
||||
|
||||
// Figure out if focus is about to move past the right boundary and we
|
||||
|
||||
// need to scroll the next element into view.
|
||||
|
||||
if (nextFocusElementRect.top < topBoundaryToTriggerScrollIntoView) {
|
||||
|
||||
// If yes, figure out how much to move scroll the viewport.
|
||||
|
||||
var yScrollAmount = nextFocusElementRect.top - topBoundaryToTriggerScrollIntoView;
|
||||
|
||||
yScrollPos = Math.max(0, bodyScroll.scrollTop + yScrollAmount);
|
||||
|
||||
// console.log('nextFocusElementRect.right', nextFocusElementRect.right)
|
||||
// console.log('rightBoundaryToTriggerScrollIntoView', rightBoundaryToTriggerScrollIntoView);
|
||||
console.log('yScrollPos', yScrollPos)
|
||||
bodyScroll.scrollTop = yScrollPos; //scrollTo??????????????
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case 40: // down arrow
|
||||
|
||||
case 204: // Gamepad DPad down
|
||||
|
||||
case 212: // Gamepad left thumbstick down
|
||||
|
||||
// Figure out if focus is about to move past the right boundary and we
|
||||
|
||||
// need to scroll the next element into view.
|
||||
bottomBoundaryToTriggerScrollIntoView = window.innerHeight -100;
|
||||
if (nextFocusElementRect.bottom > bottomBoundaryToTriggerScrollIntoView) {
|
||||
|
||||
// If yes, figure out how much to move scroll the viewport.
|
||||
console.log('nextFocusElementRect.bottom', nextFocusElementRect.bottom)
|
||||
var yScrollAmount = bottomBoundaryToTriggerScrollIntoView - nextFocusElementRect.bottom;
|
||||
|
||||
yScrollPos = Math.max(0, bodyScroll.scrollTop - yScrollAmount);
|
||||
|
||||
// console.log('nextFocusElementRect.right', nextFocusElementRect.right)
|
||||
// console.log('rightBoundaryToTriggerScrollIntoView', rightBoundaryToTriggerScrollIntoView);
|
||||
console.log('yScrollPos', yScrollPos)
|
||||
bodyScroll.scrollTop = yScrollPos; //scrollTo??????????????
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
|
||||
if (nextFocusElement) {
|
||||
|
||||
nextFocusElement.focus();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Listen to the focuschanging event. This event will fire right before focus is about to change
|
||||
|
||||
// allowing us to scroll content into view if needed.
|
||||
|
||||
TVJS.DirectionalNavigation.addEventListener("focuschanging", handleFocusChanging, false);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.js"></script>
|
||||
<script src="videoPlayer.js"></script>
|
||||
<script>
|
||||
$('.overArrow').click(function(){
|
||||
$(".list").animate({ scrollRight: 900 }, 600);
|
||||
return false;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,263 @@
|
|||
|
||||
{
|
||||
"start_url": "http://southridge.azurewebsites.net",
|
||||
"short_name": "SouthRidge",
|
||||
"display": "fullscreen",
|
||||
"orientation": "landscape",
|
||||
"name": "South Ridge Video",
|
||||
"scope":"/",
|
||||
"mjs_access_whitelist": [
|
||||
{
|
||||
"url": "https://southridge.azurewebsites.net",
|
||||
"apiAccess": "all"
|
||||
},
|
||||
{
|
||||
"url": "http://southridge.azurewebsites.net",
|
||||
"apiAccess": "all"
|
||||
}
|
||||
],
|
||||
"theme_color":"#2F404B",
|
||||
"icons": [
|
||||
{
|
||||
"src": "images/windows-smallsquare-24-24.png",
|
||||
"sizes": "24x24"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-smallsquare-30-30.png",
|
||||
"sizes": "30x30"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-splashscreen-1240-600.png",
|
||||
"sizes": "1240x600"
|
||||
},
|
||||
|
||||
{
|
||||
"src": "images/windows-smallsquare-42-42.png",
|
||||
"sizes": "42x42"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-smallsquare-54-54.png",
|
||||
"sizes": "54x54"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-splashscreen-1116-540.png",
|
||||
"sizes": "1116x540"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-splashscreen-868-420.png",
|
||||
"sizes": "868x420"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-splashscreen-620-300.png",
|
||||
"sizes": "620x300"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-squarelogo-270-270.png",
|
||||
"sizes": "270x270"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-squarelogo-210-210.png",
|
||||
"sizes": "210x210"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-squarelogo-150-150.png",
|
||||
"sizes": "150x150"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-squarelogo-120-120.png",
|
||||
"sizes": "120x120"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-storelogo-90-90.png",
|
||||
"sizes": "90x90"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-storelogo-70-70.png",
|
||||
"sizes": "70x70"
|
||||
},
|
||||
{
|
||||
"src": "images/windows-storelogo-50-50.png",
|
||||
"sizes": "50x50"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-appicon-106-106.png",
|
||||
"sizes": "106x106"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-appicon-62-62.png",
|
||||
"sizes": "62x62"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-appicon-44-44.png",
|
||||
"sizes": "44x44"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-mediumtile-360-360.png",
|
||||
"sizes": "360x360"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-mediumtile-210-210.png",
|
||||
"sizes": "210x210"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-mediumtile-150-150.png",
|
||||
"sizes": "150x150"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-smalltile-170-170.png",
|
||||
"sizes": "170x170"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-smalltile-99-99.png",
|
||||
"sizes": "99x99"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-smalltile-71-71.png",
|
||||
"sizes": "71x71"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-storelogo-120-120.png",
|
||||
"sizes": "120x120"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-storelogo-70-70.png",
|
||||
"sizes": "70x70"
|
||||
},
|
||||
{
|
||||
"src": "images/windowsphone-storelogo-50-50.png",
|
||||
"sizes": "50x50"
|
||||
},
|
||||
{
|
||||
"src": "images/android-launchericon-512-512.png",
|
||||
"sizes": "512x512"
|
||||
},
|
||||
{
|
||||
"src": "images/android-launchericon-192-192.png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "images/android-launchericon-144-144.png",
|
||||
"sizes": "144x144"
|
||||
},
|
||||
{
|
||||
"src": "images/android-launchericon-96-96.png",
|
||||
"sizes": "96x96"
|
||||
},
|
||||
{
|
||||
"src": "images/android-launchericon-72-72.png",
|
||||
"sizes": "72x72"
|
||||
},
|
||||
{
|
||||
"src": "images/android-launchericon-48-48.png",
|
||||
"sizes": "48x48"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-appicon-1024-1024.png",
|
||||
"sizes": "1024x1024"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-appicon-180-180.png",
|
||||
"sizes": "180x180"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-appicon-152-152.png",
|
||||
"sizes": "152x152"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-appicon-120-120.png",
|
||||
"sizes": "120x120"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-appicon-76-76.png",
|
||||
"sizes": "76x76"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-launchimage-750-1334.png",
|
||||
"sizes": "750x1334"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-launchimage-1334-750.png",
|
||||
"sizes": "1334x750"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-launchimage-1242-2208.png",
|
||||
"sizes": "1242x2208"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-launchimage-2208-1242.png",
|
||||
"sizes": "2208x1242"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-launchimage-640-960.png",
|
||||
"sizes": "640x960"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-launchimage-640-1136.png",
|
||||
"sizes": "640x1136"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-launchimage-1536-2048.png",
|
||||
"sizes": "1536x2048"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-launchimage-2048-1536.png",
|
||||
"sizes": "2048x1536"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-launchimage-768-1024.png",
|
||||
"sizes": "768x1024"
|
||||
},
|
||||
{
|
||||
"src": "images/ios-launchimage-1024-768.png",
|
||||
"sizes": "1024x768"
|
||||
},
|
||||
{
|
||||
"src": "images/chrome-extensionmanagementpage-48-48.png",
|
||||
"sizes": "48x48"
|
||||
},
|
||||
{
|
||||
"src": "images/chrome-favicon-16-16.png",
|
||||
"sizes": "16x16"
|
||||
},
|
||||
{
|
||||
"src": "images/chrome-installprocess-128-128.png",
|
||||
"sizes": "128x128"
|
||||
},
|
||||
{
|
||||
"src": "images/firefox-marketplace-512-512.png",
|
||||
"sizes": "512x512"
|
||||
},
|
||||
{
|
||||
"src": "images/firefox-marketplace-128-128.png",
|
||||
"sizes": "128x128"
|
||||
},
|
||||
{
|
||||
"src": "images/firefox-general-256-256.png",
|
||||
"sizes": "256x256"
|
||||
},
|
||||
{
|
||||
"src": "images/firefox-general-128-128.png",
|
||||
"sizes": "128x128"
|
||||
},
|
||||
{
|
||||
"src": "images/firefox-general-90-90.png",
|
||||
"sizes": "90x90"
|
||||
},
|
||||
{
|
||||
"src": "images/firefox-general-64-64.png",
|
||||
"sizes": "64x64"
|
||||
},
|
||||
{
|
||||
"src": "images/firefox-general-48-48.png",
|
||||
"sizes": "48x48"
|
||||
},
|
||||
{
|
||||
"src": "images/firefox-general-32-32.png",
|
||||
"sizes": "32x32"
|
||||
},
|
||||
{
|
||||
"src": "images/firefox-general-16-16.png",
|
||||
"sizes": "16x16"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
|
||||
h1, h2, h3 { font-size: 24px;}
|
||||
p {line-height: 1.25em; margin-bottom: 1.5em;}
|
||||
|
||||
button{ background: none;
|
||||
border:2px solid white;
|
||||
xpadding: .5em; color: white;
|
||||
width: 164px;
|
||||
text-align: center;
|
||||
height: 36px;}
|
|
@ -0,0 +1,257 @@
|
|||
div#videoContainer{
|
||||
xwidth: 100%;
|
||||
background:#000;
|
||||
margin:0px;
|
||||
position: relative;
|
||||
bottom: 0%;
|
||||
left: 0%;
|
||||
right: 0%;
|
||||
}
|
||||
|
||||
div#myVideo {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
video.scale2{
|
||||
-moz-transform:scale(1.5);
|
||||
-webkit-transform:scale(1.5);
|
||||
-o-transform:scale(1.5);
|
||||
-ms-transform:scale(1.5);
|
||||
transform:scale(1.5);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'SegoeMDL2';
|
||||
src: url("segmdl2.ttf") format("truetype");
|
||||
}
|
||||
|
||||
#videoContainer .controls {
|
||||
background: #000;
|
||||
position: absolute;
|
||||
width: inherit;
|
||||
height: 40%;
|
||||
bottom: 0%;
|
||||
z-index: 2147483647; /*fix this*/
|
||||
}
|
||||
|
||||
.left-controls {
|
||||
text-align: left;
|
||||
color: white;
|
||||
float: left;
|
||||
margin-top: 0;
|
||||
margin-left: 2%;
|
||||
}
|
||||
|
||||
.center-controls {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
margin: 3%;
|
||||
}
|
||||
.center-controls button{
|
||||
height: auto;
|
||||
width: auto;
|
||||
|
||||
}
|
||||
|
||||
.right-controls {
|
||||
text-align: right;
|
||||
color: white;
|
||||
float: right;
|
||||
margin-top: 0;
|
||||
margin-right: 2%;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: 'SegoeMDL2';
|
||||
font-size: 25px;
|
||||
background: none;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.center-content {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
input#seekSlider {
|
||||
text-align: center;
|
||||
width: 97%;
|
||||
margin: 2% 1%;
|
||||
}
|
||||
|
||||
input#volumeSlider {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
button.iconfont {
|
||||
background: black;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
button.iconfont:hover {
|
||||
background: #95a5a6;
|
||||
}
|
||||
|
||||
button.iconfont:active {
|
||||
background: #7f8c8d;
|
||||
}
|
||||
|
||||
button.iconfont:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
div#volumeModal {
|
||||
display: none;
|
||||
padding: 5px;
|
||||
z-index: 2147483700;
|
||||
width: initial;
|
||||
background: #000;
|
||||
border-style: solid;
|
||||
border-color: #BDC3C7;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
/*This removes on Chrome only. How do I get rid of it on Edge?*/
|
||||
video::-webkit-media-controls-enclosure {
|
||||
display:none !important;
|
||||
}
|
||||
|
||||
/*======================= Range Slider*/
|
||||
|
||||
/*Chrome*/
|
||||
|
||||
input[type=range] {
|
||||
-webkit-appearance: none;
|
||||
margin: 10px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
input[type=range]:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type=range]::-webkit-slider-runnable-track {
|
||||
width: 100%;
|
||||
height: 11px;
|
||||
cursor: pointer;
|
||||
background: #BDC3C7;
|
||||
border-radius: 20px;
|
||||
border: 0px solid #010101;
|
||||
}
|
||||
|
||||
input[type=range]::-webkit-slider-thumb {
|
||||
border: 2px solid #3498DB;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
border-radius: 15px;
|
||||
background: #FFFFFF;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
margin-top: -8.5px;
|
||||
}
|
||||
|
||||
input[type=range]:hover::-webkit-slider-thumb {
|
||||
background: #3498db;
|
||||
}
|
||||
|
||||
input[type=range]:active::-webkit-slider-thumb {
|
||||
background: #2980b9;
|
||||
}
|
||||
|
||||
input[type=range]:focus::-webkit-slider-runnable-track {
|
||||
background: #BDC3C7;
|
||||
}
|
||||
|
||||
/*FireFox*/
|
||||
input[type=range]::-moz-range-track {
|
||||
width: 100%;
|
||||
height: 11px;
|
||||
cursor: pointer;
|
||||
background: #BDC3C7;
|
||||
border-radius: 20px;
|
||||
border: 0px solid #010101;
|
||||
}
|
||||
|
||||
input[type=range]::-moz-range-thumb {
|
||||
box-shadow: 0px 0px 0px #000031;
|
||||
border: 2px solid #3498DB;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
border-radius: 15px;
|
||||
background: #FFFFFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*MS*/
|
||||
|
||||
input[type=range]::-ms-track {
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
input[type=range]::-ms-fill-lower {
|
||||
background: #16a085;
|
||||
border-radius: 40px;
|
||||
}
|
||||
|
||||
input[type=range]::-ms-fill-upper {
|
||||
background: #BDC3C7;
|
||||
border-radius: 40px;
|
||||
}
|
||||
|
||||
input[type=range]::-ms-thumb {
|
||||
border: 2px solid #16a085;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 15px;
|
||||
background: #000;
|
||||
cursor: pointer;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
input[type=range]:hover::-ms-thumb {
|
||||
background: #bdc3c7;
|
||||
}
|
||||
|
||||
input[type=range]:active::-ms-thumb {
|
||||
background: #16a085;
|
||||
}
|
||||
|
||||
/*========================*/
|
||||
|
||||
/* fullscreen */
|
||||
html:-ms-fullscreen {
|
||||
width:100%;
|
||||
}
|
||||
:-webkit-full-screen {
|
||||
background-color:transparent;
|
||||
}
|
||||
/* hide controls on fullscreen with WebKit */
|
||||
div[datafullscreen=true] video::-webkit-media-controls {
|
||||
display:none !important;
|
||||
}
|
||||
div[datafullscreen=true] {
|
||||
max-width:100%;
|
||||
width:100%;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
div[datafullscreen=true] video {
|
||||
height:auto;
|
||||
}
|
||||
div[datafullscreen=true] .controls {
|
||||
width:100%;
|
||||
position:absolute;
|
||||
bottom:0%;
|
||||
left:0%;
|
||||
right:0%;
|
||||
height:inherit;
|
||||
z-index:2147483647;
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
<!--
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2016 Microsoft. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Scroll into view</title>
|
||||
<script src="directionalnavigation-1.0.0.0.js"></script>
|
||||
|
||||
<style>
|
||||
|
||||
body {
|
||||
background-color: rgb(16, 16, 16);
|
||||
color: rgb(235, 235, 235);
|
||||
font-family: "Segoe UI";
|
||||
font-size: 18pt;
|
||||
}
|
||||
button {
|
||||
background-color: rgba(235, 235, 235, 0.1);
|
||||
border: 4px solid rgb(16, 16, 16);
|
||||
color: rgb(235, 235, 235);
|
||||
outline: none;
|
||||
padding: 16px;
|
||||
height: 364px;
|
||||
width: 208px;
|
||||
font-size: 18pt;
|
||||
}
|
||||
button:focus {
|
||||
background-color: rgb(16, 124, 16);
|
||||
border-color: rgba(235, 235, 235, 1);
|
||||
}
|
||||
.scrolling-list {
|
||||
overflow-x: scroll;
|
||||
height: 400px;
|
||||
}
|
||||
.viewport {
|
||||
width: 7000px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1>Scroll into view</h1>
|
||||
<div id="scrolling-list" class="scrolling-list">
|
||||
<div id="viewport" class="viewport">
|
||||
<button>1</button>
|
||||
<button>2</button>
|
||||
<button>3</button>
|
||||
<button>4</button>
|
||||
<button>5</button>
|
||||
<button>6</button>
|
||||
<button>7</button>
|
||||
<button>8</button>
|
||||
<button>9</button>
|
||||
<button>10</button>
|
||||
<button>11</button>
|
||||
<button>12</button>
|
||||
<button>13</button>
|
||||
<button>14</button>
|
||||
<button>15</button>
|
||||
<button>16</button>
|
||||
<button>17</button>
|
||||
<button>18</button>
|
||||
<button>19</button>
|
||||
<button>20</button>
|
||||
<button>21</button>
|
||||
<button>22</button>
|
||||
<button>23</button>
|
||||
<button>24</button>
|
||||
<button>25</button>
|
||||
<button>26</button>
|
||||
<button>27</button>
|
||||
<button>28</button>
|
||||
<button>29</button>
|
||||
<button>30</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
// This sample demonstrates how to use the focuschanging event to scroll elements into view so that
|
||||
// the currently focused element is never on the edge of the screen.
|
||||
|
||||
// We set up two boundaries. This means that if the focused element is not at least 200 pixels from
|
||||
// the edge of the screen, then we will scroll the viewport so that it is.
|
||||
var leftBoundaryToTriggerScrollIntoView = 200;
|
||||
var rightBoundaryToTriggerScrollIntoView = document.body.offsetWidth - 200;
|
||||
var scrollableList = document.getElementById("scrolling-list");
|
||||
|
||||
// Adjust the left and right boundaries if the window is resized.
|
||||
function handleWindowResize() {
|
||||
leftBoundaryToTriggerScrollIntoView = 200;
|
||||
rightBoundaryToTriggerScrollIntoView = document.body.offsetWidth - 200;
|
||||
};
|
||||
window.addEventListener("resize", handleWindowResize, false);
|
||||
|
||||
// This function handles the core logic for scrolling content into view.
|
||||
function handleFocusChanging(ev) {
|
||||
var keyCode = ev.detail.keyCode;
|
||||
var nextFocusElement = ev.detail.nextFocusElement;
|
||||
if (nextFocusElement) {
|
||||
var nextFocusElementRect = nextFocusElement.getBoundingClientRect();
|
||||
var newScrollLeft = -1;
|
||||
switch (keyCode) {
|
||||
case 37: // Left arrow
|
||||
case 205: // Gamepad DPad left
|
||||
case 214: // Gamepad left thumbstick left:
|
||||
// Figure out if focus is about to move past the left boundary and we
|
||||
// need to scroll the next element into view.
|
||||
if (nextFocusElementRect.left < leftBoundaryToTriggerScrollIntoView) {
|
||||
// If yes, figure out how much to move scroll the viewport.
|
||||
var xScrollAmount = -2 * (leftBoundaryToTriggerScrollIntoView - nextFocusElementRect.left);
|
||||
newScrollLeft = Math.max(0, scrollableList.scrollLeft + xScrollAmount);
|
||||
}
|
||||
break;
|
||||
case 39: // Right arrow
|
||||
case 206: // Gamepad DPad right
|
||||
case 213: // Gamepad left thumbstick right
|
||||
// Figure out if focus is about to move past the right boundary and we
|
||||
// need to scroll the next element into view.
|
||||
if (nextFocusElementRect.right > rightBoundaryToTriggerScrollIntoView) {
|
||||
// If yes, figure out how much to move scroll the viewport.
|
||||
var xScrollAmount = nextFocusElementRect.right - rightBoundaryToTriggerScrollIntoView;
|
||||
var xScrollPos = Math.max(0, scrollableList.scrollLeft + xScrollAmount);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (newScrollLeft) {
|
||||
// Note: If running on Edge or Internet Explorer 11 or higher, we could use the msZoomTo API
|
||||
// to do an animated scroll. For other browsers, you can use CSS transitions.
|
||||
scrollableList.scrollLeft = xScrollPos;
|
||||
ev.preventDefault();
|
||||
// Focus is an expensive operation so it's good to let any processing from scrolling into
|
||||
// view finish first.
|
||||
requestAnimationFrame(function () {
|
||||
setTimeout(function () {
|
||||
if (nextFocusElement) {
|
||||
nextFocusElement.focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
// Listen to the focuschanging event. This event will fire right before focus is about to change
|
||||
// allowing us to scroll content into view if needed.
|
||||
TVJS.DirectionalNavigation.addEventListener("focuschanging", handleFocusChanging, false);
|
||||
|
||||
var initialFocus = document.querySelector("button");
|
||||
initialFocus.focus();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,36 @@
|
|||
var NewText = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<h1>This is new test</h1>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
class LikeButton extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
liked: false
|
||||
};
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
handleClick() {
|
||||
this.setState({liked: !this.state.liked});
|
||||
}
|
||||
render() {
|
||||
const text = this.state.liked ? 'liked' : 'haven\'t liked';
|
||||
return (
|
||||
<div onClick={this.handleClick}>
|
||||
You {text} this. Click to toggle.
|
||||
<NewText />
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<LikeButton />,
|
||||
document.getElementById('example')
|
||||
);
|
||||
|
|
@ -0,0 +1,274 @@
|
|||
var vid,
|
||||
videoContainer,
|
||||
videoControls,
|
||||
controlsTimer,
|
||||
playPauseBtn,
|
||||
seekSlider,
|
||||
curTimeText,
|
||||
remTimeText,
|
||||
aspRatioBtn,
|
||||
volumeBtn,
|
||||
volumeModal,
|
||||
muteBtn,
|
||||
volumeSlider,
|
||||
fullscreenBtn,
|
||||
systemMediaControls;
|
||||
|
||||
var timer = 4000; //milliseconds for fade timer
|
||||
|
||||
|
||||
function initializePlayer(){
|
||||
//Set high level references
|
||||
vid = document.getElementById("myVideo");
|
||||
videoContainer = document.getElementById("videoContainer");
|
||||
videoControls = document.getElementById("videoControls");
|
||||
|
||||
//replace native video controls with custom
|
||||
vid.controls = false;
|
||||
videoControls.style.display = 'block';
|
||||
controlsTimer = setTimeout(function() {
|
||||
$('#videoControls').fadeOut('slow');
|
||||
$('#volumeModal').fadeOut('slow');
|
||||
}, timer);
|
||||
|
||||
//define button references
|
||||
playPauseBtn = document.getElementById("playPauseBtn");
|
||||
seekSlider = document.getElementById("seekSlider");
|
||||
curTimeText = document.getElementById("curTimeText");
|
||||
remTimeText = document.getElementById("remTimeText");
|
||||
aspRatioBtn = document.getElementById("aspRatioBtn");
|
||||
volumeBtn = document.getElementById("volumeBtn");
|
||||
volumeModal = document.getElementById("volumeModal");
|
||||
muteBtn = document.getElementById("muteBtn");
|
||||
volumeSlider = document.getElementById("volumeSlider");
|
||||
fullscreenBtn = document.getElementById("fullscreenBtn");
|
||||
|
||||
|
||||
|
||||
//event listeners for buttons
|
||||
vid.addEventListener("mouseover",showControls,false);
|
||||
videoControls.addEventListener("mouseover",controlTimerReset,false);
|
||||
document.body.addEventListener("keydown",showControls,false);
|
||||
playPauseBtn.addEventListener("click",playPause,false);
|
||||
seekSlider.addEventListener("change",vidSeek,false);
|
||||
vid.addEventListener("timeupdate",seekTimeUpdate,false);
|
||||
|
||||
//volume button & modal handlers
|
||||
volumeBtn.addEventListener("click",toggleVolumeModal,false);
|
||||
muteBtn.addEventListener("click",vidMute,false);
|
||||
volumeSlider.addEventListener("change",setVolume,false);
|
||||
window.addEventListener("click",focusOffModal,false);
|
||||
|
||||
fullscreenBtn.addEventListener("click",toggleFullscreen,false);
|
||||
|
||||
//Add SMTC support
|
||||
if (typeof Windows !== 'undefined') {
|
||||
systemMediaControls = Windows.Media.SystemMediaTransportControls.getForCurrentView();
|
||||
systemMediaControls.addEventListener("buttonpressed", systemMediaControlsButtonPressed, false);
|
||||
systemMediaControls.isPlayEnabled = true;
|
||||
systemMediaControls.isPauseEnabled = true;
|
||||
systemMediaControls.isStopEnabled = true;
|
||||
|
||||
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.closed;
|
||||
|
||||
|
||||
//Hookup SMTC functions
|
||||
vid.addEventListener("pause", mediaPaused);
|
||||
vid.addEventListener("playing", mediaPlaying);
|
||||
vid.addEventListener("ended", mediaEnded);
|
||||
}
|
||||
}
|
||||
|
||||
//SMTC functions
|
||||
function playMedia() {
|
||||
var media = document.getElementById("myVideo");
|
||||
media.play();
|
||||
}
|
||||
function pauseMedia() {
|
||||
var media = document.getElementById("myVideo");
|
||||
media.pause();
|
||||
}
|
||||
function stopMedia() {
|
||||
var media = document.getElementById("myVideo");
|
||||
media.pause();
|
||||
media.currentTime = 0;
|
||||
}
|
||||
|
||||
function systemMediaControlsButtonPressed(eventIn) {
|
||||
var mediaButton = Windows.Media.SystemMediaTransportControlsButton;
|
||||
switch (eventIn.button) {
|
||||
case mediaButton.play:
|
||||
playMedia();
|
||||
break;
|
||||
case mediaButton.pause:
|
||||
pauseMedia();
|
||||
break;
|
||||
case mediaButton.stop:
|
||||
stopMedia();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function mediaPlaying() {
|
||||
// Update the SystemMediaTransportControl state.
|
||||
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.playing;
|
||||
}
|
||||
function mediaPaused() {
|
||||
// Update the SystemMediaTransportControl state.
|
||||
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.paused;
|
||||
}
|
||||
function mediaEnded() {
|
||||
// Update the SystemMediaTransportControl state.
|
||||
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.stopped;
|
||||
}
|
||||
|
||||
|
||||
//window.onload = initializePlayer;
|
||||
|
||||
function showControls(event) {
|
||||
|
||||
//show controller
|
||||
$('#videoControls').fadeIn('slow');
|
||||
//reset timer
|
||||
controlTimerReset(event);
|
||||
}
|
||||
|
||||
function controlTimerReset(event) {
|
||||
|
||||
//reset timer
|
||||
window.clearTimeout(controlsTimer);
|
||||
|
||||
//restart timeout
|
||||
controlsTimer = setTimeout(function() {
|
||||
$('#videoControls').fadeOut('slow');
|
||||
$('#volumeModal').fadeOut('slow');
|
||||
}, timer);
|
||||
}
|
||||
|
||||
function playPause(event){
|
||||
if(vid.paused){
|
||||
vid.play();
|
||||
playPauseBtn.innerHTML = "";
|
||||
} else {
|
||||
vid.pause();
|
||||
playPauseBtn.innerHTML = "";
|
||||
}
|
||||
}
|
||||
|
||||
function vidSeek() {
|
||||
var seekto = vid.duration * (seekSlider.value / 100);
|
||||
vid.currentTime = seekto;
|
||||
}
|
||||
|
||||
function seekTimeUpdate() {
|
||||
var newTime = vid.currentTime * (100 / vid.duration);
|
||||
seekSlider.value = newTime;
|
||||
|
||||
var curHours = Math.floor(vid.currentTime / 3600);
|
||||
var curMins = Math.floor((vid.currentTime - curHours * 3600) / 60);
|
||||
var curSecs = Math.floor(vid.currentTime - curHours * 3600 - curMins * 60);
|
||||
|
||||
remTime = vid.duration - vid.currentTime;
|
||||
|
||||
var remHours = Math.floor(remTime / 3600);
|
||||
var remMins = Math.floor((remTime - remHours * 3600) / 60);
|
||||
var remSecs = Math.floor(remTime - remHours * 3600 - remMins * 60);
|
||||
|
||||
if (curSecs < 10) { curSecs = "0" + curSecs; }
|
||||
if (curMins < 10) { curMins = "0" + curMins; }
|
||||
if (curHours < 10) { curHours = "0" + curHours; }
|
||||
if (remSecs < 10) { remSecs = "0" + remSecs; }
|
||||
if (remMins < 10) { remMins = "0" + remMins; }
|
||||
if (remHours < 10) { remHours = "0" + remHours; }
|
||||
|
||||
curTimeText.innerHTML = curHours + ":" + curMins + ":" + curSecs;
|
||||
remTimeText.innerHTML = "-" + remHours + ":" + remMins + ":" + remSecs;
|
||||
|
||||
if (vid.ended) {
|
||||
playPauseBtn.innerHTML = "";
|
||||
remTimeText.innerHTML = "-00:00:00";
|
||||
}
|
||||
}
|
||||
|
||||
function vidMute() {
|
||||
if(vid.muted){
|
||||
vid.muted = false;
|
||||
muteBtn.innerHTML = "";
|
||||
volumeBtn.innerHTML = "";
|
||||
|
||||
} else {
|
||||
vid.muted = true;
|
||||
muteBtn.innerHTML = "";
|
||||
volumeBtn.innerHTML = "";
|
||||
}
|
||||
}
|
||||
|
||||
function setVolume() {
|
||||
vid.volume = volumeSlider.value / 100;
|
||||
|
||||
if(vid.muted){
|
||||
vid.muted = false;
|
||||
muteBtn.innerHTML = "";
|
||||
volumeBtn.innerHTML = "";
|
||||
}
|
||||
}
|
||||
|
||||
var setFullscreenData = function(state) {
|
||||
videoContainer.setAttribute('datafullscreen', !!state);
|
||||
}
|
||||
|
||||
function toggleFullscreen(){
|
||||
var state = !!(document.fullScreen || document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement || document.fullscreenElement);
|
||||
|
||||
if(state) { //is in fullscreen --> need to exit FS
|
||||
if(document.webkitExitFullscreen) {
|
||||
document.webkitExitFullscreen();
|
||||
} else if (document.mozCancelFullScreen){
|
||||
document.mozCancelFullScreen();
|
||||
}
|
||||
fullscreenBtn.innerHTML = "";
|
||||
setFullscreenData(false);
|
||||
|
||||
} else { //not in fullscreen --> need to enter FS
|
||||
if (vid.requestFullscreen) {
|
||||
vid.requestFullScreen();
|
||||
} else if (vid.webkitRequestFullscreen) {
|
||||
vid.webkitRequestFullscreen();
|
||||
} else if (vid.mozRequestFullscreen) {
|
||||
vid.mozRequestFullScreen();
|
||||
}
|
||||
fullscreenBtn.innerHTML = "";
|
||||
setFullscreenData(true);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleVolumeModal() {
|
||||
if (volumeModal.style.display == "block") { //if its open, close it
|
||||
$("#volumeModal").fadeOut('slow');
|
||||
} else { //if its closed, open it
|
||||
renderVolumeModal();
|
||||
}
|
||||
}
|
||||
|
||||
function renderVolumeModal() {
|
||||
//just to rerender in case sizing changes -- wont need to do this after focus out is there.
|
||||
volumeModal.style.display = "none";
|
||||
|
||||
$("#volumeModal").fadeIn('slow');
|
||||
volumeModal.style.display = "block";
|
||||
volumeModal.style.position = "absolute";
|
||||
var coords = $("#volumeBtn").offset();
|
||||
coords.top = coords.top - volumeModal.offsetHeight - 5;
|
||||
coords.left = coords.left - (volumeModal.offsetWidth - volumeBtn.offsetWidth) / 2;
|
||||
$("#volumeModal").offset(coords);
|
||||
}
|
||||
|
||||
function focusOffModal(event) {
|
||||
if (volumeModal.style.display == "block"
|
||||
&& event.target != volumeModal
|
||||
&& event.target != volumeBtn
|
||||
&& event.target != muteBtn
|
||||
&& event.target != volumeSlider) { //if its open, close it
|
||||
$("#volumeModal").fadeOut('slow');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<configuration>
|
||||
<system.webServer>
|
||||
<httpProtocol>
|
||||
<customHeaders>
|
||||
<add name="Access-Control-Allow-Origin" value="*" />
|
||||
</customHeaders>
|
||||
</httpProtocol>
|
||||
<staticContent>
|
||||
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
|
||||
<remove fileExtension=".json"/>
|
||||
<mimeMap fileExtension=".json" mimeType="application/manifest+json"/>
|
||||
<mimeMap fileExtension=".webapp" mimeType="application/manifest+json"/>
|
||||
<mimeMap fileExtension=".mp4" mimeType="video/mp4" />
|
||||
</staticContent>
|
||||
</system.webServer>
|
||||
</configuration>
|