From a3d2c43ef09f6f8fa95751f85fd403c6621b3fc6 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 26 Nov 2021 11:16:03 +0330 Subject: [PATCH 01/16] #250 use HTML audio instead of jplayer for playing recitations --- GanjooRazor/Pages/Index.cshtml | 1 + GanjooRazor/Pages/Index.cshtml.cs | 8 + GanjooRazor/Pages/_AudioPlayerPartial.cshtml | 176 +++++++ .../Pages/_AudioPlayerPartial.cshtml.cs | 10 + GanjooRazor/Pages/_GanjoorPagePartial.cshtml | 2 + GanjooRazor/wwwroot/css/audioplayer.css | 251 ++++++++++ GanjooRazor/wwwroot/js/audioplayer.js | 455 ++++++++++++++++++ GanjoorService.sln | 4 +- 8 files changed, 905 insertions(+), 2 deletions(-) create mode 100644 GanjooRazor/Pages/_AudioPlayerPartial.cshtml create mode 100644 GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs create mode 100644 GanjooRazor/wwwroot/css/audioplayer.css create mode 100644 GanjooRazor/wwwroot/js/audioplayer.js diff --git a/GanjooRazor/Pages/Index.cshtml b/GanjooRazor/Pages/Index.cshtml index 0fb01f13..379d0442 100644 --- a/GanjooRazor/Pages/Index.cshtml +++ b/GanjooRazor/Pages/Index.cshtml @@ -18,6 +18,7 @@ } + diff --git a/GanjooRazor/Pages/Index.cshtml.cs b/GanjooRazor/Pages/Index.cshtml.cs index c3e4fbef..bf156170 100644 --- a/GanjooRazor/Pages/Index.cshtml.cs +++ b/GanjooRazor/Pages/Index.cshtml.cs @@ -195,6 +195,14 @@ namespace GanjooRazor.Pages }; } + public _AudioPlayerPartialModel GetRecitationsModel(PublicRecitationViewModel[] recitations) + { + return new _AudioPlayerPartialModel() + { + Recitations = recitations + }; + } + public async Task OnPostReply(string replyCommentText, int refPoemId, int refCommentId) { return await OnPostComment(replyCommentText, refPoemId, refCommentId, -1); diff --git a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml new file mode 100644 index 00000000..beb644f0 --- /dev/null +++ b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml @@ -0,0 +1,176 @@ +@model GanjooRazor.Pages._AudioPlayerPartialModel +@{ +} +
+ + + +
+ +
+ Large toggle button +
+ + +
+
+
+
+ 00:00 / + 00:00 +
+
+ + +
+
+
+
+
+
+
+
+ +
+ + +
+ Previous track button + Next track button +
+ + +
+ + +
+ +
+
+ Small toggle button +
+
+ 1. +
+ +
+
+
+ Small toggle button +
+
+ 2. +
+ +
+
+
+ Small toggle button +
+
+ 3. +
+ +
+
+
+ Small toggle button +
+
+ 4. +
+ +
+
+
+ Small toggle button +
+
+ 5. +
+ +
+
+
+ Small toggle button +
+
+ 6. +
+ +
+
+
+ Small toggle button +
+
+ 7. +
+ +
+
+
+ Small toggle button +
+
+ 8. +
+ +
+
+
+ Small toggle button +
+
+ 9. +
+ +
+
+
+ Small toggle button +
+
+ 10. +
+ +
+ +
+ +
می‌خواهید شما بخوانید؟ اینجا را ببینید.
+
+ + diff --git a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs new file mode 100644 index 00000000..e3f541da --- /dev/null +++ b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Mvc.RazorPages; +using RMuseum.Models.GanjoorAudio.ViewModels; + +namespace GanjooRazor.Pages +{ + public class _AudioPlayerPartialModel : PageModel + { + public PublicRecitationViewModel[] Recitations { get; set; } + } +} diff --git a/GanjooRazor/Pages/_GanjoorPagePartial.cshtml b/GanjooRazor/Pages/_GanjoorPagePartial.cshtml index 5d98d5e6..c22b3d3e 100644 --- a/GanjooRazor/Pages/_GanjoorPagePartial.cshtml +++ b/GanjooRazor/Pages/_GanjoorPagePartial.cshtml @@ -247,6 +247,8 @@ + + } } } diff --git a/GanjooRazor/wwwroot/css/audioplayer.css b/GanjooRazor/wwwroot/css/audioplayer.css new file mode 100644 index 00000000..e3f385ec --- /dev/null +++ b/GanjooRazor/wwwroot/css/audioplayer.css @@ -0,0 +1,251 @@ +.screen-reader-text { + /* Reusable, toolbox kind of class */ + position: absolute; + top: -9999px; + left: -9999px; +} + +.disabled { + color: #666; + cursor: default; +} + +.show { + display: inline-block !important; +} + + +.container { + margin: 0 auto; + width: 500px; +} +.container .player { + height: 60px; + margin: 0; + position: relative; + width: 400px; + /* Small devices (tablets, 768px and up) */ + /* Medium devices (desktops, 992px and up) */ + /* Large devices (large desktops, 1200px and up) */ + *zoom: 1; +} +@media (min-width: 768px) and (max-width: 991px) { + .container .player { + width: 470px; + } +} +@media (min-width: 992px) and (max-width: 1100px) { + .container .player { + width: 470px; + } +} +@media (min-width: 1200px) { + .container .player { + width: 470px; + } +} +.container .player .large-toggle-btn { + border: 1px solid #d9d9d9; + border-radius: 2px; + float: left; + font-size: 1.5em; + height: 50px; + margin: 0 10px 0 0; + overflow: hidden; + padding: 5px 0 0 0; + position: relative; + text-align: center; + vertical-align: bottom; + width: 54px; +} +.container .player .large-toggle-btn .large-play-btn { + cursor: pointer; + display: inline-block; + position: relative; + top: -14%; +} + +.container .player .large-toggle-btn .large-pause-btn { + cursor: pointer; + display: inline-block; + position: relative; + top: -13%; +} +.container .player .info-box { + bottom: 10px; + left: 65px; + position: absolute; + top: 15px; +} +.container .player .info-box .track-info-box { + float: left; + font-size: 12px; + margin: 0 0 6px 0; + visibility: hidden; + width: 400px; + *zoom: 1; +} +.container .player .info-box .track-info-box .track-title-text { + display: inline-block; +} +.container .player .info-box .track-info-box .audio-time { + display: inline-block; + padding: 0 0 0 5px; + width: 80px; +} +.container .player .info-box .track-info-box:before, .container .player .info-box .track-info-box:after { + content: " "; + display: table; +} +.container .player .info-box .track-info-box:after { + clear: both; + display: block; + font-size: 0; + height: 0; + visibility: hidden; +} +.container .player .progress-box { + float: left; + min-width: 270px; + position: relative; +} +.container .player .progress-box .progress-cell { + height: 12px; + position: relative; +} +.container .player .progress-box .progress-cell .progress { + background: #fff; + border: 1px solid #d9d9d9; + height: 8px; + position: relative; + width: auto; +} +.container .player .progress-box .progress-cell .progress .progress-buffer { + background: #337ab7; + height: 100%; + width: 0; +} +.container .player .progress-box .progress-cell .progress .progress-indicator { + background: #fff; + border: 1px solid #bebebe; + border-radius: 3px; + cursor: pointer; + height: 10px; + left: 0; + overflow: hidden; + position: absolute; + top: -2px; + width: 22px; +} +.container .player .controls-box { + bottom: 10px; + left: 350px; + position: absolute; +} +.container .player .controls-box .previous-track-btn { + cursor: pointer; + display: inline-block; +} +.container .player .controls-box .next-track-btn { + cursor: pointer; + display: inline-block; +} +.container .player:before, .container .player:after { + content: " "; + display: table; +} +.container .player:after { + clear: both; + display: block; + font-size: 0; + height: 0; + visibility: hidden; +} +.container .play-list { + display: block; + margin: 0 auto 20px auto; + width: 100%; +} +.container .play-list .play-list-row { + display: block; + margin: 10px 0; + width: 100%; + *zoom: 1; +} +.container .play-list .play-list-row .track-title .playlist-track { + color: #000; + text-decoration: none; +} +.container .play-list .play-list-row .track-title .playlist-track:hover { + text-decoration: underline; +} +.container .play-list .play-list-row .small-toggle-btn { + border: 1px solid #d9d9d9; + border-radius: 2px; + cursor: pointer; + display: inline-block; + height: 20px; + margin: 0 auto; + overflow: hidden; + position: relative; + text-align: center; + vertical-align: middle; + width: 20px; +} +.container .play-list .play-list-row .small-toggle-btn .small-play-btn { + display: inline-block; +} +.container .play-list .play-list-row .small-toggle-btn .small-pause-btn { + display: inline-block; +} +.container .play-list .play-list-row .track-number { + display: inline-block; +} +.container .play-list .play-list-row .track-title { + display: inline-block; +} +.container .play-list .play-list-row .track-title .playlist-track { + text-decoration: none; +} +.container .play-list .play-list-row .track-title .playlist-track:hover { + text-decoration: underline; +} +.container .play-list .play-list-row .track-title.active-track { + font-weight: bold; +} +.container .play-list .play-list-row:before, .container .play-list .play-list-row:after { + content: " "; + display: table; +} +.container .play-list .play-list-row:after { + clear: both; + display: block; + font-size: 0; + height: 0; + visibility: hidden; +} + +.container .player .large-toggle-btn .large-play-btn:before { + content: "play_arrow"; + font: 1.5em/1.75 "Material Icons"; +} +.container .player .large-toggle-btn .large-pause-btn:before { + content: "pause"; + font: 1.5em/1.75 "Material Icons"; +} +.container .player .controls-box .previous-track-btn:before { + content: "skip_previous"; + font: 1em "Material Icons"; +} +.container .player .controls-box .next-track-btn:before { + content: "skip_next"; + font: 1em "Material Icons"; +} +.container .play-list .play-list-row .small-toggle-btn .small-play-btn:before { + content: "play_arrow"; + font: 0.85em "Material Icons"; +} +.container .play-list .play-list-row .small-toggle-btn .small-pause-btn:before { + content: "pause"; + font: 0.85em "Material Icons"; +} \ No newline at end of file diff --git a/GanjooRazor/wwwroot/js/audioplayer.js b/GanjooRazor/wwwroot/js/audioplayer.js new file mode 100644 index 00000000..e2551c58 --- /dev/null +++ b/GanjooRazor/wwwroot/js/audioplayer.js @@ -0,0 +1,455 @@ +//original source: https://codepen.io/craigstroman/pen/aOyRYx +var audioPlayer = function() { + "use strict"; + + // Private variables + var _currentTrack = null; + var _elements = { + audio: document.getElementById("audio"), + playerButtons: { + largeToggleBtn: document.querySelector(".large-toggle-btn"), + nextTrackBtn: document.querySelector(".next-track-btn"), + previousTrackBtn: document.querySelector(".previous-track-btn"), + smallToggleBtn: document.getElementsByClassName("small-toggle-btn") + }, + progressBar: document.querySelector(".progress-box"), + playListRows: document.getElementsByClassName("play-list-row"), + trackInfoBox: document.querySelector(".track-info-box") + }; + var _playAHead = false; + var _progressCounter = 0; + var _progressBarIndicator = _elements.progressBar.children[0].children[0].children[1]; + var _trackLoaded = false; + + /** + * Determines the buffer progress. + * + * @param audio The audio element on the page. + **/ + var _bufferProgress = function(audio) { + var bufferedTime = (audio.buffered.end(0) * 100) / audio.duration; + var progressBuffer = _elements.progressBar.children[0].children[0].children[0]; + + progressBuffer.style.width = bufferedTime + "%"; + }; + + /** + * A utility function for getting the event cordinates based on browser type. + * + * @param e The JavaScript event. + **/ + var _getXY = function(e) { + var containerX = _elements.progressBar.offsetLeft; + var containerY = _elements.progressBar.offsetTop; + + var coords = { + x: null, + y: null + }; + + var isTouchSuopported = "ontouchstart" in window; + + if (isTouchSuopported) { //For touch devices + coords.x = e.clientX - containerX; + coords.y = e.clientY - containerY; + + return coords; + } else if (e.offsetX || e.offsetX === 0) { // For webkit browsers + coords.x = e.offsetX; + coords.y = e.offsetY; + + return coords; + } else if (e.layerX || e.layerX === 0) { // For Mozilla firefox + coords.x = e.layerX; + coords.y = e.layerY; + + return coords; + } + }; + + var _handleProgressIndicatorClick = function(e) { + var progressBar = document.querySelector(".progress-box"); + var xCoords = _getXY(e).x; + + return (xCoords - progressBar.offsetLeft) / progressBar.children[0].offsetWidth; + }; + + /** + * Initializes the html5 audio player and the playlist. + * + **/ + var initPlayer = function() { + + if (_currentTrack === 1 || _currentTrack === null) { + _elements.playerButtons.previousTrackBtn.disabled = true; + } + + //Adding event listeners to playlist clickable elements. + for (var i = 0; i < _elements.playListRows.length; i++) { + var smallToggleBtn = _elements.playerButtons.smallToggleBtn[i]; + var playListLink = _elements.playListRows[i].children[2].children[0]; + + //Playlist link clicked. + playListLink.addEventListener("click", function(e) { + e.preventDefault(); + var selectedTrack = parseInt(this.parentNode.parentNode.getAttribute("data-track-row")); + + if (selectedTrack !== _currentTrack) { + _resetPlayStatus(); + _currentTrack = null; + _trackLoaded = false; + } + + if (_trackLoaded === false) { + _currentTrack = parseInt(selectedTrack); + _setTrack(); + } else { + _playBack(this); + } + }, false); + + //Small toggle button clicked. + smallToggleBtn.addEventListener("click", function(e) { + e.preventDefault(); + var selectedTrack = parseInt(this.parentNode.getAttribute("data-track-row")); + + if (selectedTrack !== _currentTrack) { + _resetPlayStatus(); + _currentTrack = null; + _trackLoaded = false; + } + + if (_trackLoaded === false) { + _currentTrack = parseInt(selectedTrack); + _setTrack(); + } else { + _playBack(this); + } + + }, false); + } + + //Audio time has changed so update it. + _elements.audio.addEventListener("timeupdate", _trackTimeChanged, false); + + //Audio track has ended playing. + _elements.audio.addEventListener("ended", function(e) { + _trackHasEnded(); + }, false); + + //Audio error. + _elements.audio.addEventListener("error", function(e) { + switch (e.target.error.code) { + case e.target.error.MEDIA_ERR_ABORTED: + alert('You aborted the video playback.'); + break; + case e.target.error.MEDIA_ERR_NETWORK: + alert('A network error caused the audio download to fail.'); + break; + case e.target.error.MEDIA_ERR_DECODE: + alert('The audio playback was aborted due to a corruption problem or because the video used features your browser did not support.'); + break; + case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED: + alert('The video audio not be loaded, either because the server or network failed or because the format is not supported.'); + break; + default: + alert('An unknown error occurred.'); + break; + } + trackLoaded = false; + _resetPlayStatus(); + }, false); + + //Large toggle button clicked. + _elements.playerButtons.largeToggleBtn.addEventListener("click", function(e) { + if (_trackLoaded === false) { + _currentTrack = parseInt(1); + _setTrack() + } else { + _playBack(); + } + }, false); + + //Next track button clicked. + _elements.playerButtons.nextTrackBtn.addEventListener("click", function(e) { + if (this.disabled !== true) { + _currentTrack++; + _trackLoaded = false; + _resetPlayStatus(); + _setTrack(); + } + }, false); + + //Previous track button clicked. + _elements.playerButtons.previousTrackBtn.addEventListener("click", function(e) { + if (this.disabled !== true) { + _currentTrack--; + _trackLoaded = false; + _resetPlayStatus(); + _setTrack(); + } + }, false); + + //User is moving progress indicator. + _progressBarIndicator.addEventListener("mousedown", _mouseDown, false); + + //User stops moving progress indicator. + window.addEventListener("mouseup", _mouseUp, false); + }; + + /** + * Handles the mousedown event by a user and determines if the mouse is being moved. + * + * @param e The event object. + **/ + var _mouseDown = function(e) { + window.addEventListener("mousemove", _moveProgressIndicator, true); + audio.removeEventListener("timeupdate", _trackTimeChanged, false); + + _playAHead = true; + }; + + /** + * Handles the mouseup event by a user. + * + * @param e The event object. + **/ + var _mouseUp = function(e) { + if (_playAHead === true) { + var duration = parseFloat(audio.duration); + var progressIndicatorClick = parseFloat(_handleProgressIndicatorClick(e)); + window.removeEventListener("mousemove", _moveProgressIndicator, true); + + audio.currentTime = duration * progressIndicatorClick; + audio.addEventListener("timeupdate", _trackTimeChanged, false); + _playAHead = false; + } + }; + + /** + * Moves the progress indicator to a new point in the audio. + * + * @param e The event object. + **/ + var _moveProgressIndicator = function(e) { + var newPosition = 0; + var progressBarOffsetLeft = _elements.progressBar.offsetLeft; + var progressBarWidth = 0; + var progressBarIndicator = _elements.progressBar.children[0].children[0].children[1]; + var progressBarIndicatorWidth = _progressBarIndicator.offsetWidth; + var xCoords = _getXY(e).x; + + progressBarWidth = _elements.progressBar.children[0].offsetWidth - progressBarIndicatorWidth; + newPosition = xCoords - progressBarOffsetLeft; + + if ((newPosition >= 1) && (newPosition <= progressBarWidth)) { + progressBarIndicator.style.left = newPosition + ".px"; + } + if (newPosition < 0) { + progressBarIndicator.style.left = "0"; + } + if (newPosition > progressBarWidth) { + progressBarIndicator.style.left = progressBarWidth + "px"; + } + }; + + /** + * Controls playback of the audio element. + * + **/ + var _playBack = function() { + if (_elements.audio.paused) { + _elements.audio.play(); + _updatePlayStatus(true); + } else { + _elements.audio.pause(); + _updatePlayStatus(false); + } + }; + + /** + * Sets the track if it hasn't already been loaded yet. + * + **/ + var _setTrack = function() { + var songURL = _elements.audio.children[_currentTrack - 1].src; + + _elements.audio.setAttribute("src", songURL); + _elements.audio.load(); + + _trackLoaded = true; + + _setTrackTitle(_currentTrack, _elements.playListRows); + + _setActiveItem(_currentTrack, _elements.playListRows); + + _elements.trackInfoBox.style.visibility = "visible"; + + _playBack(); + }; + + /** + * Sets the activly playing item within the playlist. + * + * @param currentTrack The current track number being played. + * @param playListRows The playlist object. + **/ + var _setActiveItem = function(currentTrack, playListRows) { + for (var i = 0; i < playListRows.length; i++) { + playListRows[i].children[2].className = "track-title"; + } + + playListRows[currentTrack - 1].children[2].className = "track-title active-track"; + }; + + /** + * Sets the text for the currently playing song. + * + * @param currentTrack The current track number being played. + * @param playListRows The playlist object. + **/ + var _setTrackTitle = function(currentTrack, playListRows) { + var trackTitleBox = document.querySelector(".player .info-box .track-info-box .track-title-text"); + var trackTitle = playListRows[currentTrack - 1].children[2].outerText; + + trackTitleBox.innerHTML = null; + + trackTitleBox.innerHTML = trackTitle; + + }; + + /** + * Plays the next track when a track has ended playing. + * + **/ + var _trackHasEnded = function() { + parseInt(_currentTrack); + _currentTrack = (_currentTrack === _elements.playListRows.length) ? 1 : _currentTrack + 1; + _trackLoaded = false; + + _resetPlayStatus(); + + _setTrack(); + }; + + /** + * Updates the time for the song being played. + * + **/ + var _trackTimeChanged = function() { + var currentTimeBox = document.querySelector(".player .info-box .track-info-box .audio-time .current-time"); + var currentTime = audio.currentTime; + var duration = audio.duration; + var durationBox = document.querySelector(".player .info-box .track-info-box .audio-time .duration"); + var trackCurrentTime = _trackTime(currentTime); + var trackDuration = _trackTime(duration); + + currentTimeBox.innerHTML = null; + currentTimeBox.innerHTML = trackCurrentTime; + + durationBox.innerHTML = null; + durationBox.innerHTML = trackDuration; + + _updateProgressIndicator(audio); + _bufferProgress(audio); + }; + + /** + * A utility function for converting a time in miliseconds to a readable time of minutes and seconds. + * + * @param seconds The time in seconds. + * + * @return time The time in minutes and/or seconds. + **/ + var _trackTime = function(seconds) { + var min = 0; + var sec = Math.floor(seconds); + var time = 0; + + min = Math.floor(sec / 60); + + min = min >= 10 ? min : '0' + min; + + sec = Math.floor(sec % 60); + + sec = sec >= 10 ? sec : '0' + sec; + + time = min + ':' + sec; + + return time; + }; + + /** + * Updates both the large and small toggle buttons accordingly. + * + * @param audioPlaying A booean value indicating if audio is playing or paused. + **/ + var _updatePlayStatus = function(audioPlaying) { + if (audioPlaying) { + _elements.playerButtons.largeToggleBtn.children[0].className = "large-pause-btn"; + + _elements.playerButtons.smallToggleBtn[_currentTrack - 1].children[0].className = "small-pause-btn"; + } else { + _elements.playerButtons.largeToggleBtn.children[0].className = "large-play-btn"; + + _elements.playerButtons.smallToggleBtn[_currentTrack - 1].children[0].className = "small-play-btn"; + } + + //Update next and previous buttons accordingly + if (_currentTrack === 1) { + _elements.playerButtons.previousTrackBtn.disabled = true; + _elements.playerButtons.previousTrackBtn.className = "previous-track-btn disabled"; + } else if (_currentTrack > 1 && _currentTrack !== _elements.playListRows.length) { + _elements.playerButtons.previousTrackBtn.disabled = false; + _elements.playerButtons.previousTrackBtn.className = "previous-track-btn"; + _elements.playerButtons.nextTrackBtn.disabled = false; + _elements.playerButtons.nextTrackBtn.className = "next-track-btn"; + } else if (_currentTrack === _elements.playListRows.length) { + _elements.playerButtons.nextTrackBtn.disabled = true; + _elements.playerButtons.nextTrackBtn.className = "next-track-btn disabled"; + } + }; + + /** + * Updates the location of the progress indicator according to how much time left in audio. + * + **/ + var _updateProgressIndicator = function() { + var currentTime = parseFloat(_elements.audio.currentTime); + var duration = parseFloat(_elements.audio.duration); + var indicatorLocation = 0; + var progressBarWidth = parseFloat(_elements.progressBar.offsetWidth); + var progressIndicatorWidth = parseFloat(_progressBarIndicator.offsetWidth); + var progressBarIndicatorWidth = progressBarWidth - progressIndicatorWidth; + + indicatorLocation = progressBarIndicatorWidth * (currentTime / duration); + + _progressBarIndicator.style.left = indicatorLocation + "px"; + }; + + /** + * Resets all toggle buttons to be play buttons. + * + **/ + var _resetPlayStatus = function() { + var smallToggleBtn = _elements.playerButtons.smallToggleBtn; + + _elements.playerButtons.largeToggleBtn.children[0].className = "large-play-btn"; + + for (var i = 0; i < smallToggleBtn.length; i++) { + if (smallToggleBtn[i].children[0].className === "small-pause-btn") { + smallToggleBtn[i].children[0].className = "small-play-btn"; + } + } + }; + + return { + initPlayer: initPlayer + }; +}; + +(function() { + var player = new audioPlayer(); + + player.initPlayer(); +})(); \ No newline at end of file diff --git a/GanjoorService.sln b/GanjoorService.sln index 3bdacee2..2d3fe143 100644 --- a/GanjoorService.sln +++ b/GanjoorService.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30011.22 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31912.275 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RSecurityBackend", "RSecurityBackend\RSecurityBackend.csproj", "{1BF45DCD-40F4-4D6E-9134-D6B3DE39C56E}" EndProject From a7757b707bde18e8fa1ab71eedd82455033e2b31 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 26 Nov 2021 12:05:50 +0330 Subject: [PATCH 02/16] #250 loading actual ganjoor recitations into the new player --- GanjooRazor/Pages/_AudioPlayerPartial.cshtml | 214 +++++-------------- 1 file changed, 57 insertions(+), 157 deletions(-) diff --git a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml index beb644f0..1cd55446 100644 --- a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml +++ b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml @@ -1,176 +1,76 @@ @model GanjooRazor.Pages._AudioPlayerPartialModel +@using DNTPersianUtils.Core @{ }
- + -
+
-
- Large toggle button -
- - -
-
-
-
- 00:00 / - 00:00 +
+ دکمهٔ بزرگ پخش و ادامه
-
- + + +
+
+
+
+ 00:00 / + 00:00 +
+
+ + +
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+ + +
+ پخش خوانش پیشین + پخش خوانش بعدی +
+
- + -
- Previous track button - Next track button -
- +
-
- - -
- -
-
- Small toggle button -
-
- 1. -
- -
-
-
- Small toggle button -
-
- 2. -
- -
-
-
- Small toggle button -
-
- 3. -
- -
-
-
- Small toggle button -
-
- 4. -
- -
-
-
- Small toggle button -
-
- 5. -
- -
-
-
- Small toggle button -
-
- 6. -
- -
-
-
- Small toggle button -
-
- 7. -
- -
-
-
- Small toggle button -
-
- 8. -
- -
-
-
- Small toggle button -
-
- 9. -
- -
-
-
- Small toggle button -
-
- 10. -
- + @for (var nRecitationIndex = 0; nRecitationIndex < Model.Recitations.Length; nRecitationIndex++) + { + var recitaion = Model.Recitations[nRecitationIndex]; +
+
+ Small toggle button +
+
+ @((nRecitationIndex + 1).ToPersianNumbers()). +
+ +
+ }
-
- -
می‌خواهید شما بخوانید؟ اینجا را ببینید.
+
می‌خواهید شما بخوانید؟ اینجا را ببینید.
From 2c224c697483bdaba3d985007db588fc5f463a24 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 26 Nov 2021 14:53:36 +0330 Subject: [PATCH 03/16] #250 title fix --- GanjooRazor/wwwroot/js/audioplayer.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/GanjooRazor/wwwroot/js/audioplayer.js b/GanjooRazor/wwwroot/js/audioplayer.js index e2551c58..7e6e0d64 100644 --- a/GanjooRazor/wwwroot/js/audioplayer.js +++ b/GanjooRazor/wwwroot/js/audioplayer.js @@ -17,7 +17,6 @@ var audioPlayer = function() { trackInfoBox: document.querySelector(".track-info-box") }; var _playAHead = false; - var _progressCounter = 0; var _progressBarIndicator = _elements.progressBar.children[0].children[0].children[1]; var _trackLoaded = false; @@ -309,8 +308,8 @@ var audioPlayer = function() { * @param playListRows The playlist object. **/ var _setTrackTitle = function(currentTrack, playListRows) { - var trackTitleBox = document.querySelector(".player .info-box .track-info-box .track-title-text"); - var trackTitle = playListRows[currentTrack - 1].children[2].outerText; + var trackTitleBox = document.querySelector(".player .info-box .track-info-box .track-title-text"); + var trackTitle = playListRows[currentTrack - 1].children[2].innerHTML; trackTitleBox.innerHTML = null; From 83827a8ae5865a6df79e933de67ddf1f2580f9a6 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 26 Nov 2021 15:22:12 +0330 Subject: [PATCH 04/16] #250 embed recitations xml urls inside audio player partial views --- GanjooRazor/Pages/_AudioPlayerPartial.cshtml | 5 +++-- GanjooRazor/wwwroot/css/audioplayer.css | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml index 1cd55446..ea0331f8 100644 --- a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml +++ b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml @@ -43,8 +43,8 @@
- پخش خوانش پیشین پخش خوانش بعدی + پخش خوانش پیشین
@@ -53,7 +53,7 @@
- @for (var nRecitationIndex = 0; nRecitationIndex < Model.Recitations.Length; nRecitationIndex++) + @for (var nRecitationIndex = 0; nRecitationIndex < Model.Recitations.Length; nRecitationIndex++) { var recitaion = Model.Recitations[nRecitationIndex];
@@ -66,6 +66,7 @@ +
@($"{GanjooRazor.APIRoot.InternetUrl}/api/audio/file/{recitaion.Id}.xml")
}
diff --git a/GanjooRazor/wwwroot/css/audioplayer.css b/GanjooRazor/wwwroot/css/audioplayer.css index e3f385ec..4f28d1f3 100644 --- a/GanjooRazor/wwwroot/css/audioplayer.css +++ b/GanjooRazor/wwwroot/css/audioplayer.css @@ -248,4 +248,8 @@ .container .play-list .play-list-row .small-toggle-btn .small-pause-btn:before { content: "pause"; font: 0.85em "Material Icons"; +} + +.xml-url-path{ + display:none; } \ No newline at end of file From 95bfb68599598e387ed396bcb30e6b42e26f7704 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 26 Nov 2021 15:50:09 +0330 Subject: [PATCH 05/16] #250 loading xml file and synching text with audio while playing recitations --- GanjooRazor/wwwroot/js/audioplayer.js | 835 ++++++++++++++------------ 1 file changed, 441 insertions(+), 394 deletions(-) diff --git a/GanjooRazor/wwwroot/js/audioplayer.js b/GanjooRazor/wwwroot/js/audioplayer.js index 7e6e0d64..7d8cb62c 100644 --- a/GanjooRazor/wwwroot/js/audioplayer.js +++ b/GanjooRazor/wwwroot/js/audioplayer.js @@ -1,454 +1,501 @@ //original source: https://codepen.io/craigstroman/pen/aOyRYx -var audioPlayer = function() { - "use strict"; +var audioPlayer = function () { + "use strict"; - // Private variables - var _currentTrack = null; - var _elements = { - audio: document.getElementById("audio"), - playerButtons: { - largeToggleBtn: document.querySelector(".large-toggle-btn"), - nextTrackBtn: document.querySelector(".next-track-btn"), - previousTrackBtn: document.querySelector(".previous-track-btn"), - smallToggleBtn: document.getElementsByClassName("small-toggle-btn") - }, - progressBar: document.querySelector(".progress-box"), - playListRows: document.getElementsByClassName("play-list-row"), - trackInfoBox: document.querySelector(".track-info-box") - }; - var _playAHead = false; - var _progressBarIndicator = _elements.progressBar.children[0].children[0].children[1]; - var _trackLoaded = false; + var verseStart = []; + var verseEnd = []; + var verseIndex = []; + var nLastHighlight = -1; + var vCount = 0; - /** - * Determines the buffer progress. - * - * @param audio The audio element on the page. - **/ - var _bufferProgress = function(audio) { - var bufferedTime = (audio.buffered.end(0) * 100) / audio.duration; - var progressBuffer = _elements.progressBar.children[0].children[0].children[0]; + // Private variables + var _currentTrack = null; + var _elements = { + audio: document.getElementById("audio"), + playerButtons: { + largeToggleBtn: document.querySelector(".large-toggle-btn"), + nextTrackBtn: document.querySelector(".next-track-btn"), + previousTrackBtn: document.querySelector(".previous-track-btn"), + smallToggleBtn: document.getElementsByClassName("small-toggle-btn") + }, + progressBar: document.querySelector(".progress-box"), + playListRows: document.getElementsByClassName("play-list-row"), + trackInfoBox: document.querySelector(".track-info-box") + }; + var _playAHead = false; + var _progressBarIndicator = _elements.progressBar.children[0].children[0].children[1]; + var _trackLoaded = false; - progressBuffer.style.width = bufferedTime + "%"; - }; + /** + * Determines the buffer progress. + * + * @param audio The audio element on the page. + **/ + var _bufferProgress = function (audio) { + var bufferedTime = (audio.buffered.end(0) * 100) / audio.duration; + var progressBuffer = _elements.progressBar.children[0].children[0].children[0]; - /** - * A utility function for getting the event cordinates based on browser type. - * - * @param e The JavaScript event. - **/ - var _getXY = function(e) { - var containerX = _elements.progressBar.offsetLeft; - var containerY = _elements.progressBar.offsetTop; - - var coords = { - x: null, - y: null + progressBuffer.style.width = bufferedTime + "%"; }; - var isTouchSuopported = "ontouchstart" in window; + /** + * A utility function for getting the event cordinates based on browser type. + * + * @param e The JavaScript event. + **/ + var _getXY = function (e) { + var containerX = _elements.progressBar.offsetLeft; + var containerY = _elements.progressBar.offsetTop; - if (isTouchSuopported) { //For touch devices - coords.x = e.clientX - containerX; - coords.y = e.clientY - containerY; + var coords = { + x: null, + y: null + }; - return coords; - } else if (e.offsetX || e.offsetX === 0) { // For webkit browsers - coords.x = e.offsetX; - coords.y = e.offsetY; + var isTouchSuopported = "ontouchstart" in window; - return coords; - } else if (e.layerX || e.layerX === 0) { // For Mozilla firefox - coords.x = e.layerX; - coords.y = e.layerY; + if (isTouchSuopported) { //For touch devices + coords.x = e.clientX - containerX; + coords.y = e.clientY - containerY; - return coords; - } - }; + return coords; + } else if (e.offsetX || e.offsetX === 0) { // For webkit browsers + coords.x = e.offsetX; + coords.y = e.offsetY; - var _handleProgressIndicatorClick = function(e) { - var progressBar = document.querySelector(".progress-box"); - var xCoords = _getXY(e).x; + return coords; + } else if (e.layerX || e.layerX === 0) { // For Mozilla firefox + coords.x = e.layerX; + coords.y = e.layerY; - return (xCoords - progressBar.offsetLeft) / progressBar.children[0].offsetWidth; - }; + return coords; + } + }; - /** - * Initializes the html5 audio player and the playlist. - * - **/ - var initPlayer = function() { + var _handleProgressIndicatorClick = function (e) { + var progressBar = document.querySelector(".progress-box"); + var xCoords = _getXY(e).x; - if (_currentTrack === 1 || _currentTrack === null) { - _elements.playerButtons.previousTrackBtn.disabled = true; - } + return (xCoords - progressBar.offsetLeft) / progressBar.children[0].offsetWidth; + }; - //Adding event listeners to playlist clickable elements. - for (var i = 0; i < _elements.playListRows.length; i++) { - var smallToggleBtn = _elements.playerButtons.smallToggleBtn[i]; - var playListLink = _elements.playListRows[i].children[2].children[0]; + /** + * Initializes the html5 audio player and the playlist. + * + **/ + var initPlayer = function () { - //Playlist link clicked. - playListLink.addEventListener("click", function(e) { - e.preventDefault(); - var selectedTrack = parseInt(this.parentNode.parentNode.getAttribute("data-track-row")); - - if (selectedTrack !== _currentTrack) { - _resetPlayStatus(); - _currentTrack = null; - _trackLoaded = false; + if (_currentTrack === 1 || _currentTrack === null) { + _elements.playerButtons.previousTrackBtn.disabled = true; } - if (_trackLoaded === false) { - _currentTrack = parseInt(selectedTrack); - _setTrack(); + //Adding event listeners to playlist clickable elements. + for (var i = 0; i < _elements.playListRows.length; i++) { + var smallToggleBtn = _elements.playerButtons.smallToggleBtn[i]; + var playListLink = _elements.playListRows[i].children[2].children[0]; + + //Playlist link clicked. + playListLink.addEventListener("click", function (e) { + e.preventDefault(); + var selectedTrack = parseInt(this.parentNode.parentNode.getAttribute("data-track-row")); + + if (selectedTrack !== _currentTrack) { + _resetPlayStatus(); + _currentTrack = null; + _trackLoaded = false; + } + + if (_trackLoaded === false) { + _currentTrack = parseInt(selectedTrack); + _setTrack(); + } else { + _playBack(this); + } + }, false); + + //Small toggle button clicked. + smallToggleBtn.addEventListener("click", function (e) { + e.preventDefault(); + var selectedTrack = parseInt(this.parentNode.getAttribute("data-track-row")); + + if (selectedTrack !== _currentTrack) { + _resetPlayStatus(); + _currentTrack = null; + _trackLoaded = false; + } + + if (_trackLoaded === false) { + _currentTrack = parseInt(selectedTrack); + _setTrack(); + } else { + _playBack(this); + } + + }, false); + } + + //Audio time has changed so update it. + _elements.audio.addEventListener("timeupdate", _trackTimeChanged, false); + + //Audio track has ended playing. + _elements.audio.addEventListener("ended", function (e) { + _trackHasEnded(); + }, false); + + //Audio error. + _elements.audio.addEventListener("error", function (e) { + switch (e.target.error.code) { + case e.target.error.MEDIA_ERR_ABORTED: + alert('You aborted the video playback.'); + break; + case e.target.error.MEDIA_ERR_NETWORK: + alert('A network error caused the audio download to fail.'); + break; + case e.target.error.MEDIA_ERR_DECODE: + alert('The audio playback was aborted due to a corruption problem or because the video used features your browser did not support.'); + break; + case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED: + alert('The video audio not be loaded, either because the server or network failed or because the format is not supported.'); + break; + default: + alert('An unknown error occurred.'); + break; + } + trackLoaded = false; + _resetPlayStatus(); + }, false); + + //Large toggle button clicked. + _elements.playerButtons.largeToggleBtn.addEventListener("click", function (e) { + if (_trackLoaded === false) { + _currentTrack = parseInt(1); + _setTrack() + } else { + _playBack(); + } + }, false); + + //Next track button clicked. + _elements.playerButtons.nextTrackBtn.addEventListener("click", function (e) { + if (this.disabled !== true) { + _currentTrack++; + _trackLoaded = false; + _resetPlayStatus(); + _setTrack(); + } + }, false); + + //Previous track button clicked. + _elements.playerButtons.previousTrackBtn.addEventListener("click", function (e) { + if (this.disabled !== true) { + _currentTrack--; + _trackLoaded = false; + _resetPlayStatus(); + _setTrack(); + } + }, false); + + //User is moving progress indicator. + _progressBarIndicator.addEventListener("mousedown", _mouseDown, false); + + //User stops moving progress indicator. + window.addEventListener("mouseup", _mouseUp, false); + }; + + /** + * Handles the mousedown event by a user and determines if the mouse is being moved. + * + * @param e The event object. + **/ + var _mouseDown = function (e) { + window.addEventListener("mousemove", _moveProgressIndicator, true); + audio.removeEventListener("timeupdate", _trackTimeChanged, false); + + _playAHead = true; + }; + + /** + * Handles the mouseup event by a user. + * + * @param e The event object. + **/ + var _mouseUp = function (e) { + if (_playAHead === true) { + var duration = parseFloat(audio.duration); + var progressIndicatorClick = parseFloat(_handleProgressIndicatorClick(e)); + window.removeEventListener("mousemove", _moveProgressIndicator, true); + + audio.currentTime = duration * progressIndicatorClick; + audio.addEventListener("timeupdate", _trackTimeChanged, false); + _playAHead = false; + } + }; + + /** + * Moves the progress indicator to a new point in the audio. + * + * @param e The event object. + **/ + var _moveProgressIndicator = function (e) { + var newPosition = 0; + var progressBarOffsetLeft = _elements.progressBar.offsetLeft; + var progressBarWidth = 0; + var progressBarIndicator = _elements.progressBar.children[0].children[0].children[1]; + var progressBarIndicatorWidth = _progressBarIndicator.offsetWidth; + var xCoords = _getXY(e).x; + + progressBarWidth = _elements.progressBar.children[0].offsetWidth - progressBarIndicatorWidth; + newPosition = xCoords - progressBarOffsetLeft; + + if ((newPosition >= 1) && (newPosition <= progressBarWidth)) { + progressBarIndicator.style.left = newPosition + ".px"; + } + if (newPosition < 0) { + progressBarIndicator.style.left = "0"; + } + if (newPosition > progressBarWidth) { + progressBarIndicator.style.left = progressBarWidth + "px"; + } + }; + + /** + * Controls playback of the audio element. + * + **/ + var _playBack = function () { + if (_elements.audio.paused) { + _elements.audio.play(); + _updatePlayStatus(true); } else { - _playBack(this); + _elements.audio.pause(); + _updatePlayStatus(false); } - }, false); + }; - //Small toggle button clicked. - smallToggleBtn.addEventListener("click", function(e) { - e.preventDefault(); - var selectedTrack = parseInt(this.parentNode.getAttribute("data-track-row")); - - if (selectedTrack !== _currentTrack) { - _resetPlayStatus(); - _currentTrack = null; - _trackLoaded = false; - } - - if (_trackLoaded === false) { - _currentTrack = parseInt(selectedTrack); - _setTrack(); - } else { - _playBack(this); - } - - }, false); + var _setXml = function () { + var xmlUrl = _elements.playListRows[_currentTrack - 1].children[3].innerHTML; + $.ajax({ + type: "GET", + url: xmlUrl, + dataType: "xml", + success: function (xml) { + var nOneSecondBugFix = 2000; + $(xml).find('OneSecondBugFix').each(function () { + nOneSecondBugFix = parseInt($(xml).find('OneSecondBugFix').text()); + }); + var v = 0; + $(xml).find('SyncInfo').each(function () { + verseStart[v] = parseInt($(this).find('AudioMiliseconds').text()) / nOneSecondBugFix; + verseIndex[v] = parseInt($(this).find('VerseOrder').text()); + if (v > 0) + verseEnd[v - 1] = verseStart[v]; + v++; + }); + v--; + if (v > 1) + verseEnd[v] = verseStart[v] + 2 * (verseEnd[v - 1] - verseStart[v - 1]); + vCount = v; + } + }); } - //Audio time has changed so update it. - _elements.audio.addEventListener("timeupdate", _trackTimeChanged, false); + /** + * Sets the track if it hasn't already been loaded yet. + * + **/ + var _setTrack = function () { + _setXml(); + var songURL = _elements.audio.children[_currentTrack - 1].src; - //Audio track has ended playing. - _elements.audio.addEventListener("ended", function(e) { - _trackHasEnded(); - }, false); + _elements.audio.setAttribute("src", songURL); + _elements.audio.load(); - //Audio error. - _elements.audio.addEventListener("error", function(e) { - switch (e.target.error.code) { - case e.target.error.MEDIA_ERR_ABORTED: - alert('You aborted the video playback.'); - break; - case e.target.error.MEDIA_ERR_NETWORK: - alert('A network error caused the audio download to fail.'); - break; - case e.target.error.MEDIA_ERR_DECODE: - alert('The audio playback was aborted due to a corruption problem or because the video used features your browser did not support.'); - break; - case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED: - alert('The video audio not be loaded, either because the server or network failed or because the format is not supported.'); - break; - default: - alert('An unknown error occurred.'); - break; - } - trackLoaded = false; - _resetPlayStatus(); - }, false); + _trackLoaded = true; + + _setTrackTitle(_currentTrack, _elements.playListRows); + + _setActiveItem(_currentTrack, _elements.playListRows); + + _elements.trackInfoBox.style.visibility = "visible"; - //Large toggle button clicked. - _elements.playerButtons.largeToggleBtn.addEventListener("click", function(e) { - if (_trackLoaded === false) { - _currentTrack = parseInt(1); - _setTrack() - } else { _playBack(); - } - }, false); + }; - //Next track button clicked. - _elements.playerButtons.nextTrackBtn.addEventListener("click", function(e) { - if (this.disabled !== true) { - _currentTrack++; + /** + * Sets the activly playing item within the playlist. + * + * @param currentTrack The current track number being played. + * @param playListRows The playlist object. + **/ + var _setActiveItem = function (currentTrack, playListRows) { + for (var i = 0; i < playListRows.length; i++) { + playListRows[i].children[2].className = "track-title"; + } + + playListRows[currentTrack - 1].children[2].className = "track-title active-track"; + }; + + /** + * Sets the text for the currently playing song. + * + * @param currentTrack The current track number being played. + * @param playListRows The playlist object. + **/ + var _setTrackTitle = function (currentTrack, playListRows) { + var trackTitleBox = document.querySelector(".player .info-box .track-info-box .track-title-text"); + var trackTitle = playListRows[currentTrack - 1].children[2].innerHTML; + + trackTitleBox.innerHTML = null; + + trackTitleBox.innerHTML = trackTitle; + + }; + + /** + * Plays the next track when a track has ended playing. + * + **/ + var _trackHasEnded = function () { + parseInt(_currentTrack); + _currentTrack = (_currentTrack === _elements.playListRows.length) ? 1 : _currentTrack + 1; _trackLoaded = false; + _resetPlayStatus(); + _setTrack(); - } - }, false); + }; - //Previous track button clicked. - _elements.playerButtons.previousTrackBtn.addEventListener("click", function(e) { - if (this.disabled !== true) { - _currentTrack--; - _trackLoaded = false; - _resetPlayStatus(); - _setTrack(); - } - }, false); + /** + * Updates the time for the song being played. + * + **/ + var _trackTimeChanged = function () { + var currentTimeBox = document.querySelector(".player .info-box .track-info-box .audio-time .current-time"); + var currentTime = audio.currentTime; + var duration = audio.duration; + var durationBox = document.querySelector(".player .info-box .track-info-box .audio-time .duration"); + var trackCurrentTime = _trackTime(currentTime); + var trackDuration = _trackTime(duration); - //User is moving progress indicator. - _progressBarIndicator.addEventListener("mousedown", _mouseDown, false); + currentTimeBox.innerHTML = null; + currentTimeBox.innerHTML = trackCurrentTime; - //User stops moving progress indicator. - window.addEventListener("mouseup", _mouseUp, false); - }; + durationBox.innerHTML = null; + durationBox.innerHTML = trackDuration; - /** - * Handles the mousedown event by a user and determines if the mouse is being moved. - * - * @param e The event object. - **/ - var _mouseDown = function(e) { - window.addEventListener("mousemove", _moveProgressIndicator, true); - audio.removeEventListener("timeupdate", _trackTimeChanged, false); + _updateProgressIndicator(audio); + _bufferProgress(audio); - _playAHead = true; - }; + if (currentTime > 0) { + for (var i = 0; i <= vCount; i++) { + if (currentTime >= verseStart[i] && currentTime <= verseEnd[i]) { + hilightverse(verseIndex[i], "red", true, playerScrollLock); - /** - * Handles the mouseup event by a user. - * - * @param e The event object. - **/ - var _mouseUp = function(e) { - if (_playAHead === true) { - var duration = parseFloat(audio.duration); - var progressIndicatorClick = parseFloat(_handleProgressIndicatorClick(e)); - window.removeEventListener("mousemove", _moveProgressIndicator, true); + if (nLastHighlight != verseIndex[i] && nLastHighlight != -1) + hilightverse(nLastHighlight, "black", false, false); + nLastHighlight = verseIndex[i]; + break; + } + } + } + }; - audio.currentTime = duration * progressIndicatorClick; - audio.addEventListener("timeupdate", _trackTimeChanged, false); - _playAHead = false; - } - }; + /** + * A utility function for converting a time in miliseconds to a readable time of minutes and seconds. + * + * @param seconds The time in seconds. + * + * @return time The time in minutes and/or seconds. + **/ + var _trackTime = function (seconds) { + var min = 0; + var sec = Math.floor(seconds); + var time = 0; - /** - * Moves the progress indicator to a new point in the audio. - * - * @param e The event object. - **/ - var _moveProgressIndicator = function(e) { - var newPosition = 0; - var progressBarOffsetLeft = _elements.progressBar.offsetLeft; - var progressBarWidth = 0; - var progressBarIndicator = _elements.progressBar.children[0].children[0].children[1]; - var progressBarIndicatorWidth = _progressBarIndicator.offsetWidth; - var xCoords = _getXY(e).x; + min = Math.floor(sec / 60); - progressBarWidth = _elements.progressBar.children[0].offsetWidth - progressBarIndicatorWidth; - newPosition = xCoords - progressBarOffsetLeft; + min = min >= 10 ? min : '0' + min; - if ((newPosition >= 1) && (newPosition <= progressBarWidth)) { - progressBarIndicator.style.left = newPosition + ".px"; - } - if (newPosition < 0) { - progressBarIndicator.style.left = "0"; - } - if (newPosition > progressBarWidth) { - progressBarIndicator.style.left = progressBarWidth + "px"; - } - }; + sec = Math.floor(sec % 60); - /** - * Controls playback of the audio element. - * - **/ - var _playBack = function() { - if (_elements.audio.paused) { - _elements.audio.play(); - _updatePlayStatus(true); - } else { - _elements.audio.pause(); - _updatePlayStatus(false); - } - }; + sec = sec >= 10 ? sec : '0' + sec; - /** - * Sets the track if it hasn't already been loaded yet. - * - **/ - var _setTrack = function() { - var songURL = _elements.audio.children[_currentTrack - 1].src; + time = min + ':' + sec; - _elements.audio.setAttribute("src", songURL); - _elements.audio.load(); + return time; + }; - _trackLoaded = true; + /** + * Updates both the large and small toggle buttons accordingly. + * + * @param audioPlaying A booean value indicating if audio is playing or paused. + **/ + var _updatePlayStatus = function (audioPlaying) { + if (audioPlaying) { + _elements.playerButtons.largeToggleBtn.children[0].className = "large-pause-btn"; - _setTrackTitle(_currentTrack, _elements.playListRows); + _elements.playerButtons.smallToggleBtn[_currentTrack - 1].children[0].className = "small-pause-btn"; + } else { + _elements.playerButtons.largeToggleBtn.children[0].className = "large-play-btn"; - _setActiveItem(_currentTrack, _elements.playListRows); + _elements.playerButtons.smallToggleBtn[_currentTrack - 1].children[0].className = "small-play-btn"; + } - _elements.trackInfoBox.style.visibility = "visible"; + //Update next and previous buttons accordingly + if (_currentTrack === 1) { + _elements.playerButtons.previousTrackBtn.disabled = true; + _elements.playerButtons.previousTrackBtn.className = "previous-track-btn disabled"; + } else if (_currentTrack > 1 && _currentTrack !== _elements.playListRows.length) { + _elements.playerButtons.previousTrackBtn.disabled = false; + _elements.playerButtons.previousTrackBtn.className = "previous-track-btn"; + _elements.playerButtons.nextTrackBtn.disabled = false; + _elements.playerButtons.nextTrackBtn.className = "next-track-btn"; + } else if (_currentTrack === _elements.playListRows.length) { + _elements.playerButtons.nextTrackBtn.disabled = true; + _elements.playerButtons.nextTrackBtn.className = "next-track-btn disabled"; + } + }; - _playBack(); - }; + /** + * Updates the location of the progress indicator according to how much time left in audio. + * + **/ + var _updateProgressIndicator = function () { + var currentTime = parseFloat(_elements.audio.currentTime); + var duration = parseFloat(_elements.audio.duration); + var indicatorLocation = 0; + var progressBarWidth = parseFloat(_elements.progressBar.offsetWidth); + var progressIndicatorWidth = parseFloat(_progressBarIndicator.offsetWidth); + var progressBarIndicatorWidth = progressBarWidth - progressIndicatorWidth; - /** - * Sets the activly playing item within the playlist. - * - * @param currentTrack The current track number being played. - * @param playListRows The playlist object. - **/ - var _setActiveItem = function(currentTrack, playListRows) { - for (var i = 0; i < playListRows.length; i++) { - playListRows[i].children[2].className = "track-title"; - } + indicatorLocation = progressBarIndicatorWidth * (currentTime / duration); - playListRows[currentTrack - 1].children[2].className = "track-title active-track"; - }; + _progressBarIndicator.style.left = indicatorLocation + "px"; + }; - /** - * Sets the text for the currently playing song. - * - * @param currentTrack The current track number being played. - * @param playListRows The playlist object. - **/ - var _setTrackTitle = function(currentTrack, playListRows) { - var trackTitleBox = document.querySelector(".player .info-box .track-info-box .track-title-text"); - var trackTitle = playListRows[currentTrack - 1].children[2].innerHTML; + /** + * Resets all toggle buttons to be play buttons. + * + **/ + var _resetPlayStatus = function () { + var smallToggleBtn = _elements.playerButtons.smallToggleBtn; - trackTitleBox.innerHTML = null; + _elements.playerButtons.largeToggleBtn.children[0].className = "large-play-btn"; - trackTitleBox.innerHTML = trackTitle; + for (var i = 0; i < smallToggleBtn.length; i++) { + if (smallToggleBtn[i].children[0].className === "small-pause-btn") { + smallToggleBtn[i].children[0].className = "small-play-btn"; + } + } + }; - }; - - /** - * Plays the next track when a track has ended playing. - * - **/ - var _trackHasEnded = function() { - parseInt(_currentTrack); - _currentTrack = (_currentTrack === _elements.playListRows.length) ? 1 : _currentTrack + 1; - _trackLoaded = false; - - _resetPlayStatus(); - - _setTrack(); - }; - - /** - * Updates the time for the song being played. - * - **/ - var _trackTimeChanged = function() { - var currentTimeBox = document.querySelector(".player .info-box .track-info-box .audio-time .current-time"); - var currentTime = audio.currentTime; - var duration = audio.duration; - var durationBox = document.querySelector(".player .info-box .track-info-box .audio-time .duration"); - var trackCurrentTime = _trackTime(currentTime); - var trackDuration = _trackTime(duration); - - currentTimeBox.innerHTML = null; - currentTimeBox.innerHTML = trackCurrentTime; - - durationBox.innerHTML = null; - durationBox.innerHTML = trackDuration; - - _updateProgressIndicator(audio); - _bufferProgress(audio); - }; - - /** - * A utility function for converting a time in miliseconds to a readable time of minutes and seconds. - * - * @param seconds The time in seconds. - * - * @return time The time in minutes and/or seconds. - **/ - var _trackTime = function(seconds) { - var min = 0; - var sec = Math.floor(seconds); - var time = 0; - - min = Math.floor(sec / 60); - - min = min >= 10 ? min : '0' + min; - - sec = Math.floor(sec % 60); - - sec = sec >= 10 ? sec : '0' + sec; - - time = min + ':' + sec; - - return time; - }; - - /** - * Updates both the large and small toggle buttons accordingly. - * - * @param audioPlaying A booean value indicating if audio is playing or paused. - **/ - var _updatePlayStatus = function(audioPlaying) { - if (audioPlaying) { - _elements.playerButtons.largeToggleBtn.children[0].className = "large-pause-btn"; - - _elements.playerButtons.smallToggleBtn[_currentTrack - 1].children[0].className = "small-pause-btn"; - } else { - _elements.playerButtons.largeToggleBtn.children[0].className = "large-play-btn"; - - _elements.playerButtons.smallToggleBtn[_currentTrack - 1].children[0].className = "small-play-btn"; - } - - //Update next and previous buttons accordingly - if (_currentTrack === 1) { - _elements.playerButtons.previousTrackBtn.disabled = true; - _elements.playerButtons.previousTrackBtn.className = "previous-track-btn disabled"; - } else if (_currentTrack > 1 && _currentTrack !== _elements.playListRows.length) { - _elements.playerButtons.previousTrackBtn.disabled = false; - _elements.playerButtons.previousTrackBtn.className = "previous-track-btn"; - _elements.playerButtons.nextTrackBtn.disabled = false; - _elements.playerButtons.nextTrackBtn.className = "next-track-btn"; - } else if (_currentTrack === _elements.playListRows.length) { - _elements.playerButtons.nextTrackBtn.disabled = true; - _elements.playerButtons.nextTrackBtn.className = "next-track-btn disabled"; - } - }; - - /** - * Updates the location of the progress indicator according to how much time left in audio. - * - **/ - var _updateProgressIndicator = function() { - var currentTime = parseFloat(_elements.audio.currentTime); - var duration = parseFloat(_elements.audio.duration); - var indicatorLocation = 0; - var progressBarWidth = parseFloat(_elements.progressBar.offsetWidth); - var progressIndicatorWidth = parseFloat(_progressBarIndicator.offsetWidth); - var progressBarIndicatorWidth = progressBarWidth - progressIndicatorWidth; - - indicatorLocation = progressBarIndicatorWidth * (currentTime / duration); - - _progressBarIndicator.style.left = indicatorLocation + "px"; - }; - - /** - * Resets all toggle buttons to be play buttons. - * - **/ - var _resetPlayStatus = function() { - var smallToggleBtn = _elements.playerButtons.smallToggleBtn; - - _elements.playerButtons.largeToggleBtn.children[0].className = "large-play-btn"; - - for (var i = 0; i < smallToggleBtn.length; i++) { - if (smallToggleBtn[i].children[0].className === "small-pause-btn") { - smallToggleBtn[i].children[0].className = "small-play-btn"; - } - } - }; - - return { - initPlayer: initPlayer - }; + return { + initPlayer: initPlayer + }; }; -(function() { - var player = new audioPlayer(); +(function () { + var player = new audioPlayer(); - player.initPlayer(); + player.initPlayer(); })(); \ No newline at end of file From 16e5e99d6f91e95c0faa43b17fb66023f4b42a78 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 26 Nov 2021 18:27:23 +0330 Subject: [PATCH 06/16] #250 some improvements --- GanjooRazor/Pages/_AudioPlayerPartial.cshtml | 20 ++++++++++---------- GanjooRazor/wwwroot/css/audioplayer.css | 8 ++++---- GanjooRazor/wwwroot/js/audioplayer.js | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml index ea0331f8..b18165fd 100644 --- a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml +++ b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml @@ -57,17 +57,17 @@ { var recitaion = Model.Recitations[nRecitationIndex];
-
- Small toggle button +
+ Small toggle button +
+
+ @((nRecitationIndex + 1).ToPersianNumbers()). +
+ +
@($"{GanjooRazor.APIRoot.InternetUrl}/api/audio/file/{recitaion.Id}.xml")
-
- @((nRecitationIndex + 1).ToPersianNumbers()). -
- -
@($"{GanjooRazor.APIRoot.InternetUrl}/api/audio/file/{recitaion.Id}.xml")
-
}
diff --git a/GanjooRazor/wwwroot/css/audioplayer.css b/GanjooRazor/wwwroot/css/audioplayer.css index 4f28d1f3..74e37eab 100644 --- a/GanjooRazor/wwwroot/css/audioplayer.css +++ b/GanjooRazor/wwwroot/css/audioplayer.css @@ -110,13 +110,13 @@ position: relative; } .container .player .progress-box .progress-cell { - height: 12px; + height: 20px; position: relative; } .container .player .progress-box .progress-cell .progress { background: #fff; border: 1px solid #d9d9d9; - height: 8px; + height: 16px; position: relative; width: auto; } @@ -130,12 +130,12 @@ border: 1px solid #bebebe; border-radius: 3px; cursor: pointer; - height: 10px; + height: 18px; left: 0; overflow: hidden; position: absolute; top: -2px; - width: 22px; + width: 30px; } .container .player .controls-box { bottom: 10px; diff --git a/GanjooRazor/wwwroot/js/audioplayer.js b/GanjooRazor/wwwroot/js/audioplayer.js index 7d8cb62c..04bc99a2 100644 --- a/GanjooRazor/wwwroot/js/audioplayer.js +++ b/GanjooRazor/wwwroot/js/audioplayer.js @@ -200,6 +200,7 @@ var audioPlayer = function () { //User stops moving progress indicator. window.addEventListener("mouseup", _mouseUp, false); + }; /** @@ -224,8 +225,7 @@ var audioPlayer = function () { var duration = parseFloat(audio.duration); var progressIndicatorClick = parseFloat(_handleProgressIndicatorClick(e)); window.removeEventListener("mousemove", _moveProgressIndicator, true); - - audio.currentTime = duration * progressIndicatorClick; + audio.currentTime += duration * progressIndicatorClick; audio.addEventListener("timeupdate", _trackTimeChanged, false); _playAHead = false; } From c1d53ebd901817ebc2d9c2cbc73c1885750f2511 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Mon, 29 Nov 2021 19:39:34 +0330 Subject: [PATCH 07/16] #250 trying pure HTML audio with minimum additional javascript --- GanjooRazor/Pages/Index.cshtml | 1 - GanjooRazor/Pages/_AudioPlayerPartial.cshtml | 142 +++--- GanjooRazor/wwwroot/css/audioplayer.css | 255 ---------- GanjooRazor/wwwroot/css/p8.css | 8 + GanjooRazor/wwwroot/js/audioplayer.js | 501 ------------------- 5 files changed, 83 insertions(+), 824 deletions(-) delete mode 100644 GanjooRazor/wwwroot/css/audioplayer.css delete mode 100644 GanjooRazor/wwwroot/js/audioplayer.js diff --git a/GanjooRazor/Pages/Index.cshtml b/GanjooRazor/Pages/Index.cshtml index 379d0442..0fb01f13 100644 --- a/GanjooRazor/Pages/Index.cshtml +++ b/GanjooRazor/Pages/Index.cshtml @@ -18,7 +18,6 @@ } - diff --git a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml index b18165fd..1c68e484 100644 --- a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml +++ b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml @@ -2,76 +2,84 @@ @using DNTPersianUtils.Core @{ } + +
+ @for (var nRecitationIndex = 0; nRecitationIndex < Model.Recitations.Length; nRecitationIndex++) + { + var recitaion = Model.Recitations[nRecitationIndex]; +
+ +
- - -
-
-
-
- 00:00 / - 00:00 -
-
- - -
-
-
-
-
-
-
-
- -
- - -
- پخش خوانش بعدی - پخش خوانش پیشین -
- - -
- - -
- - @for (var nRecitationIndex = 0; nRecitationIndex < Model.Recitations.Length; nRecitationIndex++) - { - var recitaion = Model.Recitations[nRecitationIndex]; -
-
- Small toggle button -
-
- @((nRecitationIndex + 1).ToPersianNumbers()). -
- -
@($"{GanjooRazor.APIRoot.InternetUrl}/api/audio/file/{recitaion.Id}.xml")
-
- } -
- -
می‌خواهید شما بخوانید؟ اینجا را ببینید.
+ }
- + diff --git a/GanjooRazor/wwwroot/css/audioplayer.css b/GanjooRazor/wwwroot/css/audioplayer.css deleted file mode 100644 index 74e37eab..00000000 --- a/GanjooRazor/wwwroot/css/audioplayer.css +++ /dev/null @@ -1,255 +0,0 @@ -.screen-reader-text { - /* Reusable, toolbox kind of class */ - position: absolute; - top: -9999px; - left: -9999px; -} - -.disabled { - color: #666; - cursor: default; -} - -.show { - display: inline-block !important; -} - - -.container { - margin: 0 auto; - width: 500px; -} -.container .player { - height: 60px; - margin: 0; - position: relative; - width: 400px; - /* Small devices (tablets, 768px and up) */ - /* Medium devices (desktops, 992px and up) */ - /* Large devices (large desktops, 1200px and up) */ - *zoom: 1; -} -@media (min-width: 768px) and (max-width: 991px) { - .container .player { - width: 470px; - } -} -@media (min-width: 992px) and (max-width: 1100px) { - .container .player { - width: 470px; - } -} -@media (min-width: 1200px) { - .container .player { - width: 470px; - } -} -.container .player .large-toggle-btn { - border: 1px solid #d9d9d9; - border-radius: 2px; - float: left; - font-size: 1.5em; - height: 50px; - margin: 0 10px 0 0; - overflow: hidden; - padding: 5px 0 0 0; - position: relative; - text-align: center; - vertical-align: bottom; - width: 54px; -} -.container .player .large-toggle-btn .large-play-btn { - cursor: pointer; - display: inline-block; - position: relative; - top: -14%; -} - -.container .player .large-toggle-btn .large-pause-btn { - cursor: pointer; - display: inline-block; - position: relative; - top: -13%; -} -.container .player .info-box { - bottom: 10px; - left: 65px; - position: absolute; - top: 15px; -} -.container .player .info-box .track-info-box { - float: left; - font-size: 12px; - margin: 0 0 6px 0; - visibility: hidden; - width: 400px; - *zoom: 1; -} -.container .player .info-box .track-info-box .track-title-text { - display: inline-block; -} -.container .player .info-box .track-info-box .audio-time { - display: inline-block; - padding: 0 0 0 5px; - width: 80px; -} -.container .player .info-box .track-info-box:before, .container .player .info-box .track-info-box:after { - content: " "; - display: table; -} -.container .player .info-box .track-info-box:after { - clear: both; - display: block; - font-size: 0; - height: 0; - visibility: hidden; -} -.container .player .progress-box { - float: left; - min-width: 270px; - position: relative; -} -.container .player .progress-box .progress-cell { - height: 20px; - position: relative; -} -.container .player .progress-box .progress-cell .progress { - background: #fff; - border: 1px solid #d9d9d9; - height: 16px; - position: relative; - width: auto; -} -.container .player .progress-box .progress-cell .progress .progress-buffer { - background: #337ab7; - height: 100%; - width: 0; -} -.container .player .progress-box .progress-cell .progress .progress-indicator { - background: #fff; - border: 1px solid #bebebe; - border-radius: 3px; - cursor: pointer; - height: 18px; - left: 0; - overflow: hidden; - position: absolute; - top: -2px; - width: 30px; -} -.container .player .controls-box { - bottom: 10px; - left: 350px; - position: absolute; -} -.container .player .controls-box .previous-track-btn { - cursor: pointer; - display: inline-block; -} -.container .player .controls-box .next-track-btn { - cursor: pointer; - display: inline-block; -} -.container .player:before, .container .player:after { - content: " "; - display: table; -} -.container .player:after { - clear: both; - display: block; - font-size: 0; - height: 0; - visibility: hidden; -} -.container .play-list { - display: block; - margin: 0 auto 20px auto; - width: 100%; -} -.container .play-list .play-list-row { - display: block; - margin: 10px 0; - width: 100%; - *zoom: 1; -} -.container .play-list .play-list-row .track-title .playlist-track { - color: #000; - text-decoration: none; -} -.container .play-list .play-list-row .track-title .playlist-track:hover { - text-decoration: underline; -} -.container .play-list .play-list-row .small-toggle-btn { - border: 1px solid #d9d9d9; - border-radius: 2px; - cursor: pointer; - display: inline-block; - height: 20px; - margin: 0 auto; - overflow: hidden; - position: relative; - text-align: center; - vertical-align: middle; - width: 20px; -} -.container .play-list .play-list-row .small-toggle-btn .small-play-btn { - display: inline-block; -} -.container .play-list .play-list-row .small-toggle-btn .small-pause-btn { - display: inline-block; -} -.container .play-list .play-list-row .track-number { - display: inline-block; -} -.container .play-list .play-list-row .track-title { - display: inline-block; -} -.container .play-list .play-list-row .track-title .playlist-track { - text-decoration: none; -} -.container .play-list .play-list-row .track-title .playlist-track:hover { - text-decoration: underline; -} -.container .play-list .play-list-row .track-title.active-track { - font-weight: bold; -} -.container .play-list .play-list-row:before, .container .play-list .play-list-row:after { - content: " "; - display: table; -} -.container .play-list .play-list-row:after { - clear: both; - display: block; - font-size: 0; - height: 0; - visibility: hidden; -} - -.container .player .large-toggle-btn .large-play-btn:before { - content: "play_arrow"; - font: 1.5em/1.75 "Material Icons"; -} -.container .player .large-toggle-btn .large-pause-btn:before { - content: "pause"; - font: 1.5em/1.75 "Material Icons"; -} -.container .player .controls-box .previous-track-btn:before { - content: "skip_previous"; - font: 1em "Material Icons"; -} -.container .player .controls-box .next-track-btn:before { - content: "skip_next"; - font: 1em "Material Icons"; -} -.container .play-list .play-list-row .small-toggle-btn .small-play-btn:before { - content: "play_arrow"; - font: 0.85em "Material Icons"; -} -.container .play-list .play-list-row .small-toggle-btn .small-pause-btn:before { - content: "pause"; - font: 0.85em "Material Icons"; -} - -.xml-url-path{ - display:none; -} \ No newline at end of file diff --git a/GanjooRazor/wwwroot/css/p8.css b/GanjooRazor/wwwroot/css/p8.css index 428f410f..5a80f499 100644 --- a/GanjooRazor/wwwroot/css/p8.css +++ b/GanjooRazor/wwwroot/css/p8.css @@ -1123,3 +1123,11 @@ ol { #footer .link-list-tools li { padding-right: 50px; } + +.audio-player{ + +} + +.xml-url-path{ + display:none; +} \ No newline at end of file diff --git a/GanjooRazor/wwwroot/js/audioplayer.js b/GanjooRazor/wwwroot/js/audioplayer.js deleted file mode 100644 index 04bc99a2..00000000 --- a/GanjooRazor/wwwroot/js/audioplayer.js +++ /dev/null @@ -1,501 +0,0 @@ -//original source: https://codepen.io/craigstroman/pen/aOyRYx -var audioPlayer = function () { - "use strict"; - - var verseStart = []; - var verseEnd = []; - var verseIndex = []; - var nLastHighlight = -1; - var vCount = 0; - - // Private variables - var _currentTrack = null; - var _elements = { - audio: document.getElementById("audio"), - playerButtons: { - largeToggleBtn: document.querySelector(".large-toggle-btn"), - nextTrackBtn: document.querySelector(".next-track-btn"), - previousTrackBtn: document.querySelector(".previous-track-btn"), - smallToggleBtn: document.getElementsByClassName("small-toggle-btn") - }, - progressBar: document.querySelector(".progress-box"), - playListRows: document.getElementsByClassName("play-list-row"), - trackInfoBox: document.querySelector(".track-info-box") - }; - var _playAHead = false; - var _progressBarIndicator = _elements.progressBar.children[0].children[0].children[1]; - var _trackLoaded = false; - - /** - * Determines the buffer progress. - * - * @param audio The audio element on the page. - **/ - var _bufferProgress = function (audio) { - var bufferedTime = (audio.buffered.end(0) * 100) / audio.duration; - var progressBuffer = _elements.progressBar.children[0].children[0].children[0]; - - progressBuffer.style.width = bufferedTime + "%"; - }; - - /** - * A utility function for getting the event cordinates based on browser type. - * - * @param e The JavaScript event. - **/ - var _getXY = function (e) { - var containerX = _elements.progressBar.offsetLeft; - var containerY = _elements.progressBar.offsetTop; - - var coords = { - x: null, - y: null - }; - - var isTouchSuopported = "ontouchstart" in window; - - if (isTouchSuopported) { //For touch devices - coords.x = e.clientX - containerX; - coords.y = e.clientY - containerY; - - return coords; - } else if (e.offsetX || e.offsetX === 0) { // For webkit browsers - coords.x = e.offsetX; - coords.y = e.offsetY; - - return coords; - } else if (e.layerX || e.layerX === 0) { // For Mozilla firefox - coords.x = e.layerX; - coords.y = e.layerY; - - return coords; - } - }; - - var _handleProgressIndicatorClick = function (e) { - var progressBar = document.querySelector(".progress-box"); - var xCoords = _getXY(e).x; - - return (xCoords - progressBar.offsetLeft) / progressBar.children[0].offsetWidth; - }; - - /** - * Initializes the html5 audio player and the playlist. - * - **/ - var initPlayer = function () { - - if (_currentTrack === 1 || _currentTrack === null) { - _elements.playerButtons.previousTrackBtn.disabled = true; - } - - //Adding event listeners to playlist clickable elements. - for (var i = 0; i < _elements.playListRows.length; i++) { - var smallToggleBtn = _elements.playerButtons.smallToggleBtn[i]; - var playListLink = _elements.playListRows[i].children[2].children[0]; - - //Playlist link clicked. - playListLink.addEventListener("click", function (e) { - e.preventDefault(); - var selectedTrack = parseInt(this.parentNode.parentNode.getAttribute("data-track-row")); - - if (selectedTrack !== _currentTrack) { - _resetPlayStatus(); - _currentTrack = null; - _trackLoaded = false; - } - - if (_trackLoaded === false) { - _currentTrack = parseInt(selectedTrack); - _setTrack(); - } else { - _playBack(this); - } - }, false); - - //Small toggle button clicked. - smallToggleBtn.addEventListener("click", function (e) { - e.preventDefault(); - var selectedTrack = parseInt(this.parentNode.getAttribute("data-track-row")); - - if (selectedTrack !== _currentTrack) { - _resetPlayStatus(); - _currentTrack = null; - _trackLoaded = false; - } - - if (_trackLoaded === false) { - _currentTrack = parseInt(selectedTrack); - _setTrack(); - } else { - _playBack(this); - } - - }, false); - } - - //Audio time has changed so update it. - _elements.audio.addEventListener("timeupdate", _trackTimeChanged, false); - - //Audio track has ended playing. - _elements.audio.addEventListener("ended", function (e) { - _trackHasEnded(); - }, false); - - //Audio error. - _elements.audio.addEventListener("error", function (e) { - switch (e.target.error.code) { - case e.target.error.MEDIA_ERR_ABORTED: - alert('You aborted the video playback.'); - break; - case e.target.error.MEDIA_ERR_NETWORK: - alert('A network error caused the audio download to fail.'); - break; - case e.target.error.MEDIA_ERR_DECODE: - alert('The audio playback was aborted due to a corruption problem or because the video used features your browser did not support.'); - break; - case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED: - alert('The video audio not be loaded, either because the server or network failed or because the format is not supported.'); - break; - default: - alert('An unknown error occurred.'); - break; - } - trackLoaded = false; - _resetPlayStatus(); - }, false); - - //Large toggle button clicked. - _elements.playerButtons.largeToggleBtn.addEventListener("click", function (e) { - if (_trackLoaded === false) { - _currentTrack = parseInt(1); - _setTrack() - } else { - _playBack(); - } - }, false); - - //Next track button clicked. - _elements.playerButtons.nextTrackBtn.addEventListener("click", function (e) { - if (this.disabled !== true) { - _currentTrack++; - _trackLoaded = false; - _resetPlayStatus(); - _setTrack(); - } - }, false); - - //Previous track button clicked. - _elements.playerButtons.previousTrackBtn.addEventListener("click", function (e) { - if (this.disabled !== true) { - _currentTrack--; - _trackLoaded = false; - _resetPlayStatus(); - _setTrack(); - } - }, false); - - //User is moving progress indicator. - _progressBarIndicator.addEventListener("mousedown", _mouseDown, false); - - //User stops moving progress indicator. - window.addEventListener("mouseup", _mouseUp, false); - - }; - - /** - * Handles the mousedown event by a user and determines if the mouse is being moved. - * - * @param e The event object. - **/ - var _mouseDown = function (e) { - window.addEventListener("mousemove", _moveProgressIndicator, true); - audio.removeEventListener("timeupdate", _trackTimeChanged, false); - - _playAHead = true; - }; - - /** - * Handles the mouseup event by a user. - * - * @param e The event object. - **/ - var _mouseUp = function (e) { - if (_playAHead === true) { - var duration = parseFloat(audio.duration); - var progressIndicatorClick = parseFloat(_handleProgressIndicatorClick(e)); - window.removeEventListener("mousemove", _moveProgressIndicator, true); - audio.currentTime += duration * progressIndicatorClick; - audio.addEventListener("timeupdate", _trackTimeChanged, false); - _playAHead = false; - } - }; - - /** - * Moves the progress indicator to a new point in the audio. - * - * @param e The event object. - **/ - var _moveProgressIndicator = function (e) { - var newPosition = 0; - var progressBarOffsetLeft = _elements.progressBar.offsetLeft; - var progressBarWidth = 0; - var progressBarIndicator = _elements.progressBar.children[0].children[0].children[1]; - var progressBarIndicatorWidth = _progressBarIndicator.offsetWidth; - var xCoords = _getXY(e).x; - - progressBarWidth = _elements.progressBar.children[0].offsetWidth - progressBarIndicatorWidth; - newPosition = xCoords - progressBarOffsetLeft; - - if ((newPosition >= 1) && (newPosition <= progressBarWidth)) { - progressBarIndicator.style.left = newPosition + ".px"; - } - if (newPosition < 0) { - progressBarIndicator.style.left = "0"; - } - if (newPosition > progressBarWidth) { - progressBarIndicator.style.left = progressBarWidth + "px"; - } - }; - - /** - * Controls playback of the audio element. - * - **/ - var _playBack = function () { - if (_elements.audio.paused) { - _elements.audio.play(); - _updatePlayStatus(true); - } else { - _elements.audio.pause(); - _updatePlayStatus(false); - } - }; - - var _setXml = function () { - var xmlUrl = _elements.playListRows[_currentTrack - 1].children[3].innerHTML; - $.ajax({ - type: "GET", - url: xmlUrl, - dataType: "xml", - success: function (xml) { - var nOneSecondBugFix = 2000; - $(xml).find('OneSecondBugFix').each(function () { - nOneSecondBugFix = parseInt($(xml).find('OneSecondBugFix').text()); - }); - var v = 0; - $(xml).find('SyncInfo').each(function () { - verseStart[v] = parseInt($(this).find('AudioMiliseconds').text()) / nOneSecondBugFix; - verseIndex[v] = parseInt($(this).find('VerseOrder').text()); - if (v > 0) - verseEnd[v - 1] = verseStart[v]; - v++; - }); - v--; - if (v > 1) - verseEnd[v] = verseStart[v] + 2 * (verseEnd[v - 1] - verseStart[v - 1]); - vCount = v; - } - }); - } - - /** - * Sets the track if it hasn't already been loaded yet. - * - **/ - var _setTrack = function () { - _setXml(); - var songURL = _elements.audio.children[_currentTrack - 1].src; - - _elements.audio.setAttribute("src", songURL); - _elements.audio.load(); - - _trackLoaded = true; - - _setTrackTitle(_currentTrack, _elements.playListRows); - - _setActiveItem(_currentTrack, _elements.playListRows); - - _elements.trackInfoBox.style.visibility = "visible"; - - _playBack(); - }; - - /** - * Sets the activly playing item within the playlist. - * - * @param currentTrack The current track number being played. - * @param playListRows The playlist object. - **/ - var _setActiveItem = function (currentTrack, playListRows) { - for (var i = 0; i < playListRows.length; i++) { - playListRows[i].children[2].className = "track-title"; - } - - playListRows[currentTrack - 1].children[2].className = "track-title active-track"; - }; - - /** - * Sets the text for the currently playing song. - * - * @param currentTrack The current track number being played. - * @param playListRows The playlist object. - **/ - var _setTrackTitle = function (currentTrack, playListRows) { - var trackTitleBox = document.querySelector(".player .info-box .track-info-box .track-title-text"); - var trackTitle = playListRows[currentTrack - 1].children[2].innerHTML; - - trackTitleBox.innerHTML = null; - - trackTitleBox.innerHTML = trackTitle; - - }; - - /** - * Plays the next track when a track has ended playing. - * - **/ - var _trackHasEnded = function () { - parseInt(_currentTrack); - _currentTrack = (_currentTrack === _elements.playListRows.length) ? 1 : _currentTrack + 1; - _trackLoaded = false; - - _resetPlayStatus(); - - _setTrack(); - }; - - /** - * Updates the time for the song being played. - * - **/ - var _trackTimeChanged = function () { - var currentTimeBox = document.querySelector(".player .info-box .track-info-box .audio-time .current-time"); - var currentTime = audio.currentTime; - var duration = audio.duration; - var durationBox = document.querySelector(".player .info-box .track-info-box .audio-time .duration"); - var trackCurrentTime = _trackTime(currentTime); - var trackDuration = _trackTime(duration); - - currentTimeBox.innerHTML = null; - currentTimeBox.innerHTML = trackCurrentTime; - - durationBox.innerHTML = null; - durationBox.innerHTML = trackDuration; - - _updateProgressIndicator(audio); - _bufferProgress(audio); - - if (currentTime > 0) { - for (var i = 0; i <= vCount; i++) { - if (currentTime >= verseStart[i] && currentTime <= verseEnd[i]) { - hilightverse(verseIndex[i], "red", true, playerScrollLock); - - if (nLastHighlight != verseIndex[i] && nLastHighlight != -1) - hilightverse(nLastHighlight, "black", false, false); - nLastHighlight = verseIndex[i]; - break; - } - } - } - }; - - /** - * A utility function for converting a time in miliseconds to a readable time of minutes and seconds. - * - * @param seconds The time in seconds. - * - * @return time The time in minutes and/or seconds. - **/ - var _trackTime = function (seconds) { - var min = 0; - var sec = Math.floor(seconds); - var time = 0; - - min = Math.floor(sec / 60); - - min = min >= 10 ? min : '0' + min; - - sec = Math.floor(sec % 60); - - sec = sec >= 10 ? sec : '0' + sec; - - time = min + ':' + sec; - - return time; - }; - - /** - * Updates both the large and small toggle buttons accordingly. - * - * @param audioPlaying A booean value indicating if audio is playing or paused. - **/ - var _updatePlayStatus = function (audioPlaying) { - if (audioPlaying) { - _elements.playerButtons.largeToggleBtn.children[0].className = "large-pause-btn"; - - _elements.playerButtons.smallToggleBtn[_currentTrack - 1].children[0].className = "small-pause-btn"; - } else { - _elements.playerButtons.largeToggleBtn.children[0].className = "large-play-btn"; - - _elements.playerButtons.smallToggleBtn[_currentTrack - 1].children[0].className = "small-play-btn"; - } - - //Update next and previous buttons accordingly - if (_currentTrack === 1) { - _elements.playerButtons.previousTrackBtn.disabled = true; - _elements.playerButtons.previousTrackBtn.className = "previous-track-btn disabled"; - } else if (_currentTrack > 1 && _currentTrack !== _elements.playListRows.length) { - _elements.playerButtons.previousTrackBtn.disabled = false; - _elements.playerButtons.previousTrackBtn.className = "previous-track-btn"; - _elements.playerButtons.nextTrackBtn.disabled = false; - _elements.playerButtons.nextTrackBtn.className = "next-track-btn"; - } else if (_currentTrack === _elements.playListRows.length) { - _elements.playerButtons.nextTrackBtn.disabled = true; - _elements.playerButtons.nextTrackBtn.className = "next-track-btn disabled"; - } - }; - - /** - * Updates the location of the progress indicator according to how much time left in audio. - * - **/ - var _updateProgressIndicator = function () { - var currentTime = parseFloat(_elements.audio.currentTime); - var duration = parseFloat(_elements.audio.duration); - var indicatorLocation = 0; - var progressBarWidth = parseFloat(_elements.progressBar.offsetWidth); - var progressIndicatorWidth = parseFloat(_progressBarIndicator.offsetWidth); - var progressBarIndicatorWidth = progressBarWidth - progressIndicatorWidth; - - indicatorLocation = progressBarIndicatorWidth * (currentTime / duration); - - _progressBarIndicator.style.left = indicatorLocation + "px"; - }; - - /** - * Resets all toggle buttons to be play buttons. - * - **/ - var _resetPlayStatus = function () { - var smallToggleBtn = _elements.playerButtons.smallToggleBtn; - - _elements.playerButtons.largeToggleBtn.children[0].className = "large-play-btn"; - - for (var i = 0; i < smallToggleBtn.length; i++) { - if (smallToggleBtn[i].children[0].className === "small-pause-btn") { - smallToggleBtn[i].children[0].className = "small-play-btn"; - } - } - }; - - return { - initPlayer: initPlayer - }; -}; - -(function () { - var player = new audioPlayer(); - - player.initPlayer(); -})(); \ No newline at end of file From 79fcad229677d3006ef4efce9f1aa73fba870251 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Mon, 29 Nov 2021 19:56:33 +0330 Subject: [PATCH 08/16] #250 removing unused CSS class --- GanjooRazor/wwwroot/css/p8.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/GanjooRazor/wwwroot/css/p8.css b/GanjooRazor/wwwroot/css/p8.css index 5a80f499..557acb2d 100644 --- a/GanjooRazor/wwwroot/css/p8.css +++ b/GanjooRazor/wwwroot/css/p8.css @@ -1126,8 +1126,4 @@ ol { .audio-player{ -} - -.xml-url-path{ - display:none; } \ No newline at end of file From 95a659c8bdfd2287601378a881af827c5b1235c0 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Mon, 29 Nov 2021 21:06:19 +0330 Subject: [PATCH 09/16] #250 adding recitation meta data to new UI --- GanjooRazor/Pages/_AudioPlayerPartial.cshtml | 3 ++ .../Pages/_AudioPlayerPartial.cshtml.cs | 36 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml index 1c68e484..a0401ead 100644 --- a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml +++ b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml @@ -62,6 +62,9 @@ مرورگر شما از پخش صدای HTML 5 پشتیبانی نمی‌کند. +
+ @recitaion.AudioTitle @Html.Raw(Model.getAudioDesc(recitaion, nRecitationIndex == 0)) +
+
@for (var nRecitationIndex = 0; nRecitationIndex < Model.Recitations.Length; nRecitationIndex++) @@ -67,9 +18,10 @@
+ @if (Model.IsPoemPage) + { + if (Model.GanjoorPage != null && Model.GanjoorPage.Poem.Recitations.Length > 0) + { + + } + } + @if (Model.IsHomePage) { @if (!string.IsNullOrEmpty(Model.LastError)) @@ -78,112 +136,6 @@ @{ - if (Model.IsPoemPage) - { - if (Model.GanjoorPage != null && Model.GanjoorPage.Poem.Recitations.Length > 0) - { - - - - - - } - } - if (!string.IsNullOrEmpty(Model.PinterestUrl)) { + +
+ + @if (nRecitationIndex == 4 && Model.Recitations.Length > 5) + { + همهٔ خوانش‌هاautorenew + } }
diff --git a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs index e1514a08..3452f97e 100644 --- a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs +++ b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs @@ -40,5 +40,10 @@ namespace GanjooRazor.Pages return audiodesc; } + + public string CSSClass(int recitationIndex) + { + return recitationIndex < 5 ? "audio-player" : "hidden-item"; + } } } diff --git a/GanjooRazor/wwwroot/css/p8.css b/GanjooRazor/wwwroot/css/p8.css index 557acb2d..0952ce52 100644 --- a/GanjooRazor/wwwroot/css/p8.css +++ b/GanjooRazor/wwwroot/css/p8.css @@ -1126,4 +1126,12 @@ ol { .audio-player{ +} + +.recitaion-info{ + +} + +.hidden-item { + display: none; } \ No newline at end of file From c9ba4cdd623f7ef7f61cfd6541c51094c6b0b1ae Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Wed, 1 Dec 2021 19:25:43 +0330 Subject: [PATCH 13/16] #250 showing hidden recitations button now works --- GanjooRazor/Pages/_AudioPlayerPartial.cshtml | 2 +- GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs | 2 +- GanjooRazor/wwwroot/css/p8.css | 2 +- GanjooRazor/wwwroot/js/bk.js | 8 ++++++++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml index 9213b077..c00d3279 100644 --- a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml +++ b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml @@ -39,7 +39,7 @@ @if (nRecitationIndex == 4 && Model.Recitations.Length > 5) { - همهٔ خوانش‌هاautorenew + همهٔ خوانش‌هاautorenew } } diff --git a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs index 3452f97e..88231894 100644 --- a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs +++ b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml.cs @@ -43,7 +43,7 @@ namespace GanjooRazor.Pages public string CSSClass(int recitationIndex) { - return recitationIndex < 5 ? "audio-player" : "hidden-item"; + return recitationIndex < 5 ? "audio-player" : "hidden-recitation"; } } } diff --git a/GanjooRazor/wwwroot/css/p8.css b/GanjooRazor/wwwroot/css/p8.css index 0952ce52..4f54d3c2 100644 --- a/GanjooRazor/wwwroot/css/p8.css +++ b/GanjooRazor/wwwroot/css/p8.css @@ -1132,6 +1132,6 @@ ol { } -.hidden-item { +.hidden-recitation { display: none; } \ No newline at end of file diff --git a/GanjooRazor/wwwroot/js/bk.js b/GanjooRazor/wwwroot/js/bk.js index c6754e7d..749d3725 100644 --- a/GanjooRazor/wwwroot/js/bk.js +++ b/GanjooRazor/wwwroot/js/bk.js @@ -895,4 +895,12 @@ function loadMoreRelatedFromPoet(poetId, rhythm, rhymeLetters, skipPoemFullUrl1, $(data).appendTo(document.getElementById(divId)); }, }); +} + +function showAllRecitations() { + const hiddenRecitations = document.querySelectorAll('.hidden-recitation'); + hiddenRecitations.forEach(function (recitation) { + recitation.className = 'audio-player'; + }); + document.getElementById('load-all-recitations').style.display = 'none'; } \ No newline at end of file From da12fdc8e2723a5d867341a450fa63379d05289b Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Wed, 1 Dec 2021 21:43:42 +0330 Subject: [PATCH 14/16] #250 seeking couplet recitations --- GanjooRazor/Pages/Index.cshtml | 11 +++++++++++ GanjooRazor/Pages/_AudioPlayerPartial.cshtml | 2 -- GanjooRazor/wwwroot/js/bk.js | 19 ++++++++++--------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/GanjooRazor/Pages/Index.cshtml b/GanjooRazor/Pages/Index.cshtml index f5209a81..81e10475 100644 --- a/GanjooRazor/Pages/Index.cshtml +++ b/GanjooRazor/Pages/Index.cshtml @@ -110,6 +110,17 @@ } }; + + } } diff --git a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml index c00d3279..cbaf6a7a 100644 --- a/GanjooRazor/Pages/_AudioPlayerPartial.cshtml +++ b/GanjooRazor/Pages/_AudioPlayerPartial.cshtml @@ -33,8 +33,6 @@ _trackTimeChanged(document.getElementById('audio-@(nRecitationIndex + 1)')); }); - - @if (nRecitationIndex == 4 && Model.Recitations.Length > 5) diff --git a/GanjooRazor/wwwroot/js/bk.js b/GanjooRazor/wwwroot/js/bk.js index 749d3725..e6d26f1e 100644 --- a/GanjooRazor/wwwroot/js/bk.js +++ b/GanjooRazor/wwwroot/js/bk.js @@ -415,12 +415,11 @@ function getVerseIndexFromCoupleIndex(coupletIndex) { function playCouplet(coupletIndex) { var vIndex = getVerseIndexFromCoupleIndex(coupletIndex); - if (jlist.isPlaying) { - jlist.pause(); - } var comboId = '#narrators-' + coupletIndex; - var recitationIndex = $(comboId).find(":selected").val() - jlist.select(recitationIndex); + var recitationIndex = parseInt($(comboId).find(":selected").val()); + var recitationOrder = recitationIndex + 1; + + if (audioxmlfiles.length > 0) { $.ajax({ @@ -439,13 +438,15 @@ function playCouplet(coupletIndex) { var v = parseInt($(this).find('VerseOrder').text()) if (v == vIndex) { var verseStart = parseInt($(this).find('AudioMiliseconds').text()) / nOneSecondBugFix; - $(jlist.cssSelector.jPlayer).jPlayer("play"); + var audioControl = document.getElementById('audio-' + String(recitationOrder)); + audioControl.play(); + var buttonList = '#listen-' + coupletIndex; + $(buttonList).text('در حال دریافت خوانش ...'); setTimeout(function () { - $(jlist.cssSelector.jPlayer).jPlayer("play", verseStart); + audioControl.currentTime = verseStart; + $(buttonList).text('در حال خواندن'); }, 100); foundCouplet = true; - var buttonList = '#listen-' + coupletIndex; - $(buttonList).text('در حال خواندن'); return false; } }); From b1d3eddacc31e02d1545b6f4582d817e6f236f1e Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Wed, 1 Dec 2021 21:56:10 +0330 Subject: [PATCH 15/16] #250 styling audio-player --- GanjooRazor/wwwroot/css/p8.css | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/GanjooRazor/wwwroot/css/p8.css b/GanjooRazor/wwwroot/css/p8.css index 4f54d3c2..726e2741 100644 --- a/GanjooRazor/wwwroot/css/p8.css +++ b/GanjooRazor/wwwroot/css/p8.css @@ -1124,8 +1124,14 @@ ol { padding-right: 50px; } -.audio-player{ - +.audio-player { + margin: 20px auto 6px; + display: block; + background: transparent url('/image/cbk.jpg') top center repeat scroll; + padding: 3px; + clear: both; + border: 2px solid #300; + border-radius: 20px; } .recitaion-info{ From 9a3f6179ee2b2edd4b0786f7cc0861fd8ac006e9 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Wed, 1 Dec 2021 22:16:40 +0330 Subject: [PATCH 16/16] #250 moving recitations block out of poem block --- GanjooRazor/Pages/_GanjoorPagePartial.cshtml | 78 +++++++++++++------- GanjooRazor/wwwroot/css/p8.css | 14 +--- 2 files changed, 55 insertions(+), 37 deletions(-) diff --git a/GanjooRazor/Pages/_GanjoorPagePartial.cshtml b/GanjooRazor/Pages/_GanjoorPagePartial.cshtml index f45be562..c0a22fcc 100644 --- a/GanjooRazor/Pages/_GanjoorPagePartial.cshtml +++ b/GanjooRazor/Pages/_GanjoorPagePartial.cshtml @@ -136,7 +136,9 @@ @@ -151,7 +153,9 @@ @{ foreach (var gran in Model.GanjoorPage.PoetOrCat.Cat.Ancestors) { - @Html.Raw(gran.Title) » + @Html.Raw(gran.Title) + + » } @if (!Model.IsPoemPage && !Model.IsCatPage && !Model.IsPoetPage) @@ -168,7 +172,9 @@ { @if (Model.IsPoemPage) { - @Html.Raw(Model.GanjoorPage.PoetOrCat.Cat.Title) » + @Html.Raw(Model.GanjoorPage.PoetOrCat.Cat.Title) + + »

@Html.Raw(Model.GanjoorPage.Poem.Title) @@ -191,15 +197,7 @@ @Html.Raw(Model.GanjoorPage.HtmlText) } - @{ - if (Model.IsPoemPage) - { - if (Model.GanjoorPage.Poem.Recitations.Length > 0) - { - - } - } - } + @{ if (Model.IsCatPage) { @@ -209,13 +207,17 @@ @@ -231,23 +233,31 @@ @@ -256,7 +266,6 @@ if (Model.GanjoorPage.Poem.Category.Cat.Previous != null)
-

mouse با دو بار کلیک روی واژه‌ها یا انتخاب متن و کلیک روی آنها می‌توانید آنها را در لغتنامهٔ دهخدا جستجو کنید. @@ -353,6 +362,21 @@ if (Model.GanjoorPage.Poem.Category.Cat.Previous != null) برای ویرایش و بهبود متن با نام کاربری خود وارد شوید } + @{ + if (Model.IsPoemPage) + { + if (Model.GanjoorPage.Poem.Recitations.Length > 0) + { +

+ } + } + } + @if (Model.GanjoorPage.Poem.Top6RelatedPoems.Length > 0) {