Widget:Flipflop
<style> .flipflopButton {
color: #36b; font-weight: bold; cursor: pointer;
} .flipflopButton[disabled], .flipflopButton:disabled {
color: grey; cursor: default;
}
article.flipflop-book-instance {
display: flex; flex-wrap: nowrap; justify-content: space-between; align-items: center; height: 150px; border-bottom: 1px solid grey; padding: 10px 0 10px 0; }
article.flipflop-book-instance:first-of-type {
border-top: 1px solid grey;
}
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */ position: fixed; /* Stay in place */ z-index: 1; /* Sit on top */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: auto; /* Enable scroll if needed */ background-color: rgb(0,0,0); /* Fallback color */ background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
/* Modal Content/Box */ .modal-content {
background-color: #fefefe; margin: 15% auto; /* 15% from the top and centered */ padding: 20px; border: 1px solid #888; width: 80%; /* Could be more or less, depending on screen size */
}
/* The Close Button */ .close {
color: #aaa; float: right; font-size: 28px; font-weight: bold;
}
.close:hover, .close:focus {
color: black; text-decoration: none; cursor: pointer;
} </style>
<script type="text/javascript"> var flipflopBooks = [
// Flick 1
[
{
textLeft: "äng",
videoUrl: "/images/finssl_flipflop/1_1.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/1_1.png",
},
{
textLeft: "dal",
videoUrl: "/images/finssl_flipflop/1_2.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/1_2.png",
},
{
textLeft: "backe",
videoUrl: "/images/finssl_flipflop/1_3.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/1_3.png",
},
{
textLeft: "väg",
videoUrl: "/images/finssl_flipflop/1_4.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/1_4.png",
},
{
textLeft: "moln",
videoUrl: "/images/finssl_flipflop/1_5.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/1_5.png",
},
{
textLeft: "skog",
videoUrl: "/images/finssl_flipflop/1_6.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/1_6.png",
},
{
textLeft: "hav",
videoUrl: "/images/finssl_flipflop/1_7.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/1_7.png",
},
],
// Flick 2
[
{
textLeft: "ko",
videoUrl: "/images/finssl_flipflop/2_1.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/2_1.png",
},
{
textLeft: "räv",
videoUrl: "/images/finssl_flipflop/2_2.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/2_2.png",
},
{
textLeft: "älg",
videoUrl: "/images/finssl_flipflop/2_3.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/2_3.png",
},
{
textLeft: "gris",
videoUrl: "/images/finssl_flipflop/2_4.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/2_4.png",
},
{
textLeft: "elefant",
videoUrl: "/images/finssl_flipflop/2_5.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/2_5.png",
},
{
textLeft: "hare",
videoUrl: "/images/finssl_flipflop/2_6.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/2_6.png",
},
{
textLeft: "dinosaurie",
videoUrl: "/images/finssl_flipflop/2_7.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/2_7.png",
},
],
// Flick 3
[
{
textLeft: "cykla",
videoUrl: "/images/finssl_flipflop/3_1.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/3_1.png",
},
{
textLeft: "åka rullbräda",
videoUrl: "/images/finssl_flipflop/3_2.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/3_2.png",
},
{
textLeft: "åka pulka",
videoUrl: "/images/finssl_flipflop/3_3.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/3_3.png",
},
{
textLeft: "köra bil",
videoUrl: "/images/finssl_flipflop/3_4.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/3_4.png",
},
{
textLeft: "flyga",
videoUrl: "/images/finssl_flipflop/3_5.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/3_5.png",
},
{
textLeft: "skrinna",
videoUrl: "/images/finssl_flipflop/3_6.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/3_6.png",
},
{
textLeft: "köra båt",
videoUrl: "/images/finssl_flipflop/3_7.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/3_7.png",
},
],
// Flick 4
[
{
textLeft: "slott",
videoUrl: "/images/finssl_flipflop/4_1.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/4_1.png",
},
{
textLeft: "väderkvarn",
videoUrl: "/images/finssl_flipflop/4_2.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/4_2.png",
},
{
textLeft: "lada",
videoUrl: "/images/finssl_flipflop/4_3.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/4_3.png",
},
{
textLeft: "hus",
videoUrl: "/images/finssl_flipflop/4_4.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/4_4.png",
},
{
textLeft: "fyr",
videoUrl: "/images/finssl_flipflop/4_5.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/4_5.png",
},
{
textLeft: "tält",
videoUrl: "/images/finssl_flipflop/4_6.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/4_6.png",
},
{
textLeft: "fängelse",
videoUrl: "/images/finssl_flipflop/4_7.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/4_7.png",
},
],
// Flick 5
[
{
textLeft: "groda",
videoUrl: "/images/finssl_flipflop/5_1.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/5_1.png",
},
{
textLeft: "hund",
videoUrl: "/images/finssl_flipflop/5_2.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/5_2.png",
},
{
textLeft: "apa",
videoUrl: "/images/finssl_flipflop/5_3.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/5_3.png",
},
{
textLeft: "katt",
videoUrl: "/images/finssl_flipflop/5_4.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/5_4.png",
},
{
textLeft: "mus",
videoUrl: "/images/finssl_flipflop/5_5.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/5_5.png",
},
{
textLeft: "björn",
videoUrl: "/images/finssl_flipflop/5_6.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/5_6.png",
},
{
textLeft: "spindel",
videoUrl: "/images/finssl_flipflop/5_7.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/5_7.png",
},
],
// Flick 6
[
{
textLeft: "läsa",
videoUrl: "/images/finssl_flipflop/6_1.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/6_1.png",
},
{
textLeft: "diska",
videoUrl: "/images/finssl_flipflop/6_2.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/6_2.png",
},
{
textLeft: "måla",
videoUrl: "/images/finssl_flipflop/6_3.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/6_3.png",
},
{
textLeft: "baka",
videoUrl: "/images/finssl_flipflop/6_4.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/6_4.png",
},
{
textLeft: "sticka",
videoUrl: "/images/finssl_flipflop/6_5.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/6_5.png",
},
{
textLeft: "bygga",
videoUrl: "/images/finssl_flipflop/6_6.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/6_6.png",
},
{
textLeft: "sy",
videoUrl: "/images/finssl_flipflop/6_7.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/6_7.png",
},
],
// Flick 7
[
{
textLeft: "prata med varandra",
videoUrl: "/images/finssl_flipflop/7_1.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/7_1.png",
},
{
textLeft: "tävla",
videoUrl: "/images/finssl_flipflop/7_2.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/7_2.png",
},
{
textLeft: "titta på varandra",
videoUrl: "/images/finssl_flipflop/7_3.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/7_3.png",
},
{
textLeft: "pussas",
videoUrl: "/images/finssl_flipflop/7_4.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/7_4.png",
},
{
textLeft: "spela",
videoUrl: "/images/finssl_flipflop/7_5.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/7_5.png",
},
{
textLeft: "dansa",
videoUrl: "/images/finssl_flipflop/7_6.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/7_6.png",
},
{
textLeft: "bråka",
videoUrl: "/images/finssl_flipflop/7_7.mp4",
videoType: "video/mp4",
imageLeft: "/images/finssl_flipflop/7_7.png",
},
]
]
/**
* Initializes the state of the books, state holds e.g. current page
* @param {Array} books
* @param {Array} bookState
*/
function initState(books, bookState) {
books.forEach((el, i) => bookState.push({ bookIndex: i, currentPageIndex: 0, currentPageEl: el[0] }))
}
// Root element used to append other elements to const rootElement = document.querySelector("div#flipflopapp")
var bookState = []; // Initialize book state to start from zero for each book in the flipflopBook array. initState(flipflopBooks, bookState)
/**
* Gives the next possible index in book.
* If the index is below zero, give the highest index (indicating going backwards).
* If the index is past length of book, give zero (indicating going forwards).
* @param {Integer} desiredIndex The index to switch to, if possible
* @param {Object} book The book object of pages
*/
function getNextOrPrevPageIndex(desiredIndex, book) {
if (book[desiredIndex]) return desiredIndex if (desiredIndex < 0) return book.length - 1 if (desiredIndex >= book.length) return 0 return 0
}
/**
* Switches the page within the book the page belongs to
* @param {Integer} direction Indicate the direction to switch pages, 1 or -1
* @param {Object} page Page object that holds indexes and element of book
*/
function switchPage(direction = 1, page) {
const book = flipflopBooks[page.bookIndex] const desiredPageIndex = page.currentPageIndex + direction const newCurrentPageIndex = getNextOrPrevPageIndex(desiredPageIndex, book) bookState[page.bookIndex].currentPageIndex = newCurrentPageIndex const newCurrentPageEl = book[newCurrentPageIndex] bookState[page.bookIndex].currentPageEl = newCurrentPageEl return bookState[page.bookIndex]
}
/**
* Replaces an article DOM Element with a new one
* @param {Object} newPage
* @param {Element} oldArticle
*/
function replacePageArticleDOM(newPage, oldArticle) {
const newArticle = getBookPageDOM(newPage) oldArticle.parentNode.replaceChild(newArticle, oldArticle)
}
/**
* Set the first video in the DOM Video Element */
function setVideo(video, bookId) {
const currentBookEl = bookState[bookId].currentPageEl
video_title.textContent = currentBookEl.textLeft
video.setAttribute("src", currentBookEl.videoUrl)
video.setAttribute("type", currentBookEl.videoType)
}
/**
* Creates the DOM for a book.
* Used to initialize and to update the book page.
* @param {Object} page
*/
function getBookPageDOM(page) {
const article = document.createElement("article")
article.id = `flipflop-book-${page.bookIndex}`
article.classList.add("flipflop-book-instance")
const leftBtn = document.createElement("button")
leftBtn.textContent = "← Föregående"
leftBtn.style.cssText = "height:100%;"
leftBtn.className = "flipflopButton"
const rightBtn = document.createElement("button")
rightBtn.textContent = "Följande →"
rightBtn.style.cssText = "height:100%;"
rightBtn.className = "flipflopButton"
const imgDiv = document.createElement("div")
imgDiv.style.cssText = "width:200px; text-align:center;"
const leftImg = document.createElement("img")
leftImg.src = page.currentPageEl.imageLeft
leftImg.style.cssText = "height:150px; width:auto;"
const textDiv = document.createElement("div")
textDiv.style.cssText = "width:200px; text-align:center;"
textDiv.textContent = page.currentPageEl.textLeft
const playBtn = document.createElement("button")
playBtn.textContent = "▶ Spela video"
playBtn.style.cssText = "height:100%; width:auto; max-height:150px;"
playBtn.className = "flipflopButton playBtn"
playBtn.onclick = function () {
// Reset old states of playbackRate buttons
resetSpeedButtons();
setVideo(video, page.bookIndex)
modal.style.display = "block";
// Override mediawiki default style
bodyContent.style.zIndex = "unset";
}
article.appendChild(leftBtn)
imgDiv.appendChild(leftImg)
article.appendChild(imgDiv)
article.appendChild(textDiv)
article.appendChild(playBtn)
article.appendChild(rightBtn)
leftBtn.addEventListener("click", () => {
// Switch page backwards in state
const newPage = switchPage(-1, page)
// Replace old DOM element with new
replacePageArticleDOM(newPage, article)
})
rightBtn.addEventListener("click", () => {
console.log(page)
// Switch page forwards in state
const newPage = switchPage(1, page)
// Replace old DOM element with new
replacePageArticleDOM(newPage, article)
})
return article
}
/**
* Appends the DOM Elements to the root DOM Element
* @param {Array} bookState
* @param {Element} rootElement
* @param {Element} video Video Element
*/
function initializeElements(bookState, rootElement, video) {
bookState.forEach((page) => {
const article = getBookPageDOM(page)
rootElement.appendChild(article)
})
}
// Get the video-title element from DOM const video_title = document.querySelector("p#video-title");
// Get the video player element from DOM const video = document.querySelector("video#flipflop");
// Fill in the DOM Elements for the App initializeElements(bookState, rootElement, video)
// Event listener on when video starts playing video.onplay = (video) => {
console.log("Playing a video:", video)
}
// Get the modal var modal = document.getElementById("playModal");
// Get the element that closes the modal var span = document.getElementsByClassName("close")[0];
// Get all buttons that change playbackRate var speedBtns = document.querySelectorAll('.speed-button');
// When user click speed buttons call function to change playbackRate speedBtns.forEach(button => button.addEventListener("click", changeSpeed(button)));
function changeSpeed(button) {
return function() {
// Reset old states of playbackRate buttons
resetSpeedButtons();
video.playbackRate = button.value;
// Make button look like its pressed
button.disabled = true;
}
}
function resetSpeedButtons() {
speedBtns.forEach(button => button.disabled = false);
}
// When the user clicks on (x), close the modal span.onclick = function () {
modal.style.display = "none"; // Restore mediawiki default style bodyContent.style.zIndex = 0;
}
// When the user clicks anywhere outside of the modal, close it window.onclick = function (event) {
if (event.target == modal) {
modal.style.display = "none";
// Restore mediawiki default style
bodyContent.style.zIndex = 0;
}
} </script>