← Back to team overview

openlp-dev team mailing list archive

[Merge] lp:~ic90/openlp/animated-alerts into lp:~openlp-dev/openlp/webengine-migrate

 

Nico Opiyo has proposed merging lp:~ic90/openlp/animated-alerts into lp:~openlp-dev/openlp/webengine-migrate.

Commit message:
Refactored the tests and optimized alert display code plus fixed spacing

Requested reviews:
  Nico Opiyo (ic90)
  Raoul Snyman (raoul-snyman)

For more details, see:
https://code.launchpad.net/~ic90/openlp/animated-alerts/+merge/363053

Refactored the tests and optimized alert display code plus fixed spacing

JS Test Output is as below:
PhantomJS 2.1.1 (Windows 8.0.0) Display.setTextSlides should correctly set outline width FAILED
        TypeError: undefined is not an object (evaluating 'dom.wrapper.querySelectorAll') in openlp/core/display/html/reveal.js (line 2304)
        slide@openlp/core/display/html/reveal.js:2304:37
        goToSlide@openlp/core/display/html/display.js:712:19
        setTextSlides@openlp/core/display/html/display.js:569:22
        tests/js/test_display.js:365:26
PhantomJS 2.1.1 (Windows 8.0.0): Executed 68 of 68 (1 FAILED) (0 secs / 0.099 secs)
PhantomJS 2.1.1 (Windows 8.0.0): Executed 68 of 68 (1 FAILED) (0.127 secs / 0.099 secs)
TOTAL: 1 FAILED, 67 SUCCESS
-- 
Your team OpenLP Development is subscribed to branch lp:~openlp-dev/openlp/webengine-migrate.
=== modified file 'openlp/core/display/html/display.html'
--- openlp/core/display/html/display.html	2018-10-12 19:51:51 +0000
+++ openlp/core/display/html/display.html	2019-02-12 12:08:26 +0000
@@ -24,14 +24,89 @@
       visibility: visible;
       z-index: -1;
     }
+
+    /* Animation key frames for horizontal scrolling of alert */
+    @keyframes alert-scrolling-text {
+      from { margin-left: 100%; }
+      to {  margin-left: -300% }
+    }
+    /* Middle fade-in alert animation */
+    @keyframes middle-fade-in {
+      from { opacity: 0;}
+      to { opacity: 1;}
+    }
+
+    /* Middle fade-out alert animation */
+    @keyframes middle-fade-out {
+      from { opacity: 1;}
+      to { opacity: 0;}
+    }
+
+    /* Fade in when alert location is in the middle */
+    .middle-entrance-animation {
+      animation-duration: 2s;
+      animation-timing-function: linear;
+      animation-name: middle-fade-in;
+    }
+
+    /* Fade out when alert location is in the middle */
+    .middle-exit-animation {
+      animation-duration: 2s;
+      animation-timing-function: linear;
+      animation-name: middle-fade-out;
+    }
+
+    .horizontal-scroll-animation {
+      animation-duration: 10s;
+      animation-iteration-count: 1;
+      animation-timing-function: linear;
+      animation-name: alert-scrolling-text;
+    }
+
+    /* ALERT STYLING */
+    #alert-background {
+      position: absolute;
+      margin: 0;
+      padding: 0;
+      left: 0px;
+      right: 0px;
+      z-index: 10;
+      width: 100%;
+      height: 0%;
+      vertical-align: middle;
+      color: #ffffff;
+      background-color: #660000;
+      overflow: hidden;
+      visibility:hidden;
+    }
+
+    #alert {
+      position: relative;
+      top: 50%;
+      transform: translateY(-50%);
+      margin-top: 0%;
+      margin-right: 0%;
+      margin-left: 100%;
+      margin-bottom: 0%;
+      z-index: 11;
+      overflow: visible;
+      white-space: nowrap;
+      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+      font-size: 100pt;
+      color: #ffffff;
+      visibility: hidden;
+    }
+
     </style>
     <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
     <script type="text/javascript" src="reveal.js"></script>
     <script type="text/javascript" src="display.js"></script>
   </head>
+
   <body>
     <div class="reveal">
       <div id="global-background" class="slide-background present" data-loaded="true"></div>
+      <div id="alert-background"><p id="alert">Testing alerts</p></div>
       <div class="slides"></div>
       <div class="footer"></div>
     </div>

=== modified file 'openlp/core/display/html/display.js'
--- openlp/core/display/html/display.js	2019-02-05 21:26:30 +0000
+++ openlp/core/display/html/display.js	2019-02-12 12:08:26 +0000
@@ -53,6 +53,39 @@
 };
 
 /**
+ * Transition state enumeration
+ */
+
+var TransitionState = {
+   EntranceTransition: "entranceTransition",
+   NoTransition: "noTransition",
+   ExitTransition: "exitTransition"
+};
+
+/**
+ * Animation state enumeration
+ */
+var AnimationState = {
+  NoAnimation: "noAnimation",
+  ScrollingAnimation: "scrollingAnimation",
+  FadeInAnimation: "fadeInAnimation",
+  FadeOutAnimation: "fadeOutAnimation"
+};
+/**
+ * Alert location enumeration
+ */
+var AlertLocation = {
+  Top: "0",
+  Middle: "1",
+  Bottom: "2"
+};
+
+/**
+ *
+ * @param {Location} selector
+ */
+
+/**
  * 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
@@ -132,6 +165,10 @@
 }
 
 /**
+ *
+ */
+
+/**
  * An audio player with a play list
  */
 var AudioPlayer = function (audioElement) {
@@ -249,6 +286,8 @@
  */
 var Display = {
   _slides: {},
+  _transitionState: TransitionState.NoTransition,
+  _animationState: AnimationState.NoAnimation,
   _revealConfig: {
     margin: 0.0,
     minScale: 1.0,
@@ -372,15 +411,121 @@
    * @param {string} text - The alert text
    * @param {int} location - The location of the text (top, middle or bottom)
   */
- alert: function (text, location) {
-  console.debug(" alert text: " + text, ", location: " + location);
+  alert: function (text, location) {
+    console.debug(" alert text: " + text + ", location: " + location);
+
+    if (text == "") {
+      return null;
+    }
+
+    var alertBackground = $("#alert-background")[0];
+    var alertText = $("#alert")[0];
+
+    alertText.innerHTML = text;
+
+    /* Bring in the transition background */
+    Display._transitionState = Display.doEntranceTransition(location);
+
+    alertBackground.addEventListener('transitionend', function (e) {
+      e.stopPropagation();
+      if (Display._transitionState == TransitionState.EntranceTransition) {
+        alertText.style.visibility = "visible";
+        alertText.classList.add("horizontal-scroll-animation");
+      }
+      else if (Display._transitionState == TransitionState.ExitTransition) {
+        Display._transitionState = TransitionState.NoTransition;
+        alertBackground.style.visibility = "hidden";
+        alertText.style.visibility = "hidden";
+        alertBackground.style.top = "";
+        alertBackground.style.bottom = "";
+        alertBackground.style.height = "";
+        alertBackground.style.transition = "";
+        alertBackground.classList.remove("middle-exit-animation");
+      }
+    });
+
+    alertBackground.addEventListener('animationend', function () {
+
+      if (Display._animationState == AnimationState.FadeInAnimation) {
+        alertText.style.visibility = "visible";
+        alertText.classList.add("horizontal-scroll-animation");
+        alertText.classList.remove("middle-entrance-animation");
+        Display._animationState = AnimationState.ScrollingAnimation;
+      }
+      else if (Display._animationState == AnimationState.FadeOutAnimation) {
+        alertBackground.style.visibility = "hidden";
+        alertBackground.classList.remove("middle-exit-animation");
+        Display._animationState = AnimationState.NoAnimation;
+      }
+      else if (alertText.classList.contains("horizontal-scroll-animation")) {
+        alertText.classList.remove("horizontal-scroll-animation");
+        alertText.style.visibility = "hidden";
+        Display._animationState = AnimationState.NoAnimation;
+        Display._transitionState = Display.doExitTransition(location);
+      }
+
+    });
+
   /*
    * The implementation should show an alert.
    * It should be able to handle receiving a new alert before a previous one is "finished", basically queueing it.
    */
-  return;
-},
-
+    return location;
+  },
+
+  /**
+   * Start background entrance transition for display of alert
+   * @param {string} location - String showing the location of the alert on screen
+   */
+  doEntranceTransition: function (location) {
+    var alertBackground = $("#alert-background")[0];
+
+    switch (location) {
+      case AlertLocation.Top:
+        alertBackground.style.bottom = '';
+        alertBackground.style.top = '0px';        
+        alertBackground.style.height = "25%";
+        alertBackground.style.transition = "2s linear";
+        break;
+      case AlertLocation.Middle:
+        alertBackground.style.top = ((window.innerHeight - alertBackground.clientHeight) / 2) + 'px';
+        alertBackground.style.height = "25%";
+        alertBackground.classList.add("middle-entrance-animation");
+        Display._animationState = AnimationState.FadeInAnimation;
+        break;
+      case AlertLocation.Bottom:
+      default:
+        alertBackground.style.top = '';
+        alertBackground.style.bottom = '0px';        
+        alertBackground.style.height = "25%";
+        alertBackground.style.transition= "2s linear";
+        break;
+    }
+    alertBackground.style.visibility = "visible";
+    return TransitionState.EntranceTransition;
+
+  },
+
+  /**
+   * Start background exit transition once alert has been displayed
+   * @param {string} location - Integer showing the location of the alert on screen
+   */
+  doExitTransition: function (location) {
+
+    var alertBackground = $("#alert-background")[0];
+
+    if (location == AlertLocation.Top || location == AlertLocation.Bottom) {
+      alertBackground.style.height = "0%";
+      alertBackground.style.transition = '2s linear';      
+    }
+    else if (location == AlertLocation.Middle) {
+      alertBackground.classList.add("middle-exit-animation");
+      alertBackground.style.height = "0%";      
+      Display._animationState = AnimationState.FadeOutAnimation;
+    }
+
+    return TransitionState.ExitTransition;
+  },
   /**
    * Add a slides. If the slide exists but the HTML is different, update the slide.
    * @param {string} verse - The verse number, e.g. "v1"

=== modified file 'openlp/core/display/window.py'
--- openlp/core/display/window.py	2018-12-06 20:26:35 +0000
+++ openlp/core/display/window.py	2019-02-12 12:08:26 +0000
@@ -401,4 +401,4 @@
         """
         Set an alert
         """
-        self.run_javascript('Display.alert({text}, {location});'.format(text=text, location=location))
+        self.run_javascript('Display.alert("{text}", "{location}");'.format(text=text, location=location))

=== modified file 'tests/js/test_display.js'
--- tests/js/test_display.js	2019-01-16 06:15:21 +0000
+++ tests/js/test_display.js	2019-02-12 12:08:26 +0000
@@ -18,6 +18,14 @@
   it("AudioState should exist", function () {
     expect(AudioState).toBeDefined();
   });
+
+  it("TransitionState should exist", function(){
+    expect(TransitionState).toBeDefined();
+  });
+
+  it("AnimationState should exist", function(){
+    expect(AnimationState).toBeDefined();
+  });
 });
 
 describe("The function", function () {
@@ -138,7 +146,111 @@
     Display.goToSlide("v1");
     expect(Reveal.slide).toHaveBeenCalledWith(0);
   });
-});
+
+  it("should have an alert() method", function () {
+    expect(Display.alert).toBeDefined();
+  });
+
+});
+
+describe("Display.alert", function () {
+  var alertBackground, alert;
+
+  beforeEach(function () {
+    document.body.innerHTML = "";
+    alertBackground = document.createElement("div");
+    alertBackground.setAttribute("id", "alert-background");
+    document.body.appendChild(alertBackground);
+    alert = document.createElement("p");
+    alert.setAttribute("id","alert");
+    alertBackground.appendChild(alert);
+  });
+
+  it("should return null if called without any text", function () {
+    expect(Display.alert("","2")).toBeNull();
+  });
+
+  it("should set correct alert text", function () {
+    Display.alert("OPEN-LP-3.0 Alert Test", "2");
+    expect(alert.innerHTML).toEqual("OPEN-LP-3.0 Alert Test");
+  });
+
+  it("should set the correct alert position", function () {
+    expect(Display.alert("Alert Location Test","2")).toEqual("2");
+  });
+});
+
+describe("The doEntranceTransition", function () {
+
+  var alertBackground;
+
+  beforeEach(function() {
+    document.body.innerHTML = "";
+    alertBackground = document.createElement("div");
+    alertBackground.setAttribute("id", "alert-background");
+    document.body.appendChild(alertBackground);
+    alertBackground.style.top = '0px';
+    alertBackground.style.height = "0%";
+  });
+
+  it("should set the correct styles for the alert when location is top of the page", function () {
+    Display.doEntranceTransition("0");
+    expect(alertBackground.style.bottom).toEqual('');
+    expect(alertBackground.style.top).toEqual('0px');
+    expect(alertBackground.style.transition).toEqual("2s linear");
+    expect(alertBackground.style.height).toEqual("25%");
+    expect(alertBackground.style.visibility).toEqual("visible");
+  });
+
+  it("should set the correct styles for the alert when location is middle of the page", function () {
+    Display.doEntranceTransition("1");
+    var middlePosition = ((window.innerHeight - alertBackground.clientHeight) / 2) + 'px';
+    expect(alertBackground.style.top).toEqual(middlePosition);
+    expect(alertBackground.classList.contains("middle-entrance-animation"));
+    expect(alertBackground.style.height).toEqual("25%");
+    expect(alertBackground.style.visibility).toEqual("visible");
+  });
+
+  it("should set the correct styles for the alert when location is bottom of the page", function () {
+    Display.doEntranceTransition("2");
+    expect(alertBackground.style.top).toEqual('');
+    expect(alertBackground.style.bottom).toEqual('0px');    
+    expect(alertBackground.style.transition).toEqual("2s linear");
+    expect(alertBackground.style.height).toEqual("25%");
+    expect(alertBackground.style.visibility).toEqual("visible");
+  });
+});
+
+describe("The doExitTransition", function () {
+  var alertBackground;
+
+  beforeEach(function () {
+    document.body.innerHTML = "";
+    alertBackground = document.createElement("div");
+    alertBackground.setAttribute("id", "alert-background");
+    document.body.appendChild(alertBackground);
+  });
+
+  it("should remove the styles correctly when the location is the top of the page", function () {
+    Display.doExitTransition("0");
+    expect(alertBackground.style.height).toEqual('0%');
+    expect(alertBackground.style.transition).toEqual("2s linear");
+  });
+
+  it("should remove the styles correctly when the location is middle of the page", function () {
+    Display.doExitTransition("1");
+    expect(alertBackground.style.height).toEqual('0%');
+    expect(alertBackground.classList.contains("middle-exit-animation"));
+  });
+
+it("should remove the styles correctly when the location is the bottom of the page", function () {
+  Display.doExitTransition("2");
+  expect(alertBackground.style.height).toEqual('0%');
+  expect(alertBackground.style.transition).toEqual("2s linear");
+});
+
+});
+
 
 describe("Display.addTextSlide", function () {
   beforeEach(function() {


Follow ups