diff --git a/config-default.js b/config-default.js index 1079d91..babaa02 100644 --- a/config-default.js +++ b/config-default.js @@ -58,17 +58,14 @@ module.exports = { "displays": [ { - "id": 1, "name": "Big Screen", "bundle": "default" }, { - "id": 2, "name": "Secondary Screen", "bundle": "set1" }, { - "id": 3, "name": "Kiosk", "bundle": "default" } diff --git a/locales/en/translation.json b/locales/en/translation.json index c21026e..186d80b 100644 --- a/locales/en/translation.json +++ b/locales/en/translation.json @@ -23,7 +23,8 @@ "createNew": "Create New", "createNewSlide": "Create New Slide", "addWebPage": "Add Web page", - "announce": "Fast Announce" + "announce": "Fast Announce", + "announceAll": "Global Announce" }, "navs": { "bundle": "bundle", diff --git a/locales/fi/translation.json b/locales/fi/translation.json index e9d98e8..4efe47f 100644 --- a/locales/fi/translation.json +++ b/locales/fi/translation.json @@ -23,7 +23,8 @@ "createNew": "Luo Uusi", "createNewSlide": "Luo uusi dia", "addWebPage": "Lisää Web-sivu", - "announce": "Ilmoita" + "announce": "Ilmoita", + "announceAll": "Ilmoita Kaikille" }, "navs": { "bundle": "DiaPaketti", diff --git a/modules/admin.js b/modules/admin.js index 2bbcb8a..be902e3 100644 --- a/modules/admin.js +++ b/modules/admin.js @@ -206,10 +206,16 @@ class admin { // override socket.on('admin.override', function (data) { try { - let view = getView(parseInt(data.displayId)); - view.overrideSlide(data.json, data.png, data.duration); - - view.displayCurrentSlide(); + if (data.displayId === null) { + if (data.duration == null || data.duration <= 5) { + data.duration = 45; + } + dispatcher.emit("all.override", data); + } else { + let view = getView(parseInt(data.displayId)); + view.overrideSlide(data.json, data.png, data.duration); + view.displayCurrentSlide(); + } } catch (err) { cli.error("error, admin.override", err); } @@ -223,9 +229,8 @@ class admin { }); socket.on('admin.dashboard.sync', function (data) { - cli.error("admin.dashboard.sync is deprecated!"); - // syncDashboard(socket, 0); - // updateDashboard(socket, data.displayId); + syncDashboard(socket, data.displayId); + updateDashboard(socket, data.displayId); }); socket.on('admin.setDisplay', function (data) { diff --git a/modules/display.js b/modules/display.js index 5c526b8..b97cd5e 100644 --- a/modules/display.js +++ b/modules/display.js @@ -65,6 +65,12 @@ class display { * @listens event:announce * */ + + dispatcher.on("all.override", function (data) { + self.overrideSlide(data.json, data.png, data.duration); + self.displayCurrentSlide(); + }); + dispatcher.on("announce", function (obj) { // if global announce, ie screens is null if (obj.screens == null) { @@ -109,6 +115,7 @@ class display { init(meta) { + this.io.emit("callback.reload"); this.changeBundle(meta.bundle); } @@ -127,6 +134,7 @@ class display { this.serverOptions.currentId = bundle.enabledSlides.indexOf(this.serverOptions.currentFile); this.serverOptions.transition = bundle.getBundleData().transition; this.serverOptions.loop = true; + this.io.emit("callbackLoad", this.getSlideData()); this.mainLoop(); } diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..b481474 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/js/display.js b/public/js/display.js index d722efe..b529cbe 100644 --- a/public/js/display.js +++ b/public/js/display.js @@ -44,7 +44,7 @@ $(function () { var layer = 0; var flvPlayer; - +var doNext = false; /** bundleData * @see data/default/bundle.json * @@ -85,6 +85,7 @@ function getLayer(offset) { /** when connected **/ socket.on('connect', function () { socket.emit("sync"); + doNext = true; }); socket.on('callback.blackout', function (data) { @@ -117,7 +118,10 @@ socket.on('callbackLoad', function (data) { checkBlackout(); setBackground(data.bundleData.background); if (checkStream(serverOptions) === false) { - nextSlide(data); + if (doNext) { + doNext = false; + nextSlide(data); + } } }); @@ -198,7 +202,7 @@ function checkBlackout() { function nextSlide(data) { serverOptions = data.serverOptions; bundleData = data.bundleData; - checkImages(data.slides); + var needWait = checkImages(data.slides); checkTimeDisplay(); if (serverOptions.isAnnounce) { @@ -208,17 +212,17 @@ function nextSlide(data) { clearIFrame(getWebLayer()); clearIFrame(getWebLayer(1)); }, 2500); - $("#slider").show(); - $("#slider").addClass(); - $("#helperLayer").addClass("announce"); try { var randomId = uuidv4(); - var image = new Image(); - image.src = "/tmp/" + serverOptions.displayId + "/?randomId=" + randomId; - image.id = randomId; - image.class = "temp"; - window.f.images.push(image); - window.f.showTempImage(randomId); + getDataUri("/tmp/" + serverOptions.displayId + "/?randomId=" + randomId, randomId, function (imageId, dataUrl, image) { + image.id = imageId; + image.class = "temp"; + window.f.images.push(image); + window.f.imageData.push(dataUrl); + $("#slider").show(); + $("#helperLayer").addClass("announce"); + window.f.showTempImage(imageId); + }); } catch (err) { console.log(err); } @@ -246,7 +250,10 @@ function nextSlide(data) { }, 2500); $("#slider").show(); - window.f.showImageById(serverOptions.currentFile, transition); + setTimeout(function () { + window.f.showImageById(serverOptions.currentFile, transition); + }, needWait ? 1000 : 50); + break; } } @@ -293,9 +300,7 @@ function showBackgroundOnly() { } function checkStream(serverOptions) { - if (serverOptions.isStreaming && streamStarted === false) { - console.log("start stream!"); if (flvjs.isSupported()) { var videoElement = document.getElementById('bgvid'); flvPlayer = flvjs.createPlayer({ @@ -327,6 +332,7 @@ function checkStream(serverOptions) { flvPlayer = null; streamStarted = false; } + return false; } return false; } @@ -339,31 +345,30 @@ function checkStream(serverOptions) { */ function preloadImages(allSlides) { window.f.clearImages(); - for (var i in allSlides) { try { if (allSlides[i].type === "slide") { - var image = new Image(); - image.src = "/render/" + serverOptions.currentBundle + "/" + allSlides[i].uuid + ".png"; - image.id = allSlides[i].uuid; - window.f.images.push(image); + getDataUri("/render/" + serverOptions.currentBundle + "/" + allSlides[i].uuid + ".png", allSlides[i].uuid, function (imageId, imageData, image) { + image.id = imageId; + window.f.images.push(image); + window.f.imageData.push(imageData); + }); } } catch (err) { console.log(err); } } - window.f.setupImages(); } function reloadImage(data) { if (serverOptions.currentBundle === data.bundleName) { window.f.clearImageById(data.uuid); window.f.setupImages(); - - var image = new Image(); - image.src = "/render/" + data.bundleName + "/" + data.uuid + ".png?" + uuidv4(); - image.id = data.uuid; - window.f.images.push(image); + getDataUri("/render/" + data.bundleName + "/" + data.uuid + ".png?" + uuidv4(), data.uuid, function (imageId, imageData, image) { + image.id = imageId; + window.f.images.push(image); + window.f.imageData.push(imageData); + }); } } @@ -398,18 +403,20 @@ function checkImages(allSlides) { for (var i in allIds) { try { if (fluxIds.indexOf(allIds[i]) < 0) { - var image = new Image(); - image.src = "/render/" + serverOptions.currentBundle + "/" + allIds[i] + ".png"; - image.id = allIds[i]; - window.f.images.push(image); + getDataUri("/render/" + serverOptions.currentBundle + "/" + allIds[i] + ".png", allIds[i], function (imageId, imageData, image) { + image.id = imageId; + window.f.images.push(image); + window.f.imageData.push(imageData); + }); + return true; } } catch (err) { console.log(err); + return false; } } } - - + return false; } /** Generate an uuid @@ -431,9 +438,7 @@ function updateTimeout() { function displayWebPage(url) { - var ifr = document.getElementById(getWebLayer()); - ifr.contentWindow.location.href = url; - $("#" + getWebLayer()).addClass("fadeIn").removeClass("fadeOut"); + $("#" + getWebLayer()).attr('src', url).addClass("fadeIn").removeClass("fadeOut"); $("#" + getWebLayer(1)).addClass("fadeOut").removeClass("fadeIn"); layer++; if (layer > 1) { @@ -446,12 +451,22 @@ function getWebLayer(offset) { return "webLayer" + (layer + offset) % 2; } -function clearIFrame(elementId) { - var frame = document.getElementById(elementId); - - if (frame.contentWindow.location.href !== document.location.origin + "/empty") { - frame.contentWindow.location.href = "/empty"; +function clearIFrame(id) { + if ($('#' + id).attr('src') !== "/empty") { + $('#' + id).attr('src', '/empty'); } } +function getDataUri(url, imageId, callback) { + var image = new Image(); + image.onload = function () { + var canvas = document.createElement('canvas'); + canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size + canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size + + canvas.getContext('2d').drawImage(this, 0, 0); + callback(imageId, canvas.toDataURL('image/png'), this); + }; + image.src = url; +} diff --git a/public/js/displayLite.js b/public/js/displayLite.js index 580c6fa..def0551 100644 --- a/public/js/displayLite.js +++ b/public/js/displayLite.js @@ -26,6 +26,67 @@ $(function () { fixImageSizes(); displayTime(); setInterval(displayTime, 1000); + +// socketio callbacks + /** when connected **/ + socket.on('connect', function () { + socket.emit("sync"); + }); + + socket.on('error', function () { + $("#networkstatus").css("opacity", 1); + }); + + socket.on('disconnect', function () { + $("#networkstatus").css("opacity", 1); + }); + + socket.on('pong', function () { + updateTimeout(); + }); + + socket.on('callback.blackout', function (data) { + serverOptions = data.serverOptions; + checkBlackout(); + }); + + socket.on('callback.time', function (data) { + serverOptions.displayTime = data; + checkTimeDisplay(); + }); + + + /** callback Load **/ + socket.on('callbackLoad', function (data) { + serverOptions = data.serverOptions; + bundleData = data.bundleData; + checkBlackout(); + nextSlide(data); + }); + + + /** callback Update **/ + socket.on('callback.update', function (data) { + serverOptions = data.serverOptions; + bundleData = data.bundleData; + checkBlackout(); + nextSlide(data); + }); + + socket.on('callback.reload', function () { + location.reload(true); + }); + + socket.on('callback.announce', function (data) { + checkBlackout(); + nextSlide(data); + }); + + socket.on('callback.forceSlide', function (data) { + checkBlackout(); + nextSlide(data); + }); + }); $(window).bind("resize", function () { @@ -39,68 +100,6 @@ function getLayer(offset) { } -// socketio callbacks -/** when connected **/ -socket.on('connect', function () { - console.log("connect, calling sync!"); - socket.emit("sync"); -}); - -socket.on('error', function () { - $("#networkstatus").css("opacity", 1); -}); - -socket.on('disconnect', function () { - $("#networkstatus").css("opacity", 1); -}); - -socket.on('pong', function () { - updateTimeout(); -}); - -socket.on('callback.blackout', function (data) { - serverOptions = data.serverOptions; - checkBlackout(); -}); - -socket.on('callback.time', function (data) { - serverOptions.displayTime = data; - checkTimeDisplay(); -}); - - -/** callback Load **/ -socket.on('callbackLoad', function (data) { - serverOptions = data.serverOptions; - bundleData = data.bundleData; - checkBlackout(); - nextSlide(data); -}); - - -/** callback Update **/ -socket.on('callback.update', function (data) { - serverOptions = data.serverOptions; - bundleData = data.bundleData; - checkBlackout(); - nextSlide(data); -}); - -socket.on('callback.reload', function () { - location.reload(true); -}); - -socket.on('callback.announce', function (data) { - checkBlackout(); - nextSlide(data); -}); - -socket.on('callback.forceSlide', function (data) { - checkBlackout(); - nextSlide(data); -}); - - /** * Displays the local time for bottom of screen * hh:mm @@ -161,9 +160,9 @@ function nextSlide(data) { $("#" + getWebLayer()).addClass("fadeOut").removeClass("fadeIn"); $("#" + getWebLayer(1)).addClass("fadeOut").removeClass("fadeIn"); setTimeout(function () { - clearIFrame(getLayer()); - clearIFrame(getLayer(1)); - }, 1000); + clearIFrame(getWebLayer()); + clearIFrame(getWebLayer(1)); + }, 1500); $("#helperLayer").addClass("announce"); try { @@ -307,9 +306,7 @@ function uuidv4() { var weblayer = 0; function displayWebPage(url) { - var ifr = document.getElementById(getWebLayer()); - ifr.contentWindow.location.href = url; - $("#" + getWebLayer()).addClass("fadeIn").removeClass("fadeOut"); + $("#" + getWebLayer()).attr('src', url).addClass("fadeIn").removeClass("fadeOut"); $("#" + getWebLayer(1)).addClass("fadeOut").removeClass("fadeIn"); weblayer++; if (weblayer > 1) { @@ -323,8 +320,8 @@ function getWebLayer(offset) { } function clearIFrame(id) { - var frame = document.getElementById(id), - frameDoc = frame.contentDocument || frame.contentWindow.document; - frameDoc.documentElement.innerHTML = ""; + if ($('#' + id).attr('src') !== "/empty") { + $('#' + id).attr('src', '/empty'); + } } diff --git a/public/js/edit.js b/public/js/edit.js index 8397056..600ee98 100644 --- a/public/js/edit.js +++ b/public/js/edit.js @@ -546,31 +546,34 @@ function removeSelectedObjects() { } -function cueSlide() { - if (displayId !== null) { - if (confirm('Force display of the current slide?')) { - var duration = null; - if ($.isNumeric($("#duration").val())) { - duration = parseFloat($("#duration").val()); - } - - var objects = canvas.getObjects('line'); - for (let i in objects) { - canvas.remove(objects[i]); - } - - let obj = { - json: canvas.toJSON(['id']), - png: canvas.toDataURL('png'), - displayId: displayId, - duration: duration - }; - socket.emit("admin.override", obj); - - drawGrid(); +function cueSlide(id) { + if (id === null) { + var bool = confirm('You are about to display the current slide for ALL DISPLAYS, are you sure?') + if (bool === false) { + return; } - } else { - alert("Can't find display to announce"); + } + + if (confirm('Force display of the current slide?') && bool) { + var duration = null; + if ($.isNumeric($("#duration").val())) { + duration = parseFloat($("#duration").val()); + } + + var objects = canvas.getObjects('line'); + for (let i in objects) { + canvas.remove(objects[i]); + } + + let obj = { + json: canvas.toJSON(['id']), + png: canvas.toDataURL('png'), + displayId: id, + duration: duration + }; + socket.emit("admin.override", obj); + + drawGrid(); } } diff --git a/public/js/flux.js b/public/js/flux.js index 4d4a0df..12d451e 100644 --- a/public/js/flux.js +++ b/public/js/flux.js @@ -72,6 +72,7 @@ window.flux = { this.options.transitions = newTrans; this.images = []; + this.imageData = []; this.imageLoadedCount = 0; this.currentImageIndex = 0; this.nextImageIndex = 1; @@ -229,20 +230,18 @@ window.flux = { this.setNextIndex(index); // Temporarily stop the transition interval - //clearInterval(this.interval); - //this.interval = null; + // clearInterval(this.interval); + // this.interval = null; this.setupImages(); this.transition(trans, opts); }, showImageById: function (id, trans, opts) { - let i = 0; - for (var img of this.images) { - if (img.id === id) { + for (var i in this.images) { + if (this.images[i].id === id) { this.showImage(i, trans, opts); break; } - i++; } this.clearTempImages(); }, @@ -257,20 +256,21 @@ window.flux = { } }, clearImages: function () { - delete this.images; this.images = []; + this.imageData = []; }, clearTempImages: function () { for (var i in this.images) { if (this.images[i].class === "temp") { this.images.splice(i, 1); + this.imageData.splice(i, 1); } } }, clearImageById: function (id) { for (var i in this.images) { if (this.images[i].id === id) { - + this.imageData.splice(i, 1); this.images.splice(i, 1); } } @@ -400,29 +400,20 @@ window.flux = { this.updateCaption(); }, setupImages: function () { - var img1 = this.getImage(this.currentImageIndex); + + var img1 = this.getImageData(this.currentImageIndex); css1 = { - 'background-image': 'url("' + img1.src + '")', + 'background-image': 'url("' + img1.replace(/(\r\n|\n|\r)/gm, "") + '")', 'z-index': 101, 'cursor': 'auto', 'background-repeat': 'no-repeat', 'background-size': this.options.width + "px " + this.options.height + "px" }; - // Does this image have an associated link? - if ($(img1).data('href')) { - css1.cursor = 'pointer'; - this.image1.addClass('hasLink'); - this.image1.data('href', $(img1).data('href')); - } else { - this.image1.removeClass('hasLink'); - this.image1.data('href', null); - } - this.image1.css(css1).children().remove(); - + var img2 = this.getImageData(this.nextImageIndex); this.image2.css({ - 'background-image': 'url("' + this.getImage(this.nextImageIndex).src + '")', + 'background-image': 'url("' + img2.replace(/(\r\n|\n|\r)/gm, "") + '")', 'z-index': 100, 'background-repeat': 'no-repeat', 'background-size': this.options.width + "px " + this.options.height + "px", @@ -470,6 +461,11 @@ window.flux = { return this.images[index]; }, + getImageData: function (index) { + index = index % this.imageData.length; + + return this.imageData[index]; + }, setNextIndex: function (nextIndex) { if (nextIndex == undefined) nextIndex = this.currentImageIndex + 1; diff --git a/routes/index.js b/routes/index.js index 6842131..bde1ba8 100644 --- a/routes/index.js +++ b/routes/index.js @@ -24,11 +24,20 @@ module.exports = function (websocket, dispatcher) { res.render('index', {config: config}); }); + router.get('/favicon.ico', function (req, res, next) { + res.send("public/favicon.ico"); + }); + router.get('/display/:id/lite', function (req, res, next) { res.header('Access-Control-Allow-Origin', '*'); let idx = parseInt(req.params.id); let volume = req.params.videoVolume || 1.; - res.render('liteDisplay', {config: config, display: availableDisplays[idx], displayId: idx, videoVolume: volume}); + res.render('liteDisplay', { + config: config, + display: availableDisplays[idx], + displayId: idx, + videoVolume: volume + }); }); router.get('/display/:id', function (req, res, next) { diff --git a/views/admin/editSlide.twig b/views/admin/editSlide.twig index acd7801..b7a090b 100644 --- a/views/admin/editSlide.twig +++ b/views/admin/editSlide.twig @@ -66,9 +66,10 @@
{{ t("actions.save") }} {% if displayId != null %} - {{ t("actions.announce") }} + {{ t("actions.announce") }} {% endif %} - {{ t("actions.cancel") }} + {{ t("actions.announceAll") }} + {{ t("actions.cancel") }}
diff --git a/views/admin/overview.twig b/views/admin/overview.twig index fbbd41c..edcb23e 100644 --- a/views/admin/overview.twig +++ b/views/admin/overview.twig @@ -2,12 +2,18 @@ {% block header %} + {% endblock %} {% block body %}
+

+ {{ t ("infoscreen") }} +

{{ t("index.displays") }}

@@ -18,13 +24,89 @@

{{ display.name }}

- View + + +
+ + + + + + + +
{% endfor %}
-{% endblock %} + + +{% endblock %} \ No newline at end of file diff --git a/views/liteDisplay.twig b/views/liteDisplay.twig index 63a45bd..f64fe36 100644 --- a/views/liteDisplay.twig +++ b/views/liteDisplay.twig @@ -19,13 +19,13 @@
- - + + -
+
-
+
@@ -40,9 +40,13 @@ {% endblock %}