forked from openlp/openlp
Merge branch 'master' of gitlab.com:openlp/openlp
This commit is contained in:
commit
2d2576aa6c
@ -3,20 +3,25 @@ stages:
|
||||
- test
|
||||
- deploy
|
||||
|
||||
lint:
|
||||
lint-python:
|
||||
stage: lint
|
||||
image: openlp/debian
|
||||
before_script:
|
||||
- sh scripts/generate_resources.sh
|
||||
script:
|
||||
- sh scripts/generate_resources.sh
|
||||
- flake8
|
||||
|
||||
lint-javascript:
|
||||
stage: lint
|
||||
image: openlp/angular
|
||||
script:
|
||||
- yarn install
|
||||
- yarn lint
|
||||
|
||||
test-debian:
|
||||
stage: test
|
||||
image: openlp/debian
|
||||
before_script:
|
||||
- sh scripts/generate_resources.sh
|
||||
script:
|
||||
- sh scripts/generate_resources.sh
|
||||
- xvfb-run -s '-screen 0 1024x768x24' pytest-3 --color=no --disable-warnings --cov openlp --cov-report term
|
||||
- mv .coverage linux.coverage
|
||||
artifacts:
|
||||
@ -26,35 +31,31 @@ test-debian:
|
||||
test-ubuntu:
|
||||
stage: test
|
||||
image: openlp/ubuntu
|
||||
before_script:
|
||||
- sh scripts/generate_resources.sh
|
||||
script:
|
||||
- sh scripts/generate_resources.sh
|
||||
- xvfb-run -s '-screen 0 1024x768x24' pytest-3 --color=no --disable-warnings
|
||||
|
||||
test-fedora:
|
||||
stage: test
|
||||
image: openlp/fedora
|
||||
before_script:
|
||||
- sh scripts/generate_resources.sh
|
||||
script:
|
||||
- sh scripts/generate_resources.sh
|
||||
- xvfb-run -s '-screen 0 1024x768x24' pytest-3 --color=no --disable-warnings
|
||||
|
||||
test-arch:
|
||||
stage: test
|
||||
image: openlp/arch
|
||||
before_script:
|
||||
- sh scripts/generate_resources.sh
|
||||
script:
|
||||
- sh scripts/generate_resources.sh
|
||||
- xvfb-run -s '-screen 0 1024x768x24' pytest --color=no --disable-warnings
|
||||
|
||||
test-macos:
|
||||
stage: test
|
||||
tags:
|
||||
- macos
|
||||
before_script:
|
||||
script:
|
||||
- export PATH=/opt/local/bin:$PATH
|
||||
- sh scripts/generate_resources.sh
|
||||
script:
|
||||
- python3 -m pytest --color=no --disable-warnings --cov openlp
|
||||
- mv .coverage macos.coverage
|
||||
artifacts:
|
||||
@ -76,6 +77,13 @@ test-windows:
|
||||
only:
|
||||
- master@openlp/openlp
|
||||
|
||||
test-display:
|
||||
stage: test
|
||||
image: openlp/angular
|
||||
script:
|
||||
- yarn install
|
||||
- yarn test --browsers ChromiumHeadlessCI
|
||||
|
||||
pages:
|
||||
stage: deploy
|
||||
image: openlp/debian
|
||||
|
@ -23,9 +23,9 @@ module.exports = function(config) {
|
||||
// preprocess matching files before serving them to the browser
|
||||
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
||||
preprocessors: {
|
||||
// source files, that you wanna generate coverage for
|
||||
// do not include tests or libraries
|
||||
// (these files will be instrumented by Istanbul)
|
||||
// source files, that you wanna generate coverage for
|
||||
// do not include tests or libraries
|
||||
// (these files will be instrumented by Istanbul)
|
||||
// "display.js": ["coverage"]
|
||||
},
|
||||
|
||||
@ -34,7 +34,7 @@ module.exports = function(config) {
|
||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||
reporters: ["dots", "junit"],
|
||||
|
||||
// configure the coverateReporter
|
||||
// configure the coverateReporter
|
||||
/* coverageReporter: {
|
||||
type : "html",
|
||||
dir : "htmlcov/"
|
||||
@ -64,6 +64,12 @@ module.exports = function(config) {
|
||||
// start these browsers
|
||||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||
browsers: ["Chromium"],
|
||||
customLaunchers: {
|
||||
ChromiumHeadlessCI: {
|
||||
base: 'ChromiumHeadless',
|
||||
flags: ['--no-sandbox']
|
||||
}
|
||||
},
|
||||
|
||||
// Continuous Integration mode
|
||||
// if true, Karma captures browsers, runs the tests and exits
|
||||
|
@ -25,10 +25,18 @@ sup {
|
||||
.reveal .slides > section,
|
||||
.reveal .slides > section > section {
|
||||
padding: 0;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.reveal > .backgrounds > .present {
|
||||
visibility: hidden !important;
|
||||
.reveal .slides > section.text-slides {
|
||||
/* Need to override reveal styles to use our text aligment */
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.reveal .slides > section p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#global-background {
|
||||
|
@ -28,19 +28,19 @@ var GradientType = {
|
||||
* Horizontal alignment enumeration
|
||||
*/
|
||||
var HorizontalAlign = {
|
||||
Left: "left",
|
||||
Right: "right",
|
||||
Center: "center",
|
||||
Justify: "justify"
|
||||
Left: 0,
|
||||
Right: 1,
|
||||
Center: 2,
|
||||
Justify: 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Vertical alignment enumeration
|
||||
*/
|
||||
var VerticalAlign = {
|
||||
Top: "top",
|
||||
Middle: "middle",
|
||||
Bottom: "bottom"
|
||||
Top: 0,
|
||||
Middle: 1,
|
||||
Bottom: 2
|
||||
};
|
||||
|
||||
/**
|
||||
@ -85,7 +85,7 @@ var AlertLocation = {
|
||||
var AlertState = {
|
||||
Displaying: "displaying",
|
||||
NotDisplaying: "notDisplaying"
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Alert delay enumeration
|
||||
@ -94,7 +94,7 @@ var AlertDelay = {
|
||||
FiftyMilliseconds: 50,
|
||||
OneSecond: 1000,
|
||||
OnePointFiveSeconds: 1500
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of elements based on the selector query
|
||||
@ -180,12 +180,13 @@ function _fromCamelCase(text) {
|
||||
* @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) {
|
||||
var style = $("style#" + id)[0];
|
||||
style = $("style#" + id)[0];
|
||||
}
|
||||
else {
|
||||
var style = document.createElement("style");
|
||||
style = document.createElement("style");
|
||||
document.getElementsByTagName("head")[0].appendChild(style);
|
||||
style.type = "text/css";
|
||||
style.id = id;
|
||||
@ -348,7 +349,7 @@ var Display = {
|
||||
* Start up reveal and do any other initialisation
|
||||
*/
|
||||
init: function () {
|
||||
Reveal.initialize(this._revealConfig);
|
||||
Reveal.initialize(Display._revealConfig);
|
||||
},
|
||||
/**
|
||||
* Reinitialise Reveal
|
||||
@ -368,13 +369,17 @@ var Display = {
|
||||
*/
|
||||
clearSlides: function () {
|
||||
$(".slides")[0].innerHTML = "";
|
||||
this._slides = {};
|
||||
Display._slides = {};
|
||||
},
|
||||
/**
|
||||
* Checks if the present slide content fits within the slide
|
||||
*/
|
||||
doesContentFit: function () {
|
||||
var currSlide = $(".slides")[0];
|
||||
var currSlide = $("section.text-slides");
|
||||
if (currSlide.length === 0) {
|
||||
currSlide = $(".slides");
|
||||
}
|
||||
currSlide = currSlide[0];
|
||||
console.debug("scrollHeight: " + currSlide.scrollHeight + ", clientHeight: " + currSlide.clientHeight);
|
||||
return currSlide.clientHeight >= currSlide.scrollHeight;
|
||||
},
|
||||
@ -475,10 +480,10 @@ var Display = {
|
||||
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"]
|
||||
backgroundColor: settings.backgroundColor,
|
||||
fontFamily: "'" + settings.fontFace + "'",
|
||||
fontSize: settings.fontSize.toString() + "pt",
|
||||
color: settings.fontColor
|
||||
});
|
||||
alertBackground.classList.add("settings");
|
||||
alertBackground.classList.replace("hide", "show");
|
||||
@ -593,33 +598,35 @@ var Display = {
|
||||
* 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"
|
||||
* @param {string} footer_text - The HTML for the footer
|
||||
* @param {bool} reinit - True if React should reinit when creating a new slide
|
||||
*/
|
||||
addTextSlide: function (verse, text, footerText) {
|
||||
addTextSlide: function (verse, text, footerText, reinit=true) {
|
||||
var slide;
|
||||
var html = _prepareText(text);
|
||||
if (this._slides.hasOwnProperty(verse)) {
|
||||
var slide = $("#" + verse)[0];
|
||||
if (Display._slides.hasOwnProperty(verse)) {
|
||||
slide = $("#" + verse)[0];
|
||||
if (slide.innerHTML != html) {
|
||||
slide.innerHTML = html;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var slidesDiv = $(".slides")[0];
|
||||
var slide = document.createElement("section");
|
||||
} else {
|
||||
var parent = $("section.text-slides");
|
||||
if (parent.length === 0) {
|
||||
Display._createTextContainer();
|
||||
parent = $("section.text-slides");
|
||||
}
|
||||
parent = parent[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;
|
||||
parent.appendChild(slide);
|
||||
Display._slides[verse] = parent.children.length - 1;
|
||||
if (footerText) {
|
||||
$(".footer")[0].innerHTML = footerText;
|
||||
}
|
||||
}
|
||||
if ((arguments.length > 3) && (arguments[3] === true)) {
|
||||
this.reinit();
|
||||
}
|
||||
else if (arguments.length == 3) {
|
||||
this.reinit();
|
||||
if (reinit) {
|
||||
Display.reinit();
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
@ -634,6 +641,19 @@ var Display = {
|
||||
Display.reinit();
|
||||
Display.goToSlide(0);
|
||||
},
|
||||
/**
|
||||
* Create the <section> that will contain text slides (vertical slides in react)
|
||||
*/
|
||||
_createTextContainer: function () {
|
||||
var slideContainer = document.createElement("section");
|
||||
slideContainer.classList = "text-slides";
|
||||
var slidesDiv = $(".slides")[0];
|
||||
slidesDiv.appendChild(slideContainer);
|
||||
// Apply the current theme to the new container
|
||||
if (!!Display._theme) {
|
||||
Display.setTheme(Display._theme);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Set image slides
|
||||
* @param {Object[]} slides - A list of images to add as JS objects [{"path": "url/to/file"}]
|
||||
@ -641,18 +661,20 @@ var Display = {
|
||||
setImageSlides: function (slides) {
|
||||
Display.clearSlides();
|
||||
var slidesDiv = $(".slides")[0];
|
||||
var parentSection = document.createElement("section");
|
||||
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.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);
|
||||
parentSection.appendChild(section);
|
||||
Display._slides[index.toString()] = index;
|
||||
});
|
||||
slidesDiv.appendChild(parentSection);
|
||||
Display.reinit();
|
||||
},
|
||||
/**
|
||||
@ -660,11 +682,11 @@ var Display = {
|
||||
* @param {Object} video - The video to show as a JS object: {"path": "url/to/file"}
|
||||
*/
|
||||
setVideo: function (video) {
|
||||
this.clearSlides();
|
||||
Display.clearSlides();
|
||||
var section = document.createElement("section");
|
||||
section.setAttribute("data-background", "#000");
|
||||
var videoElement = document.createElement("video");
|
||||
videoElement.src = video["path"];
|
||||
videoElement.src = video.path;
|
||||
videoElement.preload = "auto";
|
||||
videoElement.setAttribute("id", "video");
|
||||
videoElement.setAttribute("style", "height: 100%; width: 100%;");
|
||||
@ -690,7 +712,7 @@ var Display = {
|
||||
});
|
||||
section.appendChild(videoElement);
|
||||
$(".slides")[0].appendChild(section);
|
||||
this.reinit();
|
||||
Display.reinit();
|
||||
},
|
||||
/**
|
||||
* Play a video
|
||||
@ -780,21 +802,21 @@ var Display = {
|
||||
* @param slide The slide number or name, e.g. "v1", 0
|
||||
*/
|
||||
goToSlide: function (slide) {
|
||||
if (this._slides.hasOwnProperty(slide)) {
|
||||
Reveal.slide(this._slides[slide]);
|
||||
if (Display._slides.hasOwnProperty(slide)) {
|
||||
Reveal.slide(0, Display._slides[slide]);
|
||||
}
|
||||
else {
|
||||
Reveal.slide(slide);
|
||||
Reveal.slide(0, slide);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Go to the next slide in the list
|
||||
*/
|
||||
next: Reveal.next,
|
||||
next: Reveal.nextFragment,
|
||||
/**
|
||||
* Go to the previous slide in the list
|
||||
*/
|
||||
prev: Reveal.prev,
|
||||
prev: Reveal.prevFragment,
|
||||
/**
|
||||
* Blank the screen
|
||||
*/
|
||||
@ -833,59 +855,59 @@ var Display = {
|
||||
* @param fontSize The font size in pts
|
||||
*/
|
||||
calculateLineCount: function (fontSize) {
|
||||
var p = $(".slides > section > p");
|
||||
var p = $(".slides > section > section > p");
|
||||
if (p.length == 0) {
|
||||
this.addSlide("v1", "Arky arky");
|
||||
p = $(".slides > section > p");
|
||||
Display.addSlide("v1", "Arky arky");
|
||||
p = $(".slides > section > section > p");
|
||||
}
|
||||
p = p[0];
|
||||
p.style.fontSize = "" + fontSize + "pt";
|
||||
var d = $(".slides")[0];
|
||||
var d = $(".slides > section")[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;
|
||||
Display._theme = theme;
|
||||
// Set the background
|
||||
var globalBackground = $("#global-background")[0];
|
||||
var backgroundStyle = {};
|
||||
var backgroundHtml = "";
|
||||
switch (theme.background_type) {
|
||||
case BackgroundType.Transparent:
|
||||
backgroundStyle["background"] = "transparent";
|
||||
backgroundStyle.background = "transparent";
|
||||
break;
|
||||
case BackgroundType.Solid:
|
||||
backgroundStyle["background"] = theme.background_color;
|
||||
backgroundStyle.background = theme.background_color;
|
||||
break;
|
||||
case BackgroundType.Gradient:
|
||||
switch (theme.background_direction) {
|
||||
case GradientType.Horizontal:
|
||||
backgroundStyle["background"] = _buildLinearGradient("left top", "left bottom",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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,
|
||||
backgroundStyle.background = _buildRadialGradient(window.innerWidth / 2, theme.background_start_color,
|
||||
theme.background_end_color);
|
||||
break;
|
||||
default:
|
||||
backgroundStyle["background"] = "#000";
|
||||
backgroundStyle.background = "#000";
|
||||
}
|
||||
break;
|
||||
case BackgroundType.Image:
|
||||
@ -898,76 +920,104 @@ var Display = {
|
||||
console.warn(backgroundHtml);
|
||||
break;
|
||||
default:
|
||||
backgroundStyle["background"] = "#000";
|
||||
backgroundStyle.background = "#000";
|
||||
}
|
||||
globalBackground.style.cssText = "";
|
||||
for (var key in backgroundStyle) {
|
||||
if (backgroundStyle.hasOwnProperty(key)) {
|
||||
globalBackground.style.setProperty(key, backgroundStyle[key]);
|
||||
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"*/
|
||||
};
|
||||
mainStyle = {};
|
||||
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;
|
||||
}
|
||||
// These need to be fixed, in the Python they use a width passed in as a parameter
|
||||
mainStyle.width = theme.font_main_width + "px";
|
||||
mainStyle.height = theme.font_main_height + "px";
|
||||
mainStyle.top = "" + theme.font_main_y + "px";
|
||||
mainStyle.left = "" + theme.font_main_x + "px";
|
||||
mainStyle.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";
|
||||
// Using text-align-last because there is a <br> seperating each line
|
||||
switch (theme.display_horizontal_align) {
|
||||
case HorizontalAlign.Justify:
|
||||
mainStyle["text-align"] = "justify";
|
||||
mainStyle["text-align-last"] = "justify";
|
||||
break;
|
||||
case HorizontalAlign.Center:
|
||||
mainStyle["text-align"] = "center";
|
||||
mainStyle["text-align-last"] = "center";
|
||||
break;
|
||||
case HorizontalAlign.Left:
|
||||
mainStyle["text-align"] = "left";
|
||||
mainStyle["text-align-last"] = "left";
|
||||
break;
|
||||
case HorizontalAlign.Right:
|
||||
mainStyle["text-align"] = "right";
|
||||
mainStyle["text-align-last"] = "right";
|
||||
break;
|
||||
default:
|
||||
mainStyle["text-align"] = "center";
|
||||
mainStyle["text-align-last"] = "center";
|
||||
}
|
||||
switch (theme.display_vertical_align) {
|
||||
case VerticalAlign.Middle:
|
||||
mainStyle["justify-content"] = "center";
|
||||
break;
|
||||
case VerticalAlign.Top:
|
||||
mainStyle["justify-content"] = "flex-start";
|
||||
break;
|
||||
case VerticalAlign.Bottom:
|
||||
mainStyle["justify-content"] = "flex-end";
|
||||
// This gets around the webkit scroll height bug
|
||||
mainStyle["padding-bottom"] = "" + (theme.font_main_size / 8) + "px";
|
||||
break;
|
||||
default:
|
||||
mainStyle["justify-content"] = "center";
|
||||
}
|
||||
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["text-shadow"] = theme.font_main_shadow_color + " " + theme.font_main_shadow_size + "pt " +
|
||||
theme.font_main_shadow_size + "pt";
|
||||
}
|
||||
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 key in mainStyle) {
|
||||
if (mainStyle.hasOwnProperty(key)) {
|
||||
slidesDiv.style.setProperty(key, mainStyle[key]);
|
||||
var slidesDiv = $("section.text-slides");
|
||||
if (slidesDiv.length > 0) {
|
||||
slidesDiv = slidesDiv[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.position = "absolute";
|
||||
footerStyle.left = "" + theme.font_footer_x + "px";
|
||||
footerStyle.top = "" + theme.font_footer_y + "px";
|
||||
footerStyle.width = "" + theme.font_footer_width + "px";
|
||||
footerStyle.height = "" + theme.font_footer_height + "px";
|
||||
footerStyle.color = theme.font_footer_color;
|
||||
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 key in footerStyle) {
|
||||
if (footerStyle.hasOwnProperty(key)) {
|
||||
footer.style.setProperty(key, footerStyle[key]);
|
||||
for (var footerKey in footerStyle) {
|
||||
if (footerStyle.hasOwnProperty(footerKey)) {
|
||||
footer.style.setProperty(footerKey, footerStyle[footerKey]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -169,6 +169,7 @@ class Theme(object):
|
||||
jsn = get_text_file_string(json_path)
|
||||
self.load_theme(jsn)
|
||||
self.background_filename = None
|
||||
self.background_source = None
|
||||
self.version = 2
|
||||
|
||||
def expand_json(self, var, prev=None):
|
||||
|
@ -67,7 +67,7 @@ class Ui_PrintServiceDialog(object):
|
||||
self.toolbar.addWidget(self.options_button)
|
||||
self.toolbar.addSeparator()
|
||||
self.plain_copy = self.toolbar.addAction(UiIcons().clone,
|
||||
translate('OpenLP.PrintServiceForm', 'Copy'))
|
||||
translate('OpenLP.PrintServiceForm', 'Copy as Text'))
|
||||
self.html_copy = self.toolbar.addAction(UiIcons().clone,
|
||||
translate('OpenLP.PrintServiceForm', 'Copy as HTML'))
|
||||
self.toolbar.addSeparator()
|
||||
@ -139,7 +139,7 @@ class Ui_PrintServiceDialog(object):
|
||||
self.zoom_in_button.setToolTip(translate('OpenLP.PrintServiceForm', 'Zoom In'))
|
||||
self.options_button.setText(translate('OpenLP.PrintServiceForm', 'Options'))
|
||||
self.title_label.setText(translate('OpenLP.PrintServiceForm', 'Title:'))
|
||||
self.footer_label.setText(translate('OpenLP.PrintServiceForm', 'Custom Footer Text:'))
|
||||
self.footer_label.setText(translate('OpenLP.PrintServiceForm', 'Service Note Text:'))
|
||||
self.options_group_box.setTitle(translate('OpenLP.PrintServiceForm', 'Other Options'))
|
||||
self.slide_text_check_box.setText(translate('OpenLP.PrintServiceForm', 'Include slide text if available'))
|
||||
self.page_break_after_text.setText(translate('OpenLP.PrintServiceForm', 'Add page break before each text item'))
|
||||
|
@ -197,7 +197,7 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert
|
||||
if self.footer_text_edit.toPlainText():
|
||||
div = self._add_element('div', parent=html_data.body, class_id='customNotes')
|
||||
self._add_element(
|
||||
'span', translate('OpenLP.ServiceManager', 'Custom Service Notes: '), div, class_id='customNotesTitle')
|
||||
'span', translate('OpenLP.ServiceManager', 'Service Notes: '), div, class_id='customNotesTitle')
|
||||
self._add_element('span', html.escape(self.footer_text_edit.toPlainText()), div, class_id='customNotesText')
|
||||
self.document.setHtml(lxml.html.tostring(html_data).decode())
|
||||
self.preview_widget.updatePreview()
|
||||
|
@ -280,7 +280,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
||||
Run the wizard.
|
||||
"""
|
||||
log.debug('Editing theme {name}'.format(name=self.theme.theme_name))
|
||||
self.temp_background_filename = None
|
||||
self.temp_background_filename = self.theme.background_source
|
||||
self.update_theme_allowed = False
|
||||
self.set_defaults()
|
||||
self.update_theme_allowed = True
|
||||
@ -325,11 +325,11 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
||||
self.setField('background_type', 1)
|
||||
elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Image):
|
||||
self.image_color_button.color = self.theme.background_border_color
|
||||
self.image_path_edit.path = self.theme.background_filename
|
||||
self.image_path_edit.path = self.theme.background_source
|
||||
self.setField('background_type', 2)
|
||||
elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Video):
|
||||
self.video_color_button.color = self.theme.background_border_color
|
||||
self.video_path_edit.path = self.theme.background_filename
|
||||
self.video_path_edit.path = self.theme.background_source
|
||||
self.setField('background_type', 4)
|
||||
elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Stream):
|
||||
self.setField('background_type', 5)
|
||||
@ -467,6 +467,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
||||
:param pathlib.Path new_path: Path to the new image
|
||||
:rtype: None
|
||||
"""
|
||||
self.theme.background_source = new_path
|
||||
self.theme.background_filename = new_path
|
||||
self.set_background_page_values()
|
||||
|
||||
@ -477,6 +478,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
||||
:param pathlib.Path new_path: Path to the new video
|
||||
:rtype: None
|
||||
"""
|
||||
self.theme.background_source = new_path
|
||||
self.theme.background_filename = new_path
|
||||
self.set_background_page_values()
|
||||
|
||||
@ -553,14 +555,14 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
||||
translate('OpenLP.ThemeWizard', 'Theme Name Invalid'),
|
||||
translate('OpenLP.ThemeWizard', 'Invalid theme name. Please enter one.'))
|
||||
return
|
||||
source_path = None
|
||||
destination_path = None
|
||||
if self.theme.background_type == BackgroundType.to_string(BackgroundType.Image) or \
|
||||
self.theme.background_type == BackgroundType.to_string(BackgroundType.Video):
|
||||
file_name = self.theme.background_filename.name
|
||||
destination_path = self.path / self.theme.theme_name / file_name
|
||||
source_path = self.theme.background_filename
|
||||
if not self.edit_mode and not self.theme_manager.check_if_theme_exists(self.theme.theme_name):
|
||||
return
|
||||
self.theme_manager.save_theme(self.theme, source_path, destination_path, self.preview_box.save_screenshot())
|
||||
# Set the theme background to the cache location
|
||||
self.theme.background_filename = destination_path
|
||||
self.theme_manager.save_theme(self.theme, self.preview_box.save_screenshot())
|
||||
return QtWidgets.QDialog.accept(self)
|
||||
|
@ -325,14 +325,11 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R
|
||||
:param str new_theme_name: The new theme name of the theme
|
||||
:rtype: None
|
||||
"""
|
||||
destination_path = None
|
||||
source_path = None
|
||||
if theme_data.background_type == 'image' or theme_data.background_type == 'video':
|
||||
destination_path = self.theme_path / new_theme_name / theme_data.background_filename.name
|
||||
source_path = theme_data.background_filename
|
||||
theme_data.background_filename = self.theme_path / new_theme_name / theme_data.background_filename.name
|
||||
theme_data.theme_name = new_theme_name
|
||||
theme_data.extend_image_filename(self.theme_path)
|
||||
self.save_theme(theme_data, source_path, destination_path)
|
||||
self.save_theme(theme_data)
|
||||
self.load_themes()
|
||||
|
||||
def on_edit_theme(self, field=None):
|
||||
@ -648,14 +645,12 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R
|
||||
return False
|
||||
return True
|
||||
|
||||
def save_theme(self, theme, image_source_path=None, image_destination_path=None, image=None):
|
||||
def save_theme(self, theme, image=None):
|
||||
"""
|
||||
Writes the theme to the disk and handles the background image if necessary
|
||||
Writes the theme to the disk and including the background image and thumbnail if necessary
|
||||
|
||||
:param Theme theme: The theme data object.
|
||||
:param Path image_source_path: Where the theme image is currently located.
|
||||
:param Path image_destination_path: Where the Theme Image is to be saved to
|
||||
:param image: The example image of the theme. Optionally.
|
||||
:param image: The theme thumbnail. Optionally.
|
||||
:rtype: None
|
||||
"""
|
||||
name = theme.theme_name
|
||||
@ -667,12 +662,14 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R
|
||||
theme_path.write_text(theme_pretty)
|
||||
except OSError:
|
||||
self.log_exception('Saving theme to file failed')
|
||||
if image_source_path and image_destination_path:
|
||||
if self.old_background_image_path and image_destination_path != self.old_background_image_path:
|
||||
if theme.background_source and theme.background_filename:
|
||||
if self.old_background_image_path and theme.background_filename != self.old_background_image_path:
|
||||
delete_file(self.old_background_image_path)
|
||||
if image_source_path != image_destination_path:
|
||||
if not theme.background_source.exists():
|
||||
self.log_warning('Background does not exist, retaining cached background')
|
||||
elif theme.background_source != theme.background_filename:
|
||||
try:
|
||||
shutil.copyfile(image_source_path, image_destination_path)
|
||||
shutil.copyfile(theme.background_source, theme.background_filename)
|
||||
except OSError:
|
||||
self.log_exception('Failed to save theme image')
|
||||
if image:
|
||||
|
@ -8,6 +8,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"jasmine-core": "^2.6.4",
|
||||
"jshint": "^2.10.2",
|
||||
"karma": "^3.1.4",
|
||||
"karma-chrome-launcher": "^3.1.0",
|
||||
"karma-coverage": "^1.1.2",
|
||||
@ -17,7 +18,11 @@
|
||||
"karma-log-reporter": "0.0.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "karma start --single-run"
|
||||
"test": "karma start --single-run",
|
||||
"lint": "jshint openlp/core/display/html/display.js"
|
||||
},
|
||||
"jshintConfig": {
|
||||
"esversion": 6
|
||||
},
|
||||
"author": "OpenLP Developers",
|
||||
"license": "GPL-3.0-or-later"
|
||||
|
@ -181,4 +181,4 @@ class TestTheme(TestCase):
|
||||
assert 0 == theme.display_vertical_align, 'display_vertical_align should be 0'
|
||||
assert theme.font_footer_bold is False, 'font_footer_bold should be False'
|
||||
assert 'Arial' == theme.font_main_name, 'font_main_name should be "Arial"'
|
||||
assert 48 == len(theme.__dict__), 'The theme should have 48 attributes'
|
||||
assert 49 == len(theme.__dict__), 'The theme should have 49 attributes'
|
||||
|
@ -87,19 +87,22 @@ class TestThemeManager(TestCase):
|
||||
Test that we don't try to overwrite a theme background image with itself
|
||||
"""
|
||||
# GIVEN: A new theme manager instance, with mocked builtins.open, copyfile,
|
||||
# theme, create_paths and thememanager-attributes.
|
||||
# theme, create_paths, thememanager-attributes and background
|
||||
# .filename path is the same as the source path.
|
||||
theme_manager = ThemeManager(None)
|
||||
theme_manager.old_background_image = None
|
||||
theme_manager.old_background_image_path = None
|
||||
theme_manager.update_preview_images = MagicMock()
|
||||
theme_manager.theme_path = MagicMock()
|
||||
mocked_theme = MagicMock()
|
||||
mocked_theme.theme_name = 'themename'
|
||||
mocked_theme.extract_formatted_xml = MagicMock()
|
||||
mocked_theme.extract_formatted_xml.return_value = 'fake_theme_xml'.encode()
|
||||
|
||||
# WHEN: Calling save_theme with path to the same image, but the path written slightly different
|
||||
file_path_1 = RESOURCE_PATH / 'church.jpg'
|
||||
theme_manager.save_theme(mocked_theme, file_path_1, file_path_1)
|
||||
mocked_theme.background_filename = file_path_1
|
||||
mocked_theme.background_source = file_path_1
|
||||
|
||||
# WHEN: Calling save_theme with both background paths to the same image
|
||||
theme_manager.save_theme(mocked_theme)
|
||||
|
||||
# THEN: The mocked_copyfile should not have been called
|
||||
assert mocked_shutil.copyfile.called is False, 'copyfile should not be called'
|
||||
@ -111,30 +114,118 @@ class TestThemeManager(TestCase):
|
||||
Test that we do overwrite a theme background image when a new is submitted
|
||||
"""
|
||||
# GIVEN: A new theme manager instance, with mocked builtins.open, copyfile,
|
||||
# theme, create_paths and thememanager-attributes.
|
||||
# theme, create_paths, thememanager-attributes and background
|
||||
# .filename path is the same as the source path.
|
||||
theme_manager = ThemeManager(None)
|
||||
theme_manager.old_background_image = None
|
||||
theme_manager.old_background_image_path = None
|
||||
theme_manager.update_preview_images = MagicMock()
|
||||
theme_manager.theme_path = MagicMock()
|
||||
mocked_theme = MagicMock()
|
||||
mocked_theme.theme_name = 'themename'
|
||||
mocked_theme.filename = "filename"
|
||||
mocked_theme.background_filename = RESOURCE_PATH / 'church.jpg'
|
||||
mocked_theme.background_source = RESOURCE_PATH / 'church2.jpg'
|
||||
|
||||
# WHEN: Calling save_theme with path to different images
|
||||
file_path_1 = RESOURCE_PATH / 'church.jpg'
|
||||
file_path_2 = RESOURCE_PATH / 'church2.jpg'
|
||||
theme_manager.save_theme(mocked_theme, file_path_1, file_path_2)
|
||||
# WHEN: Calling save_theme with both background paths to different images
|
||||
theme_manager.save_theme(mocked_theme)
|
||||
|
||||
# THEN: The mocked_copyfile should not have been called
|
||||
# THEN: The mocked_copyfile should have been called
|
||||
assert mocked_shutil.copyfile.called is True, 'copyfile should be called'
|
||||
|
||||
@patch('openlp.core.ui.thememanager.shutil')
|
||||
@patch('openlp.core.ui.thememanager.delete_file')
|
||||
@patch('openlp.core.ui.thememanager.create_paths')
|
||||
def test_save_theme_delete_old_image(self, mocked_create_paths, mocked_delete_file, mocked_shutil):
|
||||
"""
|
||||
Test that we do delete a old theme background image when a new is submitted
|
||||
"""
|
||||
# GIVEN: A new theme manager instance, with mocked builtins.open,
|
||||
# theme, create_paths, thememanager-attributes and background
|
||||
# .filename path is the same as the source path.
|
||||
theme_manager = ThemeManager(None)
|
||||
theme_manager.old_background_image_path = RESOURCE_PATH / 'old_church.png'
|
||||
theme_manager.update_preview_images = MagicMock()
|
||||
theme_manager.theme_path = MagicMock()
|
||||
mocked_theme = MagicMock()
|
||||
mocked_theme.theme_name = 'themename'
|
||||
mocked_theme.background_filename = RESOURCE_PATH / 'church.jpg'
|
||||
mocked_theme.background_source = RESOURCE_PATH / 'church2.jpg'
|
||||
|
||||
# WHEN: Calling save_theme with both background paths to different images
|
||||
theme_manager.save_theme(mocked_theme)
|
||||
|
||||
# THEN: The mocked_delete_file should have been called to delete the old cached background
|
||||
assert mocked_delete_file.called is True, 'delete_file should be called'
|
||||
|
||||
@patch.object(ThemeManager, 'log_exception')
|
||||
@patch('openlp.core.ui.thememanager.delete_file')
|
||||
@patch('openlp.core.ui.thememanager.create_paths')
|
||||
def test_save_theme_missing_original(self, mocked_paths, mocked_delete, mocked_log_exception):
|
||||
"""
|
||||
Test that we revert to the old theme background image if the source is missing
|
||||
when changing the theme. (User doesn't change background but the original is
|
||||
missing)
|
||||
"""
|
||||
# GIVEN: A new theme manager instance, with invalid files. Setup as if the user
|
||||
# has left the background the same, or reselected the same path.
|
||||
# Not using resource dir because I could potentially copy a file
|
||||
folder_path = Path(mkdtemp())
|
||||
theme_manager = ThemeManager(None)
|
||||
theme_manager.old_background_image_path = folder_path / 'old.png'
|
||||
theme_manager.update_preview_images = MagicMock()
|
||||
theme_manager.theme_path = MagicMock()
|
||||
mocked_theme = MagicMock()
|
||||
mocked_theme.theme_name = 'themename'
|
||||
mocked_theme.background_filename = folder_path / 'old.png'
|
||||
mocked_theme.background_source = folder_path / 'non_existent_original.png'
|
||||
|
||||
# WHEN: Calling save_theme with a invalid background_filename
|
||||
# Although all filenames are considered invalid in this test,
|
||||
# it is important it reverts to the old background path as this in reality is always
|
||||
# valid unless someone has messed with the cache.
|
||||
theme_manager.save_theme(mocked_theme)
|
||||
|
||||
# THEN: The old background should not have bee deleted
|
||||
# AND the filename should have been replaced with the old cached background
|
||||
# AND there is no exception
|
||||
assert mocked_delete.called is False, 'delete_file should not be called'
|
||||
assert mocked_theme.background_filename == theme_manager.old_background_image_path, \
|
||||
'Background path should be reverted'
|
||||
assert mocked_log_exception.called is False, \
|
||||
'Should not have been an exception as the file wasn\'t changed'
|
||||
|
||||
@patch.object(ThemeManager, 'log_warning')
|
||||
@patch('openlp.core.ui.thememanager.delete_file')
|
||||
@patch('openlp.core.ui.thememanager.create_paths')
|
||||
def test_save_theme_missing_new(self, mocked_paths, mocked_delete, mocked_log_warning):
|
||||
"""
|
||||
Test that we log a warning if the new background is missing
|
||||
"""
|
||||
# GIVEN: A new theme manager instance, with invalid files. Setup as if the user
|
||||
# has changed the background to a invalid path.
|
||||
# Not using resource dir because I could potentially copy a file
|
||||
folder_path = Path(mkdtemp())
|
||||
theme_manager = ThemeManager(None)
|
||||
theme_manager.old_background_image_path = folder_path / 'old.png'
|
||||
theme_manager.update_preview_images = MagicMock()
|
||||
theme_manager.theme_path = MagicMock()
|
||||
mocked_theme = MagicMock()
|
||||
mocked_theme.theme_name = 'themename'
|
||||
mocked_theme.background_filename = folder_path / 'new_cached.png'
|
||||
mocked_theme.background_source = folder_path / 'new_original.png'
|
||||
|
||||
# WHEN: Calling save_theme with a invalid background_filename
|
||||
theme_manager.save_theme(mocked_theme)
|
||||
|
||||
# THEN: A warning should have happened due to attempting to copy a missing file
|
||||
mocked_log_warning.assert_called_once_with('Background does not exist, retaining cached background')
|
||||
|
||||
def test_save_theme_special_char_name(self):
|
||||
"""
|
||||
Test that we can save themes with special characters in the name
|
||||
"""
|
||||
# GIVEN: A new theme manager instance, with mocked theme and thememanager-attributes.
|
||||
theme_manager = ThemeManager(None)
|
||||
theme_manager.old_background_image = None
|
||||
theme_manager.old_background_image_path = None
|
||||
theme_manager.update_preview_images = MagicMock()
|
||||
theme_manager.theme_path = Path(self.temp_folder)
|
||||
mocked_theme = MagicMock()
|
||||
|
@ -22,6 +22,7 @@
|
||||
This module contains tests for the PdfController
|
||||
"""
|
||||
import os
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from shutil import rmtree, which
|
||||
from tempfile import mkdtemp
|
||||
@ -173,7 +174,13 @@ class TestPdfController(TestCase, TestMixin):
|
||||
if exe_path:
|
||||
self.load_pdf(exe_path)
|
||||
self.load_pdf_pictures(exe_path)
|
||||
# PyMuPDF
|
||||
|
||||
def test_loading_pdf_using_pymupdf(self):
|
||||
try:
|
||||
import fitz # noqa: F401
|
||||
except ImportError:
|
||||
pytest.skip('PyMuPDF is not installed')
|
||||
|
||||
self.load_pdf(None)
|
||||
self.load_pdf_pictures(None)
|
||||
|
||||
|
@ -147,7 +147,7 @@ describe("The Display object", function () {
|
||||
Display._slides["v1"] = 0;
|
||||
|
||||
Display.goToSlide("v1");
|
||||
expect(Reveal.slide).toHaveBeenCalledWith(0);
|
||||
expect(Reveal.slide).toHaveBeenCalledWith(0, 0);
|
||||
});
|
||||
|
||||
it("should have an alert() method", function () {
|
||||
@ -458,8 +458,8 @@ describe("Display.addTextSlide", function () {
|
||||
Display.addTextSlide(verse, text, footer);
|
||||
|
||||
expect(Display._slides[verse]).toEqual(0);
|
||||
expect($(".slides > section").length).toEqual(1);
|
||||
expect($(".slides > section")[0].innerHTML).toEqual(_prepareText(text));
|
||||
expect($(".slides > section > section").length).toEqual(1);
|
||||
expect($(".slides > section > section")[0].innerHTML).toEqual(_prepareText(text));
|
||||
expect(Display.reinit).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -472,8 +472,8 @@ describe("Display.addTextSlide", function () {
|
||||
Display.addTextSlide(verse, text, footer, false);
|
||||
|
||||
expect(Display._slides[verse]).toEqual(0);
|
||||
expect($(".slides > section").length).toEqual(1);
|
||||
expect($(".slides > section")[0].innerHTML).toEqual(_prepareText(text));
|
||||
expect($(".slides > section > section").length).toEqual(1);
|
||||
expect($(".slides > section > section")[0].innerHTML).toEqual(_prepareText(text));
|
||||
expect(Display.reinit).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -484,12 +484,12 @@ describe("Display.addTextSlide", function () {
|
||||
Display.addTextSlide(verse, "Amazing grace,\nhow sweet the sound", footer, false);
|
||||
spyOn(Display, "reinit");
|
||||
|
||||
Display.addTextSlide(verse, text, true);
|
||||
Display.addTextSlide(verse, text, footer, true);
|
||||
|
||||
expect(Display._slides[verse]).toEqual(0);
|
||||
expect($(".slides > section").length).toEqual(1);
|
||||
expect($(".slides > section")[0].innerHTML).toEqual(_prepareText(text));
|
||||
expect(Display.reinit).toHaveBeenCalled();
|
||||
expect($(".slides > section > section").length).toEqual(1);
|
||||
expect($(".slides > section > section")[0].innerHTML).toEqual(_prepareText(text));
|
||||
expect(Display.reinit).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
@ -526,12 +526,12 @@ describe("Display.setTextSlides", function () {
|
||||
expect(Display.clearSlides).toHaveBeenCalledTimes(1);
|
||||
expect(Display._slides["v1"]).toEqual(0);
|
||||
expect(Display._slides["v2"]).toEqual(1);
|
||||
expect($(".slides > section").length).toEqual(2);
|
||||
expect($(".slides > section > section").length).toEqual(2);
|
||||
expect(Display.reinit).toHaveBeenCalledTimes(1);
|
||||
expect(Reveal.slide).toHaveBeenCalledWith(0);
|
||||
expect(Reveal.slide).toHaveBeenCalledWith(0, 0);
|
||||
});
|
||||
|
||||
xit("should correctly set outline width (skipped for now)", function () {
|
||||
it("should correctly set outline width", function () {
|
||||
const slides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
@ -549,14 +549,68 @@ describe("Display.setTextSlides", function () {
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTextSlides(slides);
|
||||
Display.setTheme(theme);
|
||||
Display.setTextSlides(slides);
|
||||
|
||||
const slidesDiv = $(".slides")[0];
|
||||
const slidesDiv = $(".text-slides")[0];
|
||||
expect(slidesDiv.style['-webkit-text-stroke']).toEqual('42pt red');
|
||||
expect(slidesDiv.style['padding-left']).toEqual('84pt');
|
||||
expect(slidesDiv.style['-webkit-text-fill-color']).toEqual('yellow');
|
||||
})
|
||||
|
||||
it("should correctly set text alignment,\
|
||||
(check the order of alignments in the emuns are the same in both js and python)", function () {
|
||||
const slides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
"text": "Amazing grace, how sweet the sound\nThat saved a wretch like me\n" +
|
||||
"I once was lost, but now I'm found\nWas blind but now I see",
|
||||
"footer": "Public Domain"
|
||||
}
|
||||
];
|
||||
//
|
||||
const theme = {
|
||||
'display_horizontal_align': 3,
|
||||
'display_vertical_align': 1
|
||||
};
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTheme(theme);
|
||||
Display.setTextSlides(slides);
|
||||
|
||||
const slidesDiv = $(".text-slides")[0];
|
||||
expect(slidesDiv.style['text-align-last']).toEqual('justify');
|
||||
expect(slidesDiv.style['justify-content']).toEqual('center');
|
||||
})
|
||||
|
||||
it("should correctly set slide size position to theme size when adding a text slide", function () {
|
||||
const slides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
"text": "Amazing grace, how sweet the sound\nThat saved a wretch like me\n" +
|
||||
"I once was lost, but now I'm found\nWas blind but now I see",
|
||||
"footer": "Public Domain"
|
||||
}
|
||||
];
|
||||
//
|
||||
const theme = {
|
||||
'font_main_y': 789,
|
||||
'font_main_x': 1000,
|
||||
'font_main_width': 1230,
|
||||
'font_main_height': 4560
|
||||
};
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTheme(theme);
|
||||
Display.setTextSlides(slides);
|
||||
|
||||
const slidesDiv = $(".text-slides")[0];
|
||||
expect(slidesDiv.style['top']).toEqual('789px');
|
||||
expect(slidesDiv.style['left']).toEqual('1000px');
|
||||
expect(slidesDiv.style['width']).toEqual('1230px');
|
||||
expect(slidesDiv.style['height']).toEqual('4560px');
|
||||
})
|
||||
});
|
||||
|
||||
describe("Display.setImageSlides", function () {
|
||||
@ -578,12 +632,12 @@ describe("Display.setImageSlides", function () {
|
||||
expect(Display.clearSlides).toHaveBeenCalledTimes(1);
|
||||
expect(Display._slides["0"]).toEqual(0);
|
||||
expect(Display._slides["1"]).toEqual(1);
|
||||
expect($(".slides > section").length).toEqual(2);
|
||||
expect($(".slides > section > img").length).toEqual(2);
|
||||
expect($(".slides > section > img")[0].getAttribute("src")).toEqual("file:///openlp1.jpg")
|
||||
expect($(".slides > section > img")[0].getAttribute("style")).toEqual("max-width: 100%; max-height: 100%; margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);")
|
||||
expect($(".slides > section > img")[1].getAttribute("src")).toEqual("file:///openlp2.jpg")
|
||||
expect($(".slides > section > img")[1].getAttribute("style")).toEqual("max-width: 100%; max-height: 100%; margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);")
|
||||
expect($(".slides > section > section").length).toEqual(2);
|
||||
expect($(".slides > section > section > img").length).toEqual(2);
|
||||
expect($(".slides > section > section > img")[0].getAttribute("src")).toEqual("file:///openlp1.jpg")
|
||||
expect($(".slides > section > section > img")[0].getAttribute("style")).toEqual("max-width: 100%; max-height: 100%; margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);")
|
||||
expect($(".slides > section > section > img")[1].getAttribute("src")).toEqual("file:///openlp2.jpg")
|
||||
expect($(".slides > section > section > img")[1].getAttribute("style")).toEqual("max-width: 100%; max-height: 100%; margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);")
|
||||
expect(Display.reinit).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user