From ac958f98da20332393d4b6d11adbb9d0ec2a3ed5 Mon Sep 17 00:00:00 2001
From: Fabio Manganiello <blacklight86@gmail.com>
Date: Sat, 5 May 2018 04:37:22 +0200
Subject: [PATCH] Added images carousel web widget

---
 .gitignore                                    |  1 +
 platypush/backend/http/__init__.py            | 24 ++++++++++++
 .../backend/http/static/css/dashboard.css     |  7 +---
 .../static/css/widgets/image-carousel.css     |  8 ++++
 .../http/static/js/widgets/image-carousel.js  | 37 +++++++++++++++++++
 .../backend/http/static/resources/README      |  1 +
 .../backend/http/templates/dashboard.html     | 20 ++++++++--
 .../templates/widgets/image-carousel.html     | 12 ++++++
 8 files changed, 102 insertions(+), 8 deletions(-)
 create mode 100644 platypush/backend/http/static/css/widgets/image-carousel.css
 create mode 100644 platypush/backend/http/static/js/widgets/image-carousel.js
 create mode 100644 platypush/backend/http/static/resources/README
 create mode 100644 platypush/backend/http/templates/widgets/image-carousel.html

diff --git a/.gitignore b/.gitignore
index ec2b7e074..4d5002226 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ dist/
 *.egg-info/
 package.sh
 .pypirc
+platypush/backend/http/static/resources/*
diff --git a/platypush/backend/http/__init__.py b/platypush/backend/http/__init__.py
index 2f4dd1ad3..53fb3b934 100644
--- a/platypush/backend/http/__init__.py
+++ b/platypush/backend/http/__init__.py
@@ -3,6 +3,7 @@ import inspect
 import logging
 import json
 import os
+import re
 import time
 
 from threading import Thread
@@ -235,6 +236,29 @@ class HttpUtils(object):
             raise RuntimeError('Constraint violation: should be 1 <= columns <= 12, ' +
                                'got columns={}'.format(columns))
 
+    @staticmethod
+    def search_directory(directory, *extensions, recursive=False):
+        files = []
+
+        if recursive:
+            for root, subdirs, files in os.walk(directory):
+                for file in files:
+                    if not extensions or os.path.splitext(file)[1].lower() in extensions:
+                        files.append(os.path.join(root, file))
+        else:
+            for file in os.listdir(directory):
+                if not extensions or os.path.splitext(file)[1].lower() in extensions:
+                    files.append(os.path.join(directory, file))
+
+        return files
+
+    @classmethod
+    def search_web_directory(cls, directory, *extensions):
+        directory = re.sub('^/+', '', directory)
+        basedir = os.path.dirname(inspect.getfile(cls))
+        results = cls.search_directory(os.path.join(basedir, directory), *extensions)
+        return [item[len(basedir):] for item in results]
+
 
 # vim:sw=4:ts=4:et:
 
diff --git a/platypush/backend/http/static/css/dashboard.css b/platypush/backend/http/static/css/dashboard.css
index 2fa596f7d..1b92afdfa 100644
--- a/platypush/backend/http/static/css/dashboard.css
+++ b/platypush/backend/http/static/css/dashboard.css
@@ -3,14 +3,11 @@ body {
     font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
 }
 
-#widgets-container {
-    padding: 2em;
-}
-
 .widget {
     background: white;
+    margin-top: 2em;
     border-radius: 5px;
-    height: 25em;
+    height: 22.5em;
     overflow: hidden;
     box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16), 0 0 0 1px rgba(0,0,0,0.08);
 }
diff --git a/platypush/backend/http/static/css/widgets/image-carousel.css b/platypush/backend/http/static/css/widgets/image-carousel.css
new file mode 100644
index 000000000..69344f243
--- /dev/null
+++ b/platypush/backend/http/static/css/widgets/image-carousel.css
@@ -0,0 +1,8 @@
+.carousel {
+    height: 100%;
+    background-color: black;
+    background-size: auto 100%;
+    background-position: center;
+    background-repeat: no-repeat;
+}
+
diff --git a/platypush/backend/http/static/js/widgets/image-carousel.js b/platypush/backend/http/static/js/widgets/image-carousel.js
new file mode 100644
index 000000000..d3cfa6bc2
--- /dev/null
+++ b/platypush/backend/http/static/js/widgets/image-carousel.js
@@ -0,0 +1,37 @@
+$(document).ready(function() {
+    var $imgElement = $('.image-carousel').find('.carousel'),
+        config = window.widgets['image-carousel'],
+        images = config.imageUrls,
+        processedImages = 0;
+
+    var shuffleImages = function() {
+		for (var i=images.length-1; i > 0; i--) {
+			var j = Math.floor(Math.random() * (i + 1));
+			var x = images[i];
+			images[i] = images[j];
+			images[j] = x;
+        }
+    };
+
+    var refreshImage = function() {
+        $imgElement.css('background-image', "url('" + images[processedImages++] + "')");
+        if (processedImages == images.length-1) {
+            shuffleImages();
+            processedImages = 0;
+        }
+    };
+
+    var initWidget = function() {
+        shuffleImages();
+        refreshImage();
+        setInterval(refreshImage,
+            'refresh_seconds' in config ? config.refresh_seconds * 1000 : 15000);
+    };
+
+    var init = function() {
+        initWidget();
+    };
+
+    init();
+});
+
diff --git a/platypush/backend/http/static/resources/README b/platypush/backend/http/static/resources/README
new file mode 100644
index 000000000..7024be140
--- /dev/null
+++ b/platypush/backend/http/static/resources/README
@@ -0,0 +1 @@
+Place in this folder the static resources you want to serve over HTTP (images, fonts etc.)
diff --git a/platypush/backend/http/templates/dashboard.html b/platypush/backend/http/templates/dashboard.html
index 19926bab9..0415ee5a7 100644
--- a/platypush/backend/http/templates/dashboard.html
+++ b/platypush/backend/http/templates/dashboard.html
@@ -17,20 +17,27 @@
     <script type="text/javascript" src="{{ url_for('static', filename='js/pushbullet.js') }}"></script>
     <script type="text/javascript" src="{{ url_for('static', filename='js/assistant.google.js') }}"></script>
     <script type="text/javascript">
-        window.websocket_port = {% print(websocket_port) %}
+        window.websocket_port = {% print(websocket_port) %};
 
         {% if token %}
-            window.token = '{% print(token) %}'
+            window.token = '{% print(token) %}';
         {% else %}
-            window.token = undefined
+            window.token = undefined;
         {% endif %}
+
+        window.widgets = {{ config['widgets'] | safe }};
     </script>
 </head>
 
 <body>
     <main>
         <div id="widgets-container">
+            {% set used_columns = [0] %}
             {% for widget_name, widget in config['widgets'].items() %}
+                {% if used_columns[0] % 12 == 0 %}
+                <div class="row">
+                {% endif %}
+
                 <div class="widget {% print(utils.widget_columns_to_html_class(widget['columns'])) %}
                         {% print(widget_name) %}"
                         id="{% print(widget['id'] if 'id' in widget else widget_name) %}">
@@ -38,6 +45,13 @@
                         {% include 'widgets/' + widget_name + '.html' %}
                     {% endwith %}
                 </div>
+
+                {# increment counter #}
+                {% if used_columns.append(used_columns.pop() + widget['columns']) %}{% endif %}
+
+                {% if used_columns[0] % 12 == 0 %}
+                </div>
+                {% endif %}
             {% endfor %}
         </div>
 
diff --git a/platypush/backend/http/templates/widgets/image-carousel.html b/platypush/backend/http/templates/widgets/image-carousel.html
new file mode 100644
index 000000000..30e10533d
--- /dev/null
+++ b/platypush/backend/http/templates/widgets/image-carousel.html
@@ -0,0 +1,12 @@
+<script type="text/javascript" src="{{ url_for('static', filename='js/widgets/image-carousel.js') }}"></script>
+<link rel="stylesheet" href="{{ url_for('static', filename='css/widgets/image-carousel.css') }}"></script>
+
+{% set images = utils.search_web_directory(
+    widget['images_path'], '.jpg', 'jpeg', '.png') %}
+
+<script type="text/javascript">
+    window.widgets['image-carousel'].imageUrls = {{ images|safe }};
+</script>
+
+<div class="carousel"></div>
+