openlp/openlp/core/display/html/display.js

1005 lines
32 KiB
JavaScript

/**
* display.js is the main Javascript file that is used to drive the display.
*/
/**
* Background type enumeration
*/
var BackgroundType = {
Transparent: "transparent",
Solid: "solid",
Gradient: "gradient",
Video: "video",
Image: "image"
};
/**
* Gradient type enumeration
*/
var GradientType = {
Horizontal: "horizontal",
LeftTop: "leftTop",
LeftBottom: "leftBottom",
Vertical: "vertical",
Circular: "circular"
};
/**
* Horizontal alignment enumeration
*/
var HorizontalAlign = {
Left: "left",
Right: "right",
Center: "center",
Justify: "justify"
};
/**
* Vertical alignment enumeration
*/
var VerticalAlign = {
Top: "top",
Middle: "middle",
Bottom: "bottom"
};
/**
* Audio state enumeration
*/
var AudioState = {
Playing: "playing",
Paused: "paused",
Stopped: "stopped"
};
/**
* Transition state enumeration
*/
var TransitionState = {
EntranceTransition: "entranceTransition",
NoTransition: "noTransition",
ExitTransition: "exitTransition"
};
/**
* Animation state enumeration
*/
var AnimationState = {
NoAnimation: "noAnimation",
ScrollingText: "scrollingText",
NonScrollingText: "noScrollingText"
};
/**
* Alert location enumeration
*/
var AlertLocation = {
Top: 0,
Middle: 1,
Bottom: 2
};
/**
* Alert state enumeration
*/
var AlertState = {
Displaying: "displaying",
NotDisplaying: "notDisplaying"
};
/**
* Alert delay enumeration
*/
var AlertDelay = {
FiftyMilliseconds: 50,
OneSecond: 1000,
OnePointFiveSeconds: 1500
};
/**
* Return an array of elements based on the selector query
* @param {string} selector - The selector to find elements
* @returns {array} An array of matching elements
*/
function $(selector) {
return Array.from(document.querySelectorAll(selector));
}
/**
* Build linear gradient CSS
* @private
* @param {string} startDir - Starting direction
* @param {string} endDir - Ending direction
* @param {string} startColor - The starting color
* @param {string} endColor - The ending color
* @returns {string} A string of the gradient CSS
*/
function _buildLinearGradient(startDir, endDir, startColor, endColor) {
return "-webkit-gradient(linear, " + startDir + ", " + endDir + ", from(" + startColor + "), to(" + endColor + ")) fixed";
}
/**
* Build radial gradient CSS
* @private
* @param {string} width - Width of the gradient
* @param {string} startColor - The starting color
* @param {string} endColor - The ending color
* @returns {string} A string of the gradient CSS
*/
function _buildRadialGradient(width, startColor, endColor) {
return "-webkit-gradient(radial, " + width + " 50%, 100, " + width + " 50%, " + width + ", from(" + startColor + "), to(" + endColor + ")) fixed";
}
/**
* Get a style value from an element (computed or manual)
* @private
* @param {Object} element - The element whose style we want
* @param {string} style - The name of the style we want
* @returns {(Number|string)} The style value (type depends on the style)
*/
function _getStyle(element, style) {
return document.defaultView.getComputedStyle(element).getPropertyValue(style);
}
/**
* Convert newlines to <br> tags
* @private
* @param {string} text - The text to parse
* @returns {string} The text now with <br> tags
*/
function _nl2br(text) {
return text.replace("\r\n", "\n").replace("\n", "<br>");
}
/**
* Prepare text by creating paragraphs and calling _nl2br to convert newlines to <br> tags
* @private
* @param {string} text - The text to parse
* @returns {string} The text now with <p> and <br> tags
*/
function _prepareText(text) {
return "<p>" + _nl2br(text) + "</p>";
}
/**
* Change a camelCaseString to a camel-case-string
* @private
* @param {string} text
* @returns {string} the Un-camel-case-ified string
*/
function _fromCamelCase(text) {
return text.replace(/([A-Z])/g, function (match, submatch) {
return '-' + submatch.toLowerCase();
});
}
/**
* Create a CSS style
* @private
* @param {string} selector - The selector for this style
* @param {Object} rules - The rules to apply to the style
*/
function _createStyle(selector, rules) {
var style;
var id = selector.replace("#", "").replace(" .", "-").replace(".", "-").replace(" ", "_");
if ($("style#" + id).length != 0) {
style = $("style#" + id)[0];
}
else {
style = document.createElement("style");
document.getElementsByTagName("head")[0].appendChild(style);
style.type = "text/css";
style.id = id;
}
var rulesString = selector + " { ";
for (var key in rules) {
var ruleValue = rules[key];
var ruleKey = _fromCamelCase(key);
rulesString += "" + ruleKey + ": " + ruleValue + ";";
}
rulesString += " } ";
if (style.styleSheet) {
style.styleSheet.cssText = rulesString;
}
else {
style.appendChild(document.createTextNode(rulesString));
}
}
/**
* An audio player with a play list
*/
var AudioPlayer = function (audioElement) {
this._audioElement = null;
this._eventListeners = {};
this._playlist = [];
this._currentTrack = null;
this._canRepeat = false;
this._state = AudioState.Stopped;
this.createAudioElement();
};
/**
* Call all listeners associated with this event
* @private
* @param {object} event - The event that was emitted
*/
AudioPlayer.prototype._callListener = function (event) {
if (this._eventListeners.hasOwnProperty(event.type)) {
this._eventListeners[event.type].forEach(function (listener) {
listener(event);
});
}
else {
console.warn("Received unknown event \"" + event.type + "\", doing nothing.");
}
};
/**
* Create the <audio> element that is used to play the audio
*/
AudioPlayer.prototype.createAudioElement = function () {
this._audioElement = document.createElement("audio");
this._audioElement.addEventListener("ended", this.onEnded);
this._audioElement.addEventListener("ended", this._callListener);
this._audioElement.addEventListener("timeupdate", this._callListener);
this._audioElement.addEventListener("volumechange", this._callListener);
this._audioElement.addEventListener("durationchange", this._callListener);
this._audioElement.addEventListener("loadeddata", this._callListener);
document.addEventListener("complete", function(event) {
document.body.appendChild(this._audioElement);
});
};
AudioPlayer.prototype.addEventListener = function (eventType, listener) {
this._eventListeners[eventType] = this._eventListeners[eventType] || [];
this._eventListeners[eventType].push(listener);
};
AudioPlayer.prototype.onEnded = function (event) {
this.nextTrack();
};
AudioPlayer.prototype.setCanRepeat = function (canRepeat) {
this._canRepeat = canRepeat;
};
AudioPlayer.prototype.clearTracks = function () {
this._playlist = [];
};
AudioPlayer.prototype.addTrack = function (track) {
this._playlist.push(track);
};
AudioPlayer.prototype.nextTrack = function () {
if (!!this._currentTrack) {
var trackIndex = this._playlist.indexOf(this._currentTrack);
if ((trackIndex + 1 >= this._playlist.length) && this._canRepeat) {
this.play(this._playlist[0]);
}
else if (trackIndex + 1 < this._playlist.length) {
this.play(this._playlist[trackIndex + 1]);
}
else {
this.stop();
}
}
else if (this._playlist.length > 0) {
this.play(this._playlist[0]);
}
else {
console.warn("No tracks in playlist, doing nothing.");
}
};
AudioPlayer.prototype.play = function () {
if (arguments.length > 0) {
this._currentTrack = arguments[0];
this._audioElement.src = this._currentTrack;
this._audioElement.play();
this._state = AudioState.Playing;
}
else if (this._state == AudioState.Paused) {
this._audioElement.play();
this._state = AudioState.Playing;
}
else {
console.warn("No track currently paused and no track specified, doing nothing.");
}
};
/**
* Pause
*/
AudioPlayer.prototype.pause = function () {
this._audioElement.pause();
this._state = AudioState.Paused;
};
/**
* Stop playing
*/
AudioPlayer.prototype.stop = function () {
this._audioElement.pause();
this._audioElement.src = "";
this._state = AudioState.Stopped;
};
/**
* The Display object is what we use from OpenLP
*/
var Display = {
_alerts: [],
_slides: {},
_alertSettings: {},
_alertState: AlertState.NotDisplaying,
_transitionState: TransitionState.NoTransition,
_animationState: AnimationState.NoAnimation,
_revealConfig: {
margin: 0.0,
minScale: 1.0,
maxScale: 1.0,
controls: false,
progress: false,
history: false,
overview: false,
center: false,
help: false,
transition: "none",
backgroundTransition: "none",
viewDistance: 9999,
width: "100%",
height: "100%"
},
/**
* Start up reveal and do any other initialisation
*/
init: function () {
Reveal.initialize(this._revealConfig);
},
/**
* Reinitialise Reveal
*/
reinit: function () {
Reveal.reinitialize();
},
/**
* Set the transition type
* @param {string} transitionType - Can be one of "none", "fade", "slide", "convex", "concave", "zoom"
*/
setTransition: function (transitionType) {
Reveal.configure({"transition": transitionType});
},
/**
* Clear the current list of slides
*/
clearSlides: function () {
$(".slides")[0].innerHTML = "";
this._slides = {};
},
/**
* Checks if the present slide content fits within the slide
*/
doesContentFit: function () {
var currSlide = $(".slides")[0];
console.debug("scrollHeight: " + currSlide.scrollHeight + ", clientHeight: " + currSlide.clientHeight);
return currSlide.clientHeight >= currSlide.scrollHeight;
},
/**
* Generate the OpenLP startup splashscreen
* @param {string} bg_color - The background color
* @param {string} image - Path to the splash image
*/
setStartupSplashScreen: function(bg_color, image) {
Display.clearSlides();
var globalBackground = $("#global-background")[0];
globalBackground.style.cssText = "";
globalBackground.style.setProperty("background", bg_color);
var slidesDiv = $(".slides")[0];
var section = document.createElement("section");
section.setAttribute("id", 0);
section.setAttribute("data-background", bg_color);
section.setAttribute("style", "height: 100%; width: 100%; position: relative;");
var img = document.createElement('img');
img.src = image;
img.setAttribute("style", "position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto; max-height: 100%; max-width: 100%");
section.appendChild(img);
slidesDiv.appendChild(section);
Display._slides['0'] = 0;
Display.reinit();
},
/**
* Set fullscreen image from path
* @param {string} bg_color - The background color
* @param {string} image - Path to the image
*/
setFullscreenImage: function(bg_color, image) {
Display.clearSlides();
var globalBackground = $("#global-background")[0];
globalBackground.style.cssText = "";
globalBackground.style.setProperty("background", bg_color);
var slidesDiv = $(".slides")[0];
var section = document.createElement("section");
section.setAttribute("id", 0);
section.setAttribute("data-background", bg_color);
section.setAttribute("style", "height: 100%; width: 100%;");
var img = document.createElement('img');
img.src = image;
img.setAttribute("style", "height: 100%; width: 100%");
section.appendChild(img);
slidesDiv.appendChild(section);
Display._slides['0'] = 0;
Display.reinit();
},
/**
* Set fullscreen image from base64 data
* @param {string} bg_color - The background color
* @param {string} image_data - base64 encoded image data
*/
setFullscreenImageFromData: function(bg_color, image_data) {
Display.clearSlides();
var globalBackground = $("#global-background")[0];
globalBackground.style.cssText = "";
globalBackground.style.setProperty("background", bg_color);
var slidesDiv = $(".slides")[0];
var section = document.createElement("section");
section.setAttribute("id", 0);
section.setAttribute("data-background", bg_color);
section.setAttribute("style", "height: 100%; width: 100%;");
var img = document.createElement('img');
img.src = 'data:image/png;base64,' + image_data;
img.setAttribute("style", "height: 100%; width: 100%");
section.appendChild(img);
slidesDiv.appendChild(section);
Display._slides['0'] = 0;
Display.reinit();
},
/**
* Display an alert. If there's an alert already showing, add this one to the queue
* @param {string} text - The alert text
* @param {Object} JSON object - The settings for the alert object
*/
alert: function (text, settings) {
if (text == "") {
return null;
}
if (Display._alertState === AlertState.Displaying) {
console.debug("Adding to queue");
Display.addAlertToQueue(text, settings);
}
else {
console.debug("Displaying immediately");
Display.showAlert(text, settings);
}
},
/**
* Show the alert on the screen
* @param {string} text - The alert text
* @param {Object} JSON object - The settings for the alert
*/
showAlert: function (text, settings) {
var alertBackground = $('#alert-background')[0];
var alertText = $('#alert-text')[0];
// create styles for the alerts from the settings
_createStyle("#alert-background.settings", {
backgroundColor: settings.backgroundColor,
fontFamily: "'" + settings.fontFace + "'",
fontSize: settings.fontSize.toString() + "pt",
color: settings.fontColor
});
alertBackground.classList.add("settings");
alertBackground.classList.replace("hide", "show");
alertText.innerHTML = text;
Display.setAlertLocation(settings.location);
Display._transitionState = TransitionState.EntranceTransition;
/* Check if the alert is a queued alert */
if (Display._alertState !== AlertState.Displaying) {
Display._alertState = AlertState.Displaying;
}
alertBackground.addEventListener('transitionend', Display.alertTransitionEndEvent, false);
alertText.addEventListener('animationend', Display.alertAnimationEndEvent, false);
/* Either scroll the alert, or make it disappear at the end of its time */
if (settings.scroll) {
Display._animationState = AnimationState.ScrollingText;
var animationSettings = "alert-scrolling-text " + settings.timeout +
"s linear 0.6s " + settings.repeat + " normal";
alertText.style.animation = animationSettings;
}
else {
Display._animationState = AnimationState.NonScrollingText;
alertText.classList.replace("hide", "show");
setTimeout (function () {
Display._animationState = AnimationState.NoAnimation;
Display.hideAlert();
}, settings.timeout * AlertDelay.OneSecond);
}
},
/**
* Hide the alert at the end
*/
hideAlert: function () {
var alertBackground = $('#alert-background')[0];
var alertText = $('#alert-text')[0];
Display._transitionState = TransitionState.ExitTransition;
alertText.classList.replace("show", "hide");
alertBackground.classList.replace("show", "hide");
alertText.style.animation = "";
Display._alertState = AlertState.NotDisplaying;
},
/**
* Add an alert to the alert queue
* @param {string} text - The alert text to be displayed
* @param {Object} setttings - JSON object containing the settings for the alert
*/
addAlertToQueue: function (text, settings) {
Display._alerts.push({text: text, settings: settings});
},
/**
* The alertTransitionEndEvent called after a transition has ended
*/
alertTransitionEndEvent: function (e) {
e.stopPropagation();
console.debug("Transition end event reached: " + Display._transitionState);
if (Display._transitionState === TransitionState.EntranceTransition) {
Display._transitionState = TransitionState.NoTransition;
}
else if (Display._transitionState === TransitionState.ExitTransition) {
Display._transitionState = TransitionState.NoTransition;
Display.hideAlert();
Display.showNextAlert();
}
},
/**
* The alertAnimationEndEvent called after an animation has ended
*/
alertAnimationEndEvent: function (e) {
e.stopPropagation();
Display.hideAlert();
},
/**
* Set the location of the alert
* @param {int} location - Integer number with the location of the alert on screen
*/
setAlertLocation: function (location) {
var alertContainer = $(".alert-container")[0];
// Remove an existing location classes
alertContainer.classList.remove("top");
alertContainer.classList.remove("middle");
alertContainer.classList.remove("bottom");
// Apply the location class we want
switch (location) {
case AlertLocation.Top:
alertContainer.classList.add("top");
break;
case AlertLocation.Middle:
alertContainer.classList.add("middle");
break;
case AlertLocation.Bottom:
default:
alertContainer.classList.add("bottom");
break;
}
},
/**
* Display the next alert in the queue
*/
showNextAlert: function () {
console.log("showNextAlert");
if (Display._alerts.length > 0) {
console.log("Showing next alert");
var alertObject = Display._alerts.shift();
Display._alertState = AlertState.DisplayingFromQueue;
Display.showAlert(alertObject.text, alertObject.settings);
}
else {
// For the tests
return null;
}
},
/**
* Add a slide. If the slide exists but the HTML is different, update the slide.
* @param {string} verse - The verse number, e.g. "v1"
* @param {string} text - The HTML for the verse, e.g. "line1<br>line2"
* @param {string} footer_text - The HTML for the footer"
*/
addTextSlide: function (verse, text, footerText) {
var slide;
var html = _prepareText(text);
if (this._slides.hasOwnProperty(verse)) {
slide = $("#" + verse)[0];
if (slide.innerHTML != html) {
slide.innerHTML = html;
}
}
else {
var slidesDiv = $(".slides")[0];
slide = document.createElement("section");
slide.setAttribute("id", verse);
slide.innerHTML = html;
slidesDiv.appendChild(slide);
var slides = $(".slides > section");
this._slides[verse] = slides.length - 1;
if (footerText) {
$(".footer")[0].innerHTML = footerText;
}
}
if ((arguments.length > 3) && (arguments[3] === true)) {
this.reinit();
}
else if (arguments.length == 3) {
this.reinit();
}
},
/**
* Set text slides.
* @param {Object[]} slides - A list of slides to add as JS objects: {"verse": "v1", "text": "line 1\nline2"}
*/
setTextSlides: function (slides) {
Display.clearSlides();
slides.forEach(function (slide) {
Display.addTextSlide(slide.verse, slide.text, slide.footer, false);
});
Display.reinit();
Display.goToSlide(0);
},
/**
* Set image slides
* @param {Object[]} slides - A list of images to add as JS objects [{"path": "url/to/file"}]
*/
setImageSlides: function (slides) {
Display.clearSlides();
var slidesDiv = $(".slides")[0];
slides.forEach(function (slide, index) {
var section = document.createElement("section");
section.setAttribute("id", index);
section.setAttribute("data-background", "#000");
section.setAttribute("style", "height: 100%; width: 100%;");
var img = document.createElement('img');
img.src = slide.path;
img.setAttribute("style", "max-width: 100%; max-height: 100%; margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);");
section.appendChild(img);
slidesDiv.appendChild(section);
Display._slides[index.toString()] = index;
});
Display.reinit();
},
/**
* Set a video
* @param {Object} video - The video to show as a JS object: {"path": "url/to/file"}
*/
setVideo: function (video) {
this.clearSlides();
var section = document.createElement("section");
section.setAttribute("data-background", "#000");
var videoElement = document.createElement("video");
videoElement.src = video.path;
videoElement.preload = "auto";
videoElement.setAttribute("id", "video");
videoElement.setAttribute("style", "height: 100%; width: 100%;");
videoElement.autoplay = false;
// All the update methods below are Python functions, hence not camelCase
videoElement.addEventListener("durationchange", function (event) {
mediaWatcher.update_duration(event.target.duration);
});
videoElement.addEventListener("timeupdate", function (event) {
mediaWatcher.update_progress(event.target.currentTime);
});
videoElement.addEventListener("volumeupdate", function (event) {
mediaWatcher.update_volume(event.target.volume);
});
videoElement.addEventListener("ratechange", function (event) {
mediaWatcher.update_playback_rate(event.target.playbackRate);
});
videoElement.addEventListener("ended", function (event) {
mediaWatcher.has_ended(event.target.ended);
});
videoElement.addEventListener("muted", function (event) {
mediaWatcher.has_muted(event.target.muted);
});
section.appendChild(videoElement);
$(".slides")[0].appendChild(section);
this.reinit();
},
/**
* Play a video
*/
playVideo: function () {
var videoElem = $("#video");
if (videoElem.length == 1) {
videoElem[0].play();
}
},
/**
* Pause a video
*/
pauseVideo: function () {
var videoElem = $("#video");
if (videoElem.length == 1) {
videoElem[0].pause();
}
},
/**
* Stop a video
*/
stopVideo: function () {
var videoElem = $("#video");
if (videoElem.length == 1) {
videoElem[0].pause();
videoElem[0].currentTime = 0.0;
}
},
/**
* Go to a particular time in a video
* @param seconds The position in seconds to seek to
*/
seekVideo: function (seconds) {
var videoElem = $("#video");
if (videoElem.length == 1) {
videoElem[0].currentTime = seconds;
}
},
/**
* Set the playback rate of a video
* @param rate A Double of the rate. 1.0 => 100% speed, 0.75 => 75% speed, 1.25 => 125% speed, etc.
*/
setPlaybackRate: function (rate) {
var videoElem = $("#video");
if (videoElem.length == 1) {
videoElem[0].playbackRate = rate;
}
},
/**
* Set the volume
* @param level The volume level from 0 to 100.
*/
setVideoVolume: function (level) {
var videoElem = $("#video");
if (videoElem.length == 1) {
videoElem[0].volume = level / 100.0;
}
},
/**
* Mute the volume
*/
toggleVideoMute: function () {
var videoElem = $("#video");
if (videoElem.length == 1) {
videoElem[0].muted = !videoElem[0].muted;
}
},
/**
* Clear the background audio playlist
*/
clearPlaylist: function () {
var backgroundAudoElem = $("#background-audio");
if (backgroundAudoElem.length == 1) {
var audio = backgroundAudoElem[0];
/* audio.playList */
}
},
/**
* Add background audio
* @param files The list of files as objects in an array
*/
addBackgroundAudio: function (files) {
},
/**
* Go to a slide.
* @param slide The slide number or name, e.g. "v1", 0
*/
goToSlide: function (slide) {
if (this._slides.hasOwnProperty(slide)) {
Reveal.slide(this._slides[slide]);
}
else {
Reveal.slide(slide);
}
},
/**
* Go to the next slide in the list
*/
next: Reveal.next,
/**
* Go to the previous slide in the list
*/
prev: Reveal.prev,
/**
* Blank the screen
*/
blankToBlack: function () {
if (!Reveal.isPaused()) {
Reveal.togglePause();
}
// var slidesDiv = $(".slides")[0];
},
/**
* Blank to theme
*/
blankToTheme: function () {
var slidesDiv = $(".slides")[0];
slidesDiv.style.visibility = "hidden";
var footerDiv = $(".footer")[0];
footerDiv.style.visibility = "hidden";
if (Reveal.isPaused()) {
Reveal.togglePause();
}
},
/**
* Show the screen
*/
show: function () {
var slidesDiv = $(".slides")[0];
slidesDiv.style.visibility = "visible";
var footerDiv = $(".footer")[0];
footerDiv.style.visibility = "visible";
if (Reveal.isPaused()) {
Reveal.togglePause();
}
},
/**
* Figure out how many lines can fit on a slide given the font size
* @param fontSize The font size in pts
*/
calculateLineCount: function (fontSize) {
var p = $(".slides > section > p");
if (p.length == 0) {
this.addSlide("v1", "Arky arky");
p = $(".slides > section > p");
}
p = p[0];
p.style.fontSize = "" + fontSize + "pt";
var d = $(".slides")[0];
var lh = parseFloat(_getStyle(p, "line-height"));
var dh = parseFloat(_getStyle(d, "height"));
return Math.floor(dh / lh);
},
setTheme: function (theme) {
this._theme = theme;
// Set the background
var globalBackground = $("#global-background")[0];
var backgroundStyle = {};
var backgroundHtml = "";
switch (theme.background_type) {
case BackgroundType.Transparent:
backgroundStyle.background = "transparent";
break;
case BackgroundType.Solid:
backgroundStyle.background = theme.background_color;
break;
case BackgroundType.Gradient:
switch (theme.background_direction) {
case GradientType.Horizontal:
backgroundStyle.background = _buildLinearGradient("left top", "left bottom",
theme.background_start_color,
theme.background_end_color);
break;
case GradientType.Vertical:
backgroundStyle.background = _buildLinearGradient("left top", "right top",
theme.background_start_color,
theme.background_end_color);
break;
case GradientType.LeftTop:
backgroundStyle.background = _buildLinearGradient("left top", "right bottom",
theme.background_start_color,
theme.background_end_color);
break;
case GradientType.LeftBottom:
backgroundStyle.background = _buildLinearGradient("left bottom", "right top",
theme.background_start_color,
theme.background_end_color);
break;
case GradientType.Circular:
backgroundStyle.background = _buildRadialGradient(window.innerWidth / 2, theme.background_start_color,
theme.background_end_color);
break;
default:
backgroundStyle.background = "#000";
}
break;
case BackgroundType.Image:
backgroundStyle["background-image"] = "url('" + theme.background_filename + "')";
console.warn(backgroundStyle["background-image"]);
break;
case BackgroundType.Video:
backgroundStyle["background-color"] = theme.background_border_color;
backgroundHtml = "<video loop autoplay muted><source src='" + theme.background_filename + "'></video>";
console.warn(backgroundHtml);
break;
default:
backgroundStyle.background = "#000";
}
globalBackground.style.cssText = "";
for (var bgKey in backgroundStyle) {
if (backgroundStyle.hasOwnProperty(bgKey)) {
globalBackground.style.setProperty(bgKey, backgroundStyle[bgKey]);
}
}
if (!!backgroundHtml) {
globalBackground.innerHTML = backgroundHtml;
}
// set up the main area
mainStyle = {
"word-wrap": "break-word",
/*"margin": "0",
"padding": "0"*/
};
if (!!theme.font_main_outline) {
mainStyle["-webkit-text-stroke"] = "" + theme.font_main_outline_size + "pt " +
theme.font_main_outline_color;
mainStyle["-webkit-text-fill-color"] = theme.font_main_color;
}
mainStyle["font-family"] = theme.font_main_name;
mainStyle["font-size"] = "" + theme.font_main_size + "pt";
mainStyle["font-style"] = !!theme.font_main_italics ? "italic" : "";
mainStyle["font-weight"] = !!theme.font_main_bold ? "bold" : "";
mainStyle.color = theme.font_main_color;
mainStyle["line-height"] = "" + (100 + theme.font_main_line_adjustment) + "%";
mainStyle["text-align"] = theme.display_horizontal_align;
if (theme.display_horizontal_align != HorizontalAlign.Justify) {
mainStyle["white-space"] = "pre-wrap";
}
mainStyle["vertical-align"] = theme.display_vertical_align;
if (theme.hasOwnProperty('font_main_shadow_size')) {
mainStyle["text-shadow"] = theme.font_main_shadow_color + " " + theme.font_main_shadow_size + "px " +
theme.font_main_shadow_size + "px";
}
mainStyle["padding-bottom"] = theme.display_vertical_align == VerticalAlign.Bottom ? "0.5em" : "0";
mainStyle["padding-left"] = !!theme.font_main_outline ? "" + (theme.font_main_outline_size * 2) + "pt" : "0";
// These need to be fixed, in the Python they use a width passed in as a parameter
mainStyle.position = "absolute";
mainStyle.width = "" + (window.innerWidth - (theme.font_main_outline_size * 4)) + "px";
mainStyle.height = "" + (window.innerHeight - (theme.font_main_outline_size * 4)) + "px";
mainStyle.left = "" + theme.font_main_x + "px";
mainStyle.top = "" + theme.font_main_y + "px";
var slidesDiv = $(".slides")[0];
slidesDiv.style.cssText = "";
for (var mainKey in mainStyle) {
if (mainStyle.hasOwnProperty(mainKey)) {
slidesDiv.style.setProperty(mainKey, mainStyle[mainKey]);
}
}
// Set up the footer
footerStyle = {
"text-align": "left"
};
footerStyle.position = "absolute";
footerStyle.left = "" + theme.font_footer_x + "px";
footerStyle.top = "" + theme.font_footer_y + "px";
footerStyle.bottom = "" + (window.innerHeight - theme.font_footer_y - theme.font_footer_height) + "px";
footerStyle.width = "" + theme.font_footer_width + "px";
footerStyle["font-family"] = theme.font_footer_name;
footerStyle["font-size"] = "" + theme.font_footer_size + "pt";
footerStyle.color = theme.font_footer_color;
footerStyle["white-space"] = theme.font_footer_wrap ? "normal" : "nowrap";
var footer = $(".footer")[0];
footer.style.cssText = "";
for (var footerKey in footerStyle) {
if (footerStyle.hasOwnProperty(footerKey)) {
footer.style.setProperty(footerKey, footerStyle[footerKey]);
}
}
},
/**
* Return the video types supported by the video tag
*/
getVideoTypes: function () {
var videoElement = document.createElement('video');
var videoTypes = [];
if (videoElement.canPlayType('video/mp4; codecs="mp4v.20.8"') == "probably" ||
videoElement.canPlayType('video/mp4; codecs="avc1.42E01E"') == "pobably" ||
videoElement.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"') == "probably") {
videoTypes.push(['video/mp4', '*.mp4']);
}
if (videoElement.canPlayType('video/ogg; codecs="theora"') == "probably") {
videoTypes.push(['video/ogg', '*.ogv']);
}
if (videoElement.canPlayType('video/webm; codecs="vp8, vorbis"') == "probably") {
videoTypes.push(['video/webm', '*.webm']);
}
return videoTypes;
},
/**
* Sets the scale of the page - used to make preview widgets scale
*/
setScale: function(scale) {
document.body.style.zoom = scale+"%";
}
};
new QWebChannel(qt.webChannelTransport, function (channel) {
window.mediaWatcher = channel.objects.mediaWatcher;
});