diff --git a/src/components/Ayah/index.js b/src/components/Ayah/index.js index 3e9649dfc..68885911f 100644 --- a/src/components/Ayah/index.js +++ b/src/components/Ayah/index.js @@ -5,6 +5,7 @@ import { Element } from 'react-scroll'; import { ayahType, matchType } from 'types'; import Copy from 'components/Copy'; import LocaleFormattedMessage from 'components/LocaleFormattedMessage'; +import Word from 'components/Word'; import debug from 'helpers/debug'; @@ -12,14 +13,6 @@ import bindTooltip from 'utils/bindTooltip'; const styles = require('./style.scss'); -/* eslint-disable no-unused-vars */ -const CHAR_TYPE_WORD = 1; -const CHAR_TYPE_END = 2; -const CHAR_TYPE_PAUSE = 3; -const CHAR_TYPE_RUB = 4; -const CHAR_TYPE_SAJDAH = 5; -/* eslint-enable no-unused-vars */ - export default class Ayah extends Component { static propTypes = { isSearched: PropTypes.bool, @@ -106,8 +99,8 @@ export default class Ayah extends Component {

{content.name || content.resource.name}

@@ -155,63 +148,19 @@ export default class Ayah extends Component { } renderText() { - const { ayah, audioActions, tooltip, isSearched } = this.props; - - if (!ayah.words[0].code) { - return false; - } - - // position is important as it will differentiate between words and symbols, see 2:25:13 - let position = -1; - const text = ayah.words.map((word, index) => { - let id = null; - const isLast = ayah.words.length === index + 1; - const className = `${word.className} ${word.highlight ? word.highlight : ''}`; - - if (word.charTypeId === CHAR_TYPE_WORD) { - position += 1; - id = `word-${word.ayahKey.replace(/:/, '-')}-${position}`; - } else { - id = `${word.className}-${word.codeDec}`; // just don't include id - } - - if (word.translation || word.transliteration) { - const tooltipContent = word[tooltip]; - - return ( - - !isSearched && - audioActions.setCurrentWord && - audioActions.setCurrentWord(event.target.dataset.key) - } - data-key={`${word.ayahKey}:${position}`} - className={`${className}`} - title={tooltipContent} - dangerouslySetInnerHTML={{ __html: word.code }} - /> - ); - } - const label = isLast ? { title: `Verse ${ayah.ayahNum}` } : {}; - return ( - - !isSearched && - audioActions.setCurrentWord && - audioActions.setCurrentWord(event.target.dataset.key) - } - data-key={`${word.ayahKey}:${position}`} - rel="tooltip" - className={`${className} ${isLast} pointer`} - key={word.code} - dangerouslySetInnerHTML={{ __html: word.code }} - {...label} + const { ayah, tooltip, currentAyah, isPlaying, audioActions, isSearched} = this.props; + + const text = ayah.words.map(word => { + return( + - ); + ) }); return ( diff --git a/src/components/Line/index.js b/src/components/Line/index.js index 1a92cf411..372e1fc71 100644 --- a/src/components/Line/index.js +++ b/src/components/Line/index.js @@ -2,6 +2,7 @@ import React, { PropTypes } from 'react'; import debug from 'helpers/debug'; import { wordType } from 'types'; +import Word from 'components/Word'; const styles = require('../Ayah/style.scss'); @@ -9,54 +10,29 @@ export default class Line extends React.Component { static propTypes = { line: PropTypes.arrayOf(wordType).isRequired, tooltip: PropTypes.string, - currentAyah: PropTypes.string.isRequired + currentAyah: PropTypes.string.isRequired, + audioActions: PropTypes.object.isRequired, + currentWord: PropTypes.any, + isPlaying: PropTypes.bool }; shouldComponentUpdate(nextProps) { const conditions = [ this.props.currentAyah !== nextProps.currentAyah, - this.props.line !== nextProps.line + this.props.line !== nextProps.line, + this.props.isPlaying !== nextProps.isPlaying ]; return conditions.some(condition => condition); } renderText() { - const { line, tooltip, currentAyah } = this.props; - - if (!line[0].code) { // TODO shouldn't be possible, remove this clause - return false; - } - - const text = line.map((word) => { - const highlight = currentAyah === word.ayahKey ? 'highlight' : ''; - - if (word.translation) { - const tooltipContent = word[tooltip]; - - return ( - - ); - } + const { tooltip, currentAyah, audioActions, isPlaying, line } = this.props; + const text = line.map(word => { return ( - - ); + + ) }); return ( @@ -76,7 +52,7 @@ export default class Line extends React.Component { return (
-
+
{this.renderText()}
diff --git a/src/components/Word/index.js b/src/components/Word/index.js new file mode 100644 index 000000000..b5cb53bc0 --- /dev/null +++ b/src/components/Word/index.js @@ -0,0 +1,74 @@ +import React, { PropTypes } from 'react'; + +const styles = require('../Ayah/style.scss'); + +/* eslint-disable no-unused-vars */ +const CHAR_TYPE_WORD = 1; +const CHAR_TYPE_END = 2; +const CHAR_TYPE_PAUSE = 3; +const CHAR_TYPE_RUB = 4; +const CHAR_TYPE_SAJDAH = 5; +/* eslint-enable no-unused-vars */ + +export default class Line extends React.Component { + static propTypes = { + word: PropTypes.object.isRequired, + tooltip: PropTypes.string, + audioActions: PropTypes.object.isRequired, + word: PropTypes.object.isRequired, + currentAyah: PropTypes.object.isRequired, + isPlaying: PropTypes.bool, + isSearched: PropTypes.bool + }; + + buildTooltip(word, tooltip){ + let title; + if (!word.wordId && word.charTypeId == CHAR_TYPE_END) { + title = `Verse ${word.ayahKey.split(':')[1]}`; + } else { + title = word[tooltip]; + } + return title; + } + + handleWordClick(word){ + const { currentAyah, audioActions, isPlaying, isSearched } = this.props; + if(isSearched) return; + + if(currentAyah == word.ayahKey && isPlaying) { + audioActions.setCurrentWord(word.dataset.key)
; + } else { + audioActions.pause(); + audioActions.setAyah(word.dataset.ayah); + audioActions.playCurrentWord(word.dataset.key); + } + } + + render() { + const { tooltip, word, currentAyah, isPlaying } = this.props; + + let id = null; + const position = word.position - 1; + const highlight = currentAyah == word.ayahKey && isPlaying ? 'highlight' : ''; + const className = `${word.className} ${highlight} ${word.highlight ? word.highlight : ''}`; + + if (word.charTypeId === CHAR_TYPE_WORD) { + id = `word-${word.ayahKey.replace(/:/, '-')}-${position}`; + } + + return ( + this.handleWordClick(event.target)} + data-key={`${word.ayahKey}:${position}`} + data-ayah={word.ayahKey} + className={`${className} pointer`} + title={this.buildTooltip(word, tooltip)} + dangerouslySetInnerHTML={{__html: word.code}} + /> + ); + } + +} diff --git a/src/containers/Surah/index.js b/src/containers/Surah/index.js index eb3a20f8b..b774e3c8c 100644 --- a/src/containers/Surah/index.js +++ b/src/containers/Surah/index.js @@ -110,7 +110,7 @@ class Surah extends Component { this.props.isLoaded !== nextProps.isLoaded, this.props.options !== nextProps.options, this.props.currentAyah !== nextProps.currentAyah, - this.props.isPlaying !== nextProps.isPlaying + this.props.isPlaying !== nextProps.isPlaying, ]; return conditions.some(condition => condition); @@ -301,6 +301,7 @@ class Surah extends Component { return Object.values(ayahs).map(ayah => ( { @@ -325,12 +326,29 @@ class Surah extends Component { if (index + 1 !== keys.length && pageNum !== nextNum.split('-')[0]) { return [ - , + , ]; } - return ; + return ( + + ) + }); } @@ -464,7 +482,7 @@ const AsyncSurah = asyncConnect([ function mapStateToProps(state, ownProps) { const surahId = parseInt(ownProps.params.surahId, 10); const surah: Object = state.surahs.entities[surahId]; - const ayahs: ?Object = state.ayahs.entities[surahId]; + const ayahs: Object = state.ayahs.entities[surahId]; const ayahArray = ayahs ? Object.keys(ayahs).map(key => parseInt(key.split(':')[1], 10)) : []; const ayahIds = new Set(ayahArray); const lastAyahInArray = ayahArray.slice(-1)[0]; diff --git a/src/redux/actions/audioplayer.js b/src/redux/actions/audioplayer.js index 10b46383e..354f1b2ad 100644 --- a/src/redux/actions/audioplayer.js +++ b/src/redux/actions/audioplayer.js @@ -2,6 +2,7 @@ import { SET_USER_AGENT, SET_CURRENT_FILE, SET_CURRENT_WORD, + PLAY_CURRENT_WORD, PLAY, PAUSE, NEXT, @@ -33,6 +34,13 @@ export function setCurrentWord(word) { }; } +export function playCurrentWord(word) { + return { + type: PLAY_CURRENT_WORD, + word + }; +} + export function play() { return { type: PLAY diff --git a/src/redux/constants/audioplayer.js b/src/redux/constants/audioplayer.js index e0d43d7a8..e37fb38f3 100644 --- a/src/redux/constants/audioplayer.js +++ b/src/redux/constants/audioplayer.js @@ -1,6 +1,7 @@ export const SET_USER_AGENT = '@@quran/audioplayer/SET_USER_AGENT'; export const SET_CURRENT_FILE = '@@quran/audioplayer/SET_CURRENT_FILE'; export const SET_CURRENT_WORD = '@@quran/audioplayer/SET_CURRENT_WORD'; +export const PLAY_CURRENT_WORD = '@@quran/audioplayer/PLAY_CURRENT_WORD'; export const PLAY = '@@quran/audioplayer/PLAY'; export const PAUSE = '@@quran/audioplayer/PAUSE'; export const NEXT = '@@quran/audioplayer/NEXT'; @@ -10,3 +11,4 @@ export const SET_REPEAT = '@@quran/audioplayer/SET_REPEAT'; export const TOGGLE_SCROLL = '@@quran/audioplayer/TOGGLE_SCROLL'; export const BUILD_ON_CLIENT = '@@quran/audioplayer/BUILD_ON_CLIENT'; export const UPDATE = '@@quran/audioplayer/UPDATE'; + diff --git a/src/redux/modules/audioplayer.js b/src/redux/modules/audioplayer.js index f8082cc17..f79017ef2 100644 --- a/src/redux/modules/audioplayer.js +++ b/src/redux/modules/audioplayer.js @@ -7,6 +7,7 @@ import { SET_USER_AGENT, SET_CURRENT_FILE, SET_CURRENT_WORD, + PLAY_CURRENT_WORD, PLAY, PAUSE, NEXT, @@ -267,6 +268,29 @@ export default function reducer(state = initialState, action = {}) { } }; } + case PLAY_CURRENT_WORD: { + if (!action.word) return state; + + const [surahId, ayahNum, word] = action.word.split(':'); + const nextId = `${surahId}:${ayahNum}`; + const currentFile = state.files[surahId][nextId]; + + if (!state.segments[surahId][nextId].words[word]) return state; + + const currentTime = state.segments[surahId][nextId].words[word].startTime; + const endTime = state.segments[surahId][nextId].words[word].endTime; + currentFile.currentTime = currentTime; + + const int = setInterval(function() { + if (currentFile.currentTime > endTime) { + currentFile.pause(); + clearInterval(int); + } + }, 10); + currentFile.play(); + + return state; + } case SET_CURRENT_AYAH: { return { ...state,