diff --git a/htroot/env/base.css b/htroot/env/base.css
index 08e0759d9..3cd0e750e 100644
--- a/htroot/env/base.css
+++ b/htroot/env/base.css
@@ -1089,6 +1089,29 @@ div#tagcloud {
z-index: 100;
}
+
+ /******* yacysearch.html **********
+
+ /* Higlight overall audio controls when playing all results */
+#audioControls:not([data-current-track="-1"]) {
+ border-style: solid;
+ border-color: #1e90ff;
+}
+
+#stopAllBtn:hover {
+ color: red;
+}
+
+#playAllBtn:hover .glyphicon-play {
+ color: #32cd32;
+}
+
+#playAllBtn:hover .glyphicon-pause {
+ color: #ff8c00;
+}
+
+/******* yacysearch.html end ***********/
+
/******* yacysearchtrailer.html **********
Styling for the resource switch button, to avoid overlapping at various screen sizes */
diff --git a/htroot/js/yacysearch.js b/htroot/js/yacysearch.js
index 51eb81ea8..09305031d 100644
--- a/htroot/js/yacysearch.js
+++ b/htroot/js/yacysearch.js
@@ -286,52 +286,11 @@ function toggleMoreTags(button, moreTagsId) {
}
}
-/**
- * Handle embedded audio result load error.
- *
- * @param event
- * {ErrorEvent} the error event triggered
- */
-function handleAudioLoadError(event) {
- if (event != null && event.target != null) {
- /* Fill the title attribute to provide some feedback about the error without need for looking at the console */
- if (event.target.error != null && event.target.error.message) {
- event.target.title = "Cannot play ("
- + event.target.error.message + ")";
- } else {
- event.target.title = "Cannot play";
- }
-
- /* Apply CSS class marking error for visual feedback*/
- event.target.className = "audioError";
- }
-}
-
-/**
- * Handle embedded audio result 'playing' event : pauses any other currently
- * playing audio.
- *
- * @param event
- * {Event} a 'playing' event
- */
-function handleAudioPlaying(event) {
- if (event != null && event.target != null) {
- var audioElems = document.getElementsByTagName("audio");
- if(audioElems != null) {
- for (var i = 0; i < audioElems.length; i++) {
- var audioElem = audioElems[i];
- if (audioElem != event.target && audioElem.pause
- && !audioElem.paused) {
- audioElem.pause();
- }
- }
- }
- }
-}
-
/**
* Handle a rendering error on a result image thumbnail.
- * @param imgElem {HTMLImageElement} the html img element that could not be rendered
+ *
+ * @param imgElem
+ * {HTMLImageElement} the html img element that could not be rendered
*/
function handleResultThumbError(imgElem) {
if (imgElem.parentNode != null && imgElem.parentNode.parentNode != null
diff --git a/htroot/js/yacysearchAudio.js b/htroot/js/yacysearchAudio.js
new file mode 100644
index 000000000..3d04cd663
--- /dev/null
+++ b/htroot/js/yacysearchAudio.js
@@ -0,0 +1,294 @@
+/*
+* Copyright (C) 2019 by luccioman; https://github.com/luccioman
+*
+* This file is part of YaCy.
+*
+* YaCy is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 2 of the License, or
+* (at your option) any later version.
+*
+* YaCy is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with YaCy. If not, see .
+*/
+
+/* Functions dedicated to control playing of YaCy audio search results */
+
+/**
+ * Handle embedded audio result load error.
+ *
+ * @param event
+ * {ErrorEvent} the error event triggered
+ */
+function handleAudioLoadError(event) {
+ if (event != null && event.target != null) {
+ /* Fill the title attribute to provide some feedback about the error without need for looking at the console */
+ if (event.target.error != null && event.target.error.message) {
+ event.target.title = "Cannot play ("
+ + event.target.error.message + ")";
+ } else {
+ event.target.title = "Cannot play";
+ }
+
+ /* Apply CSS class marking error for visual feedback*/
+ event.target.className = "audioError";
+
+ /* Start playing the next audio result when "Play all" is running */
+ var playerElem = document.getElementById("audioControls");
+ var currentPlayAllTrack = playerElem != null ? parseInt(playerElem
+ .getAttribute("data-current-track")) : -1;
+ if(!isNaN(currentPlayAllTrack) && currentPlayAllTrack >= 0) {
+ /* Currently playing all audio results */
+ playAllNext(playerElem);
+ }
+ }
+}
+
+/**
+ * Handle embedded audio result 'playing' event : pauses any other currently
+ * playing audio.
+ *
+ * @param event
+ * {Event} a 'playing' event
+ */
+function handleAudioPlaying(event) {
+ if (event != null && event.target != null) {
+ var audioElems = document.getElementsByTagName("audio");
+ var playerElem = document.getElementById("audioControls");
+ var currentPlayAllTrack = playerElem != null ? parseInt(playerElem
+ .getAttribute("data-current-track")) : -1;
+ if (audioElems != null) {
+ for (var i = 0; i < audioElems.length; i++) {
+ var audioElem = audioElems[i];
+
+ if (audioElem == event.target) {
+ if (!isNaN(currentPlayAllTrack) && currentPlayAllTrack >= 0) {
+ if(currentPlayAllTrack == i) {
+ /* Starting or resuming play of the currently selected "Play all" track */
+ updatePlayAllButton(true);
+ } else {
+ /* Playing here a single result while "Play all" was running on a different track */
+
+ /* "Play all" is interrupted */
+ updatePlayAllButton(false);
+
+ /* Update the current play all track index */
+ playerElem.setAttribute("data-current-track", -1);
+ }
+ }
+ } else if (audioElem.pause && !audioElem.paused) {
+ audioElem.pause();
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Handle embedded audio result 'pause' event.
+ *
+ * @param event
+ * {Event} a 'pause' event
+ */
+function handleAudioPause(event) {
+ if(event != null && event.target != null && event.target.error == null) {
+ var playerElem = document.getElementById("audioControls");
+ var currentPlayAllTrack = playerElem != null ? parseInt(playerElem
+ .getAttribute("data-current-track")) : -1;
+ if(!isNaN(currentPlayAllTrack) && currentPlayAllTrack >= 0) {
+ /* Currently playing all audio results */
+ var audioElems = document.getElementsByTagName("audio");
+ if(audioElems != null) {
+ for(var i = 0; i < audioElems.length; i++) {
+ if(audioElems[i] == event.target && currentPlayAllTrack == i) {
+ /* Update the "Play all" button icon to reflect the new status.
+ * Do not update when pausing another track that may be already paused. */
+ updatePlayAllButton(false);
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Handle embedded audio result 'ended' event : start playing the next audio
+ * result when the "Play all" button is pressed.
+ *
+ * @param event
+ * {Event} a 'playing' event
+ */
+function handleAudioEnded(event) {
+ if (event != null && event.target != null) {
+ /* Start playing the next audio result when "Play all" is pressed */
+ var playerElem = document.getElementById("audioControls");
+ var currentPlayAllTrack = playerElem != null ? parseInt(playerElem
+ .getAttribute("data-current-track")) : -1;
+ if(!isNaN(currentPlayAllTrack) && currentPlayAllTrack >= 0) {
+ /* Currently playing all audio results */
+ playAllNext(playerElem);
+ }
+ }
+}
+
+/**
+ * Start playing the next audio result when one is available and update the
+ * "Play all" button.
+ *
+ * @param playerElem
+ * the player container element
+ */
+function playAllNext(playerElem) {
+ if (playerElem == null) {
+ return;
+ }
+ var audioElems = document.getElementsByTagName("audio");
+ if (audioElems == null) {
+ /* No more audio elements ? */
+ playerElem.setAttribute("data-current-track", -1);
+ updatePlayAllButton(false);
+ } else {
+ var currentTrack = parseInt(playerElem.getAttribute("data-current-track"));
+ var nextTrack;
+ if (isNaN(currentTrack) || currentTrack < 0
+ || currentTrack >= audioElems.length) {
+ nextTrack = 0;
+ } else {
+ nextTrack = currentTrack + 1;
+ }
+ if (nextTrack < audioElems.length) {
+ while (nextTrack < audioElems.length) {
+ var audioElem = audioElems[nextTrack];
+ if (audioElem != null && audioElem.error == null
+ && audioElem.play) {
+ if(audioElem.currentTime > 0) {
+ audioElem.currentTime = 0;
+ }
+ audioElem.play();
+ updatePlayAllButton(true);
+ playerElem.setAttribute("data-current-track", nextTrack);
+ break;
+ }
+ /* Go to the next element when not playable */
+ nextTrack++;
+ }
+ } else {
+ /* No other result to play */
+ playerElem.setAttribute("data-current-track", -1);
+ updatePlayAllButton(false);
+ }
+ }
+}
+
+/**
+ * Update the "Play all" button
+ * @param playing when true the new status becomes playing all, otherwise it becomes paused
+ */
+function updatePlayAllButton(playing) {
+ var playAllIcon = document.getElementById("playAllIcon");
+ if (playAllIcon != null) {
+ if(playing) {
+ if(playAllIcon.className != "glyphicon glyphicon-pause") {
+ playAllIcon.className = "glyphicon glyphicon-pause";
+ }
+ } else if(playAllIcon.className != "glyphicon glyphicon-play") {
+ playAllIcon.className = "glyphicon glyphicon-play";
+ }
+ }
+ var playAllBtn = document.getElementById("playAllBtn");
+ if(playAllBtn != null) {
+ if(playing) {
+ var pauseTitle = playAllBtn.getAttribute("data-pause-title");
+ if(pauseTitle != null && playAllBtn.title != pauseTitle) {
+ playAllBtn.title = pauseTitle;
+ }
+ } else {
+ var playAllTitle = playAllBtn.getAttribute("data-playAll-title");
+ if(playAllTitle != null && playAllBtn.title != playAllTitle) {
+ playAllBtn.title = playAllTitle;
+ }
+ }
+ }
+
+}
+
+/**
+ * Handle a click on the "Play all" button.
+ */
+function handlePlayAllBtnClick() {
+ var audioElems = document.getElementsByTagName("audio");
+ var playerElem = document.getElementById("audioControls");
+ var playAllIcon = document.getElementById("playAllIcon");
+ if (playerElem != null && audioElems != null) {
+ if (playAllIcon.className == "glyphicon glyphicon-play" && audioElems.length > 0) {
+ var currentTrack = parseInt(playerElem
+ .getAttribute("data-current-track"));
+ if (isNaN(currentTrack) || currentTrack < 0
+ || currentTrack >= audioElems.length) {
+ /* Start a new play of all audio results */
+ currentTrack = 0;
+ /* Reset all times */
+ for (var j = 0; j < audioElems.length; j++) {
+ var elem = audioElems[j];
+ if (elem.paused && elem.currentTime > 0) {
+ elem.currentTime = 0;
+ }
+ }
+ }
+ while (currentTrack < audioElems.length) {
+ var currentAudioElem = audioElems[currentTrack];
+ if (currentAudioElem != null && currentAudioElem.error == null
+ && currentAudioElem.play) {
+ currentAudioElem.play();
+ updatePlayAllButton(true);
+ break;
+ }
+ /* Go to the next element when not playable */
+ currentTrack++;
+ }
+ playerElem.setAttribute("data-current-track", currentTrack);
+ } else {
+ /* Pause any running track */
+ for (var i = 0; i < audioElems.length; i++) {
+ var audioElem = audioElems[i];
+ if (audioElem.pause && !audioElem.paused) {
+ audioElem.pause();
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Handle a click on the "Stop all" button.
+ */
+function handleStopAllBtnClick() {
+ /* Stop all audio elements */
+ var audioElems = document.getElementsByTagName("audio");
+ if (audioElems != null) {
+ for (var i = 0; i < audioElems.length; i++) {
+ var audioElem = audioElems[i];
+ if (audioElem.pause && !audioElem.paused) {
+ audioElem.pause();
+ if(audioElem.currentTime > 0) {
+ audioElem.currentTime = 0;
+ }
+ } else if(audioElem.paused && audioElem.currentTime > 0) {
+ audioElem.currentTime = 0;
+ }
+ }
+ }
+
+ updatePlayAllButton(false);
+
+ /* Update the current track index */
+ var playerElem = document.getElementById("audioControls");
+ if (playerElem != null) {
+ playerElem.setAttribute("data-current-track", -1);
+ }
+}
\ No newline at end of file
diff --git a/htroot/jslicense.html b/htroot/jslicense.html
index b863e6d0e..2db9a34c3 100755
--- a/htroot/jslicense.html
+++ b/htroot/jslicense.html
@@ -208,6 +208,11 @@
GNU-GPL-2.0-or-later |
yacysearch.js |
+
+ yacysearchAudio.js |
+ GNU-GPL-2.0-or-later |
+ yacysearchAudio.js |
+
yacysort.js |
GNU-GPL-2.0-or-later |
diff --git a/htroot/yacysearch.html b/htroot/yacysearch.html
index abd6843fb..a31a11d11 100644
--- a/htroot/yacysearch.html
+++ b/htroot/yacysearch.html
@@ -9,6 +9,9 @@
+ #(resultTable)#::::
+ #(embed)#::#(/embed)#
+ #(/resultTable)#
@@ -23,6 +26,18 @@
#(/jsResort)#