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

Highlight word in reading mode as well #556

Merged
merged 17 commits into from
Jan 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 15 additions & 66 deletions src/components/Ayah/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,14 @@ 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';

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,
Expand Down Expand Up @@ -106,8 +99,8 @@ export default class Ayah extends Component {
<h4 className="montserrat">{content.name || content.resource.name}</h4>
<h2 className={`${isArabic ? 'text-right' : 'text-left'} text-translation times-new`}>
<small
dangerouslySetInnerHTML={{ __html: content.text }}
className={`${styles[lang] || 'times-new'}`}
dangerouslySetInnerHTML={{__html: content.text}}
className={`${lang || 'times-new'}`}
/>
</h2>
</div>
Expand Down Expand Up @@ -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 (
<b // eslint-disable-line
key={word.code}
id={id}
rel="tooltip"
onClick={event =>
!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 (
<b // eslint-disable-line
id={id}
onClick={event =>
!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(
<Word
word={word}
currentAyah={currentAyah}
tooltip={tooltip}
isPlaying={isPlaying}
audioActions={audioActions}
isSearched={isSearched}
/>
);
)
});

return (
Expand Down
48 changes: 12 additions & 36 deletions src/components/Line/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,37 @@ 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');

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 (
<b
key={`${word.pageNum}${word.lineNum}${word.position}${word.code}`}
className={`${word.className} ${styles.Tooltip} ${highlight}`}
data-ayah={word.ayahKey}
data-line={word.lineNun}
data-page={word.pageNum}
data-position={word.position}
aria-label={tooltipContent}
dangerouslySetInnerHTML={{ __html: word.code }}
/>
);
}
const { tooltip, currentAyah, audioActions, isPlaying, line } = this.props;

const text = line.map(word => {
return (
<b
className={`${word.className} ${highlight} pointer`}
key={`${word.pageNum}${word.lineNum}${word.position}${word.code}`}
data-line={word.lineNum}
data-page={word.pageNum}
dangerouslySetInnerHTML={{ __html: word.code }}
/>
);
<Word word={word} currentAyah={currentAyah} tooltip={tooltip} isPlaying={isPlaying} audioActions={audioActions}/>
)
});

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

return (
<div className={`row ${styles.font} text-justify text-arabic`}>
<div className="col-md-12 line-container">
<div className="col-md-12 line-container" name={`ayah:${line[0].ayahKey}`}>
{this.renderText()}
</div>
</div>
Expand Down
74 changes: 74 additions & 0 deletions src/components/Word/index.js
Original file line number Diff line number Diff line change
@@ -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 (
<b
key={word.code}
id={id}
rel="tooltip"
onClick={(event) => 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}}
/>
);
}

}
28 changes: 23 additions & 5 deletions src/containers/Surah/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -301,6 +301,7 @@ class Surah extends Component {
return Object.values(ayahs).map(ayah => (
<Ayah
ayah={ayah}
currentAyah={currentAyah}
isCurrentAyah={isPlaying && ayah.ayahKey === currentAyah}
bookmarked={!!bookmarks[ayah.ayahKey]}
tooltip={options.tooltip}
Expand All @@ -315,7 +316,7 @@ class Surah extends Component {
}

renderLines() {
const { lines, options, currentAyah } = this.props;
const { lines, options, currentAyah, isPlaying, actions } = this.props;
const keys = Object.keys(lines);

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

if (index + 1 !== keys.length && pageNum !== nextNum.split('-')[0]) {
return [
<Line line={line} key={lineNum} currentAyah={currentAyah} tooltip={options.tooltip} />,
<Line
line={line}
key={lineNum}
currentAyah={currentAyah}
tooltip={options.tooltip}
audioActions={actions.audio}
isPlaying={isPlaying}
/>,
<PageBreak pageNum={parseInt(pageNum, 10) + 1} />
];
}

return <Line line={line} key={lineNum} currentAyah={currentAyah} tooltip={options.tooltip} />;
return (
<Line
line={line}
key={lineNum}
currentAyah={currentAyah}
tooltip={options.tooltip}
audioActions={actions.audio}
isPlaying={isPlaying}
/>
)

});
}

Expand Down Expand Up @@ -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];
Expand Down
8 changes: 8 additions & 0 deletions src/redux/actions/audioplayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
SET_USER_AGENT,
SET_CURRENT_FILE,
SET_CURRENT_WORD,
PLAY_CURRENT_WORD,
PLAY,
PAUSE,
NEXT,
Expand Down Expand Up @@ -33,6 +34,13 @@ export function setCurrentWord(word) {
};
}

export function playCurrentWord(word) {
return {
type: PLAY_CURRENT_WORD,
word
};
}

export function play() {
return {
type: PLAY
Expand Down
2 changes: 2 additions & 0 deletions src/redux/constants/audioplayer.js
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';

Loading