Skip to content
This repository was archived by the owner on Jun 28, 2021. It is now read-only.

Commit fa288e9

Browse files
naveed-ahmadmmahalwy
authored andcommitted
Highlight word in reading mode as well (#556)
* highlight current word is readmode as well * added word by word play! buggy but working * fixed word position in reading modet * DRYed word render and added tooltip in reading mode * fixed trans language class * refactoring word rendering * refactored word rendering * removed duplicated code * removed debuging * adding auto scrolling in reading mode
1 parent 28b7eaa commit fa288e9

File tree

7 files changed

+158
-107
lines changed

7 files changed

+158
-107
lines changed

src/components/Ayah/index.js

Lines changed: 15 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,14 @@ import { Element } from 'react-scroll';
55
import { ayahType, matchType } from 'types';
66
import Copy from 'components/Copy';
77
import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
8+
import Word from 'components/Word';
89

910
import debug from 'helpers/debug';
1011

1112
import bindTooltip from 'utils/bindTooltip';
1213

1314
const styles = require('./style.scss');
1415

15-
/* eslint-disable no-unused-vars */
16-
const CHAR_TYPE_WORD = 1;
17-
const CHAR_TYPE_END = 2;
18-
const CHAR_TYPE_PAUSE = 3;
19-
const CHAR_TYPE_RUB = 4;
20-
const CHAR_TYPE_SAJDAH = 5;
21-
/* eslint-enable no-unused-vars */
22-
2316
export default class Ayah extends Component {
2417
static propTypes = {
2518
isSearched: PropTypes.bool,
@@ -106,8 +99,8 @@ export default class Ayah extends Component {
10699
<h4 className="montserrat">{content.name || content.resource.name}</h4>
107100
<h2 className={`${isArabic ? 'text-right' : 'text-left'} text-translation times-new`}>
108101
<small
109-
dangerouslySetInnerHTML={{ __html: content.text }}
110-
className={`${styles[lang] || 'times-new'}`}
102+
dangerouslySetInnerHTML={{__html: content.text}}
103+
className={`${lang || 'times-new'}`}
111104
/>
112105
</h2>
113106
</div>
@@ -155,63 +148,19 @@ export default class Ayah extends Component {
155148
}
156149

157150
renderText() {
158-
const { ayah, audioActions, tooltip, isSearched } = this.props;
159-
160-
if (!ayah.words[0].code) {
161-
return false;
162-
}
163-
164-
// position is important as it will differentiate between words and symbols, see 2:25:13
165-
let position = -1;
166-
const text = ayah.words.map((word, index) => {
167-
let id = null;
168-
const isLast = ayah.words.length === index + 1;
169-
const className = `${word.className} ${word.highlight ? word.highlight : ''}`;
170-
171-
if (word.charTypeId === CHAR_TYPE_WORD) {
172-
position += 1;
173-
id = `word-${word.ayahKey.replace(/:/, '-')}-${position}`;
174-
} else {
175-
id = `${word.className}-${word.codeDec}`; // just don't include id
176-
}
177-
178-
if (word.translation || word.transliteration) {
179-
const tooltipContent = word[tooltip];
180-
181-
return (
182-
<b // eslint-disable-line
183-
key={word.code}
184-
id={id}
185-
rel="tooltip"
186-
onClick={event =>
187-
!isSearched &&
188-
audioActions.setCurrentWord &&
189-
audioActions.setCurrentWord(event.target.dataset.key)
190-
}
191-
data-key={`${word.ayahKey}:${position}`}
192-
className={`${className}`}
193-
title={tooltipContent}
194-
dangerouslySetInnerHTML={{ __html: word.code }}
195-
/>
196-
);
197-
}
198-
const label = isLast ? { title: `Verse ${ayah.ayahNum}` } : {};
199-
return (
200-
<b // eslint-disable-line
201-
id={id}
202-
onClick={event =>
203-
!isSearched &&
204-
audioActions.setCurrentWord &&
205-
audioActions.setCurrentWord(event.target.dataset.key)
206-
}
207-
data-key={`${word.ayahKey}:${position}`}
208-
rel="tooltip"
209-
className={`${className} ${isLast} pointer`}
210-
key={word.code}
211-
dangerouslySetInnerHTML={{ __html: word.code }}
212-
{...label}
151+
const { ayah, tooltip, currentAyah, isPlaying, audioActions, isSearched} = this.props;
152+
153+
const text = ayah.words.map(word => {
154+
return(
155+
<Word
156+
word={word}
157+
currentAyah={currentAyah}
158+
tooltip={tooltip}
159+
isPlaying={isPlaying}
160+
audioActions={audioActions}
161+
isSearched={isSearched}
213162
/>
214-
);
163+
)
215164
});
216165

217166
return (

src/components/Line/index.js

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,37 @@ import React, { PropTypes } from 'react';
22
import debug from 'helpers/debug';
33

44
import { wordType } from 'types';
5+
import Word from 'components/Word';
56

67
const styles = require('../Ayah/style.scss');
78

89
export default class Line extends React.Component {
910
static propTypes = {
1011
line: PropTypes.arrayOf(wordType).isRequired,
1112
tooltip: PropTypes.string,
12-
currentAyah: PropTypes.string.isRequired
13+
currentAyah: PropTypes.string.isRequired,
14+
audioActions: PropTypes.object.isRequired,
15+
currentWord: PropTypes.any,
16+
isPlaying: PropTypes.bool
1317
};
1418

1519
shouldComponentUpdate(nextProps) {
1620
const conditions = [
1721
this.props.currentAyah !== nextProps.currentAyah,
18-
this.props.line !== nextProps.line
22+
this.props.line !== nextProps.line,
23+
this.props.isPlaying !== nextProps.isPlaying
1924
];
2025

2126
return conditions.some(condition => condition);
2227
}
2328

2429
renderText() {
25-
const { line, tooltip, currentAyah } = this.props;
26-
27-
if (!line[0].code) { // TODO shouldn't be possible, remove this clause
28-
return false;
29-
}
30-
31-
const text = line.map((word) => {
32-
const highlight = currentAyah === word.ayahKey ? 'highlight' : '';
33-
34-
if (word.translation) {
35-
const tooltipContent = word[tooltip];
36-
37-
return (
38-
<b
39-
key={`${word.pageNum}${word.lineNum}${word.position}${word.code}`}
40-
className={`${word.className} ${styles.Tooltip} ${highlight}`}
41-
data-ayah={word.ayahKey}
42-
data-line={word.lineNun}
43-
data-page={word.pageNum}
44-
data-position={word.position}
45-
aria-label={tooltipContent}
46-
dangerouslySetInnerHTML={{ __html: word.code }}
47-
/>
48-
);
49-
}
30+
const { tooltip, currentAyah, audioActions, isPlaying, line } = this.props;
5031

32+
const text = line.map(word => {
5133
return (
52-
<b
53-
className={`${word.className} ${highlight} pointer`}
54-
key={`${word.pageNum}${word.lineNum}${word.position}${word.code}`}
55-
data-line={word.lineNum}
56-
data-page={word.pageNum}
57-
dangerouslySetInnerHTML={{ __html: word.code }}
58-
/>
59-
);
34+
<Word word={word} currentAyah={currentAyah} tooltip={tooltip} isPlaying={isPlaying} audioActions={audioActions}/>
35+
)
6036
});
6137

6238
return (
@@ -76,7 +52,7 @@ export default class Line extends React.Component {
7652

7753
return (
7854
<div className={`row ${styles.font} text-justify text-arabic`}>
79-
<div className="col-md-12 line-container">
55+
<div className="col-md-12 line-container" name={`ayah:${line[0].ayahKey}`}>
8056
{this.renderText()}
8157
</div>
8258
</div>

src/components/Word/index.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import React, { PropTypes } from 'react';
2+
3+
const styles = require('../Ayah/style.scss');
4+
5+
/* eslint-disable no-unused-vars */
6+
const CHAR_TYPE_WORD = 1;
7+
const CHAR_TYPE_END = 2;
8+
const CHAR_TYPE_PAUSE = 3;
9+
const CHAR_TYPE_RUB = 4;
10+
const CHAR_TYPE_SAJDAH = 5;
11+
/* eslint-enable no-unused-vars */
12+
13+
export default class Line extends React.Component {
14+
static propTypes = {
15+
word: PropTypes.object.isRequired,
16+
tooltip: PropTypes.string,
17+
audioActions: PropTypes.object.isRequired,
18+
word: PropTypes.object.isRequired,
19+
currentAyah: PropTypes.object.isRequired,
20+
isPlaying: PropTypes.bool,
21+
isSearched: PropTypes.bool
22+
};
23+
24+
buildTooltip(word, tooltip){
25+
let title;
26+
if (!word.wordId && word.charTypeId == CHAR_TYPE_END) {
27+
title = `Verse ${word.ayahKey.split(':')[1]}`;
28+
} else {
29+
title = word[tooltip];
30+
}
31+
return title;
32+
}
33+
34+
handleWordClick(word){
35+
const { currentAyah, audioActions, isPlaying, isSearched } = this.props;
36+
if(isSearched) return;
37+
38+
if(currentAyah == word.ayahKey && isPlaying) {
39+
audioActions.setCurrentWord(word.dataset.key);
40+
} else {
41+
audioActions.pause();
42+
audioActions.setAyah(word.dataset.ayah);
43+
audioActions.playCurrentWord(word.dataset.key);
44+
}
45+
}
46+
47+
render() {
48+
const { tooltip, word, currentAyah, isPlaying } = this.props;
49+
50+
let id = null;
51+
const position = word.position - 1;
52+
const highlight = currentAyah == word.ayahKey && isPlaying ? 'highlight' : '';
53+
const className = `${word.className} ${highlight} ${word.highlight ? word.highlight : ''}`;
54+
55+
if (word.charTypeId === CHAR_TYPE_WORD) {
56+
id = `word-${word.ayahKey.replace(/:/, '-')}-${position}`;
57+
}
58+
59+
return (
60+
<b
61+
key={word.code}
62+
id={id}
63+
rel="tooltip"
64+
onClick={(event) => this.handleWordClick(event.target)}
65+
data-key={`${word.ayahKey}:${position}`}
66+
data-ayah={word.ayahKey}
67+
className={`${className} pointer`}
68+
title={this.buildTooltip(word, tooltip)}
69+
dangerouslySetInnerHTML={{__html: word.code}}
70+
/>
71+
);
72+
}
73+
74+
}

src/containers/Surah/index.js

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class Surah extends Component {
110110
this.props.isLoaded !== nextProps.isLoaded,
111111
this.props.options !== nextProps.options,
112112
this.props.currentAyah !== nextProps.currentAyah,
113-
this.props.isPlaying !== nextProps.isPlaying
113+
this.props.isPlaying !== nextProps.isPlaying,
114114
];
115115

116116
return conditions.some(condition => condition);
@@ -301,6 +301,7 @@ class Surah extends Component {
301301
return Object.values(ayahs).map(ayah => (
302302
<Ayah
303303
ayah={ayah}
304+
currentAyah={currentAyah}
304305
isCurrentAyah={isPlaying && ayah.ayahKey === currentAyah}
305306
bookmarked={!!bookmarks[ayah.ayahKey]}
306307
tooltip={options.tooltip}
@@ -315,7 +316,7 @@ class Surah extends Component {
315316
}
316317

317318
renderLines() {
318-
const { lines, options, currentAyah } = this.props;
319+
const { lines, options, currentAyah, isPlaying, actions } = this.props;
319320
const keys = Object.keys(lines);
320321

321322
return keys.map((lineNum, index) => {
@@ -325,12 +326,29 @@ class Surah extends Component {
325326

326327
if (index + 1 !== keys.length && pageNum !== nextNum.split('-')[0]) {
327328
return [
328-
<Line line={line} key={lineNum} currentAyah={currentAyah} tooltip={options.tooltip} />,
329+
<Line
330+
line={line}
331+
key={lineNum}
332+
currentAyah={currentAyah}
333+
tooltip={options.tooltip}
334+
audioActions={actions.audio}
335+
isPlaying={isPlaying}
336+
/>,
329337
<PageBreak pageNum={parseInt(pageNum, 10) + 1} />
330338
];
331339
}
332340

333-
return <Line line={line} key={lineNum} currentAyah={currentAyah} tooltip={options.tooltip} />;
341+
return (
342+
<Line
343+
line={line}
344+
key={lineNum}
345+
currentAyah={currentAyah}
346+
tooltip={options.tooltip}
347+
audioActions={actions.audio}
348+
isPlaying={isPlaying}
349+
/>
350+
)
351+
334352
});
335353
}
336354

@@ -464,7 +482,7 @@ const AsyncSurah = asyncConnect([
464482
function mapStateToProps(state, ownProps) {
465483
const surahId = parseInt(ownProps.params.surahId, 10);
466484
const surah: Object = state.surahs.entities[surahId];
467-
const ayahs: ?Object = state.ayahs.entities[surahId];
485+
const ayahs: Object = state.ayahs.entities[surahId];
468486
const ayahArray = ayahs ? Object.keys(ayahs).map(key => parseInt(key.split(':')[1], 10)) : [];
469487
const ayahIds = new Set(ayahArray);
470488
const lastAyahInArray = ayahArray.slice(-1)[0];

src/redux/actions/audioplayer.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
SET_USER_AGENT,
33
SET_CURRENT_FILE,
44
SET_CURRENT_WORD,
5+
PLAY_CURRENT_WORD,
56
PLAY,
67
PAUSE,
78
NEXT,
@@ -33,6 +34,13 @@ export function setCurrentWord(word) {
3334
};
3435
}
3536

37+
export function playCurrentWord(word) {
38+
return {
39+
type: PLAY_CURRENT_WORD,
40+
word
41+
};
42+
}
43+
3644
export function play() {
3745
return {
3846
type: PLAY

src/redux/constants/audioplayer.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export const SET_USER_AGENT = '@@quran/audioplayer/SET_USER_AGENT';
22
export const SET_CURRENT_FILE = '@@quran/audioplayer/SET_CURRENT_FILE';
33
export const SET_CURRENT_WORD = '@@quran/audioplayer/SET_CURRENT_WORD';
4+
export const PLAY_CURRENT_WORD = '@@quran/audioplayer/PLAY_CURRENT_WORD';
45
export const PLAY = '@@quran/audioplayer/PLAY';
56
export const PAUSE = '@@quran/audioplayer/PAUSE';
67
export const NEXT = '@@quran/audioplayer/NEXT';
@@ -10,3 +11,4 @@ export const SET_REPEAT = '@@quran/audioplayer/SET_REPEAT';
1011
export const TOGGLE_SCROLL = '@@quran/audioplayer/TOGGLE_SCROLL';
1112
export const BUILD_ON_CLIENT = '@@quran/audioplayer/BUILD_ON_CLIENT';
1213
export const UPDATE = '@@quran/audioplayer/UPDATE';
14+

0 commit comments

Comments
 (0)