principles-ui-components
Version:
Supporting UI controller for Tizen TV web application, which developed base on React Framework.
1,038 lines (940 loc) • 42 kB
JavaScript
/**
* @author Song Zhang (song8.zhang@samsung.com) and Haipeng Zhang(hp.zhang@samsung.com)
* @fileoverview This module manages more fetch single list.
* @date 2017/07/18 (last modified date)
*
* Copyright 2017 by Samsung Electronics, Inc.,
*
* This software is the confidential and proprietary information
* of Samsung Electronics, Inc. ("Confidential Information"). You
* shall not disclose such Confidential Information and shall use
* it only in accordance with the terms of the license agreement
* you entered into with Samsung.
*/
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import Immutable, { List, Map } from 'immutable';
import { KEY, AnimationEffect, TTSTYPE } from './common/CommonDefine';
import CommonList from './CommonList';
import ScrollBar from './ScrollBar';
import TTS from './common/TTS';
import ScrollText from './common/ScrollText';
export default class SingleLineList extends Component {
constructor(props) {
super(props);
this.handleKey = this.handleKey.bind(this);
const { morefetchEnable, width, transLeft, details, gap, focusScale, initFocus, title } = this.props;
this.focus = 'LIST1';
this.hasFocus = initFocus;
this.pageData = []; // three page Data start and end
this.scaleW = details[0].OSD.layout.w * (focusScale - 1); // one scale length 285*0.2 = 57
this.halfScaleW = this.scaleW / 2;
this.listShowNum = Math.floor((width - transLeft - this.scaleW) / (details[0].OSD.layout.w + gap));
this.listNum = this.listShowNum + 2; // for edge issue
console.log(`SingleLineList constructor listNum ${this.listNum}`);
this.detailslen = details.length;
this.commonList1Data = [];
this.lastFocusOutPos = 0;
this.titleAni = '';
if (this.detailslen <= this.listNum * 3 || !morefetchEnable) { // If not exceed 3 pages, no need to use morefetch
console.log(`SingleLineList constructor listNum ${this.listNum}, detailslen ${this.detailslen}, no need to use morefetch!`);
this.pageData.push({
start: 0,
end: this.detailslen - 1,
});
this.state = {
titleAni: '',
};
return true;
}
this.showData = []; // show data of the list
this.hScrollPx = 0;
this.hList1ScrollPx = transLeft;
this.hList2ScrollPx = transLeft; // 80 285*8 = 1710 2*8 = 12 285*0.2 = 57
this.hList2ScrollPx += details[0].OSD.layout.w * this.listNum;
this.hList2ScrollPx += gap * this.listNum;
this.hList2ScrollPx += this.scaleW;
this.hList3ScrollPx = this.hList2ScrollPx; // 80 285*6 = 1710 2*6 = 12 285*0.2 = 57 285*6 = 1710 2*6 = 12
this.hList3ScrollPx += details[0].OSD.layout.w * this.listNum;
this.hList3ScrollPx += gap * this.listNum;
this.hPagePx = this.hList3ScrollPx; // three page total length 3581 285*6 = 1710 2*6 = 12 -80
this.hPagePx += details[0].OSD.layout.w * this.listNum;
this.hPagePx += gap * this.listNum;
this.hPagePx -= transLeft;
if (!this.hasFocus) {
this.hList2ScrollPx -= this.scaleW;
this.hList3ScrollPx -= this.scaleW;
}
this.hListPx = details[0].OSD.layout.w + gap; // one item move px
this.detailslen = details.length;
this.scrollBarTop = 0;
let i = 0;
for (i = 0; i < this.listShowNum; i++) {
this.showData.push({
pageIndex: 1,
listIndex: i,
});
}
this.pageData.push({
start: 0,
end: this.listNum - 1,
});
this.pageData.push({
start: this.listNum,
end: (this.listNum * 2) - 1,
});
this.pageData.push({
start: this.listNum * 2,
end: (this.listNum * 3) - 1,
});
this.commonList2Data = [];
this.commonList3Data = [];
this.transList1 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList2 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList3 = `all 0.3s ${AnimationEffect.Basic}`;
this.scrollHPercent = 0;
this.lastKey = 'keyup';
// title
if (this.hasFocus && title !== undefined && title !== null) {
this.titleAni = 'commonListFocusInAni';
}
this.state = {
scrollHPercent: 0, // Calculated when component mounted, because index is found by ref name, so it can only be calculated after component mounted.
hScrollPx: 0,
hList1ScrollPx: this.hList1ScrollPx,
hList2ScrollPx: this.hList2ScrollPx,
hList3ScrollPx: this.hList3ScrollPx,
transList1: `all 0.3s ${AnimationEffect.Basic}`,
transList2: `all 0.3s ${AnimationEffect.Basic}`,
transList3: `all 0.3s ${AnimationEffect.Basic}`,
titleAni: this.titleAni,
};
}
componentWillMount() {
const { details, title, focusScale } = this.props;
const halfScaleH = (details[0].OSD.layout.h * (focusScale - 1)) / 2;
if (title !== undefined && title !== null) {
this.style = document.createElement('style');
this.style.type = 'text/css';
const keyFrames = ` commonListFocusInAni
{
0% {transform: translateY(0px) translateZ(100px);}
50% {transform: translateY(-${title.t}px) translateZ(100px);}
100% {transform: translateY(-${halfScaleH}px) translateZ(100px);}
}
commonListFocusOutAni
{
0% {transform: translateY(-${halfScaleH}px) translateZ(100px);}
100% {transform: translateY(0px) translateZ(100px);}
}
commonListInitAni
{
0% {transform: translateY(0px) translateZ(100px);}
100% {transform: translateY(0px) translateZ(100px);}
}
`;
this.style.innerHTML = keyFrames;
document.getElementsByTagName('head')[0].appendChild(this.style);
}
}
componentDidMount() {
}
componentWillReceiveProps() {
}
shouldComponentUpdate(nextProps, nextState) {
const needUpdate = (JSON.stringify(nextProps) !== JSON.stringify(this.props) || JSON.stringify(nextState) !== JSON.stringify(this.state));
return needUpdate;
}
componentWillUpdate() {
}
componentDidUpdate() {
}
componentWillUnmount() {
this.removeStyleFromHeader();
}
getFocusIndex() {
const index = this.refs[this.focus].getFocusIndex();
const pageIndex = parseInt(this.focus.charAt(this.focus.length - 1), 10);
return this.pageData[pageIndex - 1].start + index;
}
getListData(commonListData, pageNo) {
const { details } = this.props;
let i = 0;
const start = this.pageData[pageNo].start;
const end = this.pageData[pageNo].end;
console.log(`SingleLineList pageData ${pageNo} start:${start}`);
console.log(`SingleLineList pageData ${pageNo} end:${end}`);
commonListData.splice(0, commonListData.length);
for (i = start; i <= end; i++) {
commonListData.push(details[i]);
}
}
/**
* get lastItem scroll width for the last item is not show all in screen
* @name getLastItemScrollPx
* @method
* @memberof
* @param
*/
getLastItemScrollPx() {
// 1920 - 80 - 57 = 1783 1783/287 = 6.212 1- 0.212 = 0.788 *287 = 226
const { transLeft, width, gap, details, transRight } = this.props;
let screenWidth = 0;
let screenItemsNumT = 0;
let screenItemsNum = 0;
let lastScrollPx = 0;
screenWidth = width - transLeft - this.scaleW;
screenItemsNumT = screenWidth / (details[0].OSD.layout.w + gap);
screenItemsNum = Math.floor(screenItemsNumT);
lastScrollPx = (1 - (screenItemsNumT - screenItemsNum)) * (details[0].OSD.layout.w + gap);
console.log(`[SingleLineList.js:getLastScrollPx] lastScrollPx = ${lastScrollPx}`);
return lastScrollPx + transRight;
}
removeStyleFromHeader() {
if (this.style) {
document.getElementsByTagName('head')[0].removeChild(this.style);
this.style = null;
}
}
keyFocusIn(position) {
if (this.hasFocus) {
console.error('[SingleLineList.js:keyFocusIn] List already have focus, doing nothing.');
return false;
}
const { details, gap, transLeft, title } = this.props;
this.hasFocus = true;
// title
if (title !== undefined && title !== null) {
this.titleAni = 'commonListFocusInAni';
}
if (position === null || position === undefined || position.x === 0) {
this.refs[this.focus].keyFocusInByIndex(this.lastFocusOutPos);
if (this.detailslen > this.listNum * 3 && this.props.morefetchEnable) { // If exceed 3 pages and use morefetch
this.moveListInOut(1);
const scroll = 'SCROLL';
this.refs[scroll].showBar();
if (this.props.ttsEnable) {
this.playTTS(TTSTYPE.LIST);
}
}
this.setState({
titleAni: this.titleAni,
});
return true;
}
if (this.detailslen > this.listNum * 3 && this.props.morefetchEnable) { // If exceed 3 pages and use morefetch
let i = 0;
let pageIndex;
let listIndex;
let posX = transLeft;
for (i = 0; i < this.listShowNum; i++) {
posX += (details[0].OSD.layout.w + gap);
if (posX > position.x) {
break;
}
}
if (i === this.listShowNum) {
// focus last one
pageIndex = this.showData[i - 1].pageIndex;
listIndex = this.showData[i - 1].listIndex;
this.focus = `LIST${pageIndex}`;
this.refs[this.focus].keyFocusInByIndex(listIndex);
} else {
pageIndex = this.showData[i].pageIndex;
listIndex = this.showData[i].listIndex;
this.focus = `LIST${pageIndex}`;
this.refs[this.focus].keyFocusInByIndex(listIndex);
}
this.moveListInOut(1);
const scroll = 'SCROLL';
this.refs[scroll].showBar();
if (this.props.ttsEnable) {
this.playTTS(TTSTYPE.LIST);
}
} else {
this.refs[this.focus].keyFocusIn(position);
}
this.setState({
titleAni: this.titleAni,
});
return true;
}
keyFocusOut() {
if (!this.hasFocus) {
console.error('[SingleLineList.js:keyFocusOut] List do not have focus, doing nothing.');
return false;
}
const { details, gap, transLeft, title } = this.props;
this.lastFocusOutPos = this.refs[this.focus].getFocusIndex();
const pageIndex = parseInt(this.focus.charAt(this.focus.length - 1), 10);
const listIndex = this.refs[this.focus].getFocusIndex();
const position = this.refs[this.focus].keyFocusOut();
this.hasFocus = false;
this.lastKey = 'keyup';
if (this.detailslen > this.listNum * 3 && this.props.morefetchEnable) { // If exceed 3 pages and use morefetch
this.moveListInOut(-1);
// for near focus rule
position.x = transLeft;
let i = 0;
for (i = 0; i < this.listShowNum; i++) {
if (this.showData[i].pageIndex === pageIndex && this.showData[i].listIndex === listIndex) {
position.x += (details[0].OSD.layout.w + gap) / 2;
break;
}
position.x += (details[0].OSD.layout.w + gap);
}
}
// title
if (title !== undefined && title !== null) {
this.titleAni = 'commonListFocusOutAni';
this.setState({
titleAni: this.titleAni,
});
this.titleAni = 'commonListInitAni';
this.setState({
titleAni: this.titleAni,
});
}
return position;
}
playTTS(type) {
if (type === TTSTYPE.LIST) {
this.TTSnode.playTTS();
} else if (type === TTSTYPE.ITEM) {
this.refs[this.focus].playTTS(TTSTYPE.ITEM);
}
}
moveListInOut(direct) {
if (direct !== 1 && direct !== -1) {
console.error('[SingleLineList.js:moveListInOut] direct is wrong, doing nothing.');
return false;
}
if (this.focus === 'LIST1') {
if (this.pageData[0].end !== this.detailslen - 1) {
this.hList2ScrollPx += this.scaleW * direct;
if (this.pageData[2].start > this.pageData[0].end) { // LIST3 is in the right of LIST1
this.hList3ScrollPx += this.scaleW * direct;
}
}
} else if (this.focus === 'LIST2') {
if (this.pageData[1].end !== this.detailslen - 1) {
this.hList3ScrollPx += this.scaleW * direct;
if (this.pageData[0].start > this.pageData[1].end) { // LIST1 is in the right of LIST2
this.hList1ScrollPx += this.scaleW * direct;
}
}
} else if (this.focus === 'LIST3') {
if (this.pageData[2].end !== this.detailslen - 1) {
this.hList1ScrollPx += this.scaleW * direct;
if (this.pageData[1].start > this.pageData[2].end) { // LIST2 is in the right of LIST3
this.hList2ScrollPx += this.scaleW * direct;
}
}
}
// last one
let i = 0;
for (i = 0; i < this.listShowNum; i++) {
if (this.pageData[this.showData[i].pageIndex - 1].start + this.showData[i].listIndex === this.detailslen - 1) {
this.hScrollPx -= this.scaleW * direct;
break;
}
}
this.setState({
hScrollPx: this.hScrollPx,
hList1ScrollPx: this.hList1ScrollPx,
hList2ScrollPx: this.hList2ScrollPx,
hList3ScrollPx: this.hList3ScrollPx,
transList1: `all 0.3s ${AnimationEffect.Basic}`,
transList2: `all 0.3s ${AnimationEffect.Basic}`,
transList3: `all 0.3s ${AnimationEffect.Basic}`,
});
return true;
}
moveList(lastPageIndex, curPageIndex) {
if (lastPageIndex === 2 && curPageIndex === 3) {
// move 1 list right
this.hList3ScrollPx -= this.scaleW;
if (this.pageData[curPageIndex - 1].end === this.detailslen - 1) {
this.transList1 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList2 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList3 = `all 0.3s ${AnimationEffect.Basic}`;
} else {
this.hList1ScrollPx += this.hPagePx;
this.pageData[0].start = this.pageData[2].end + 1;
this.pageData[0].end = this.pageData[2].end + this.listNum >= this.detailslen - 1 ? this.detailslen - 1 : this.pageData[2].end + this.listNum;
console.log(`SingleLineList pageData 0 start:${this.pageData[0].start}`);
console.log(`SingleLineList pageData 0 end:${this.pageData[0].end}`);
this.transList1 = `all 0s ${AnimationEffect.Basic}`;
this.transList2 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList3 = `all 0.3s ${AnimationEffect.Basic}`;
}
} else if (lastPageIndex === 3 && curPageIndex === 1) {
// move 2 list right
this.hList1ScrollPx -= this.scaleW;
if (this.pageData[curPageIndex - 1].end === this.detailslen - 1) {
this.transList1 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList2 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList3 = `all 0.3s ${AnimationEffect.Basic}`;
} else {
this.hList2ScrollPx += this.hPagePx;
this.pageData[1].start = this.pageData[0].end + 1;
this.pageData[1].end = this.pageData[0].end + this.listNum >= this.detailslen - 1 ? this.detailslen - 1 : this.pageData[0].end + this.listNum;
console.log(`SingleLineList pageData 1 start:${this.pageData[1].start}`);
console.log(`SingleLineList pageData 1 end:${this.pageData[1].end}`);
this.transList1 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList2 = `all 0s ${AnimationEffect.Basic}`;
this.transList3 = `all 0.3s ${AnimationEffect.Basic}`;
}
} else if (lastPageIndex === 1 && curPageIndex === 2) {
// move 3 list right
this.hList2ScrollPx -= this.scaleW;
if (this.pageData[0].start > 0 && this.pageData[curPageIndex - 1].end !== this.detailslen - 1) {
this.hList3ScrollPx += this.hPagePx;
this.pageData[2].start = this.pageData[1].end + 1;
this.pageData[2].end = this.pageData[1].end + this.listNum >= this.detailslen - 1 ? this.detailslen - 1 : this.pageData[1].end + this.listNum;
console.log(`SingleLineList pageData 2 start:${this.pageData[2].start}`);
console.log(`SingleLineList pageData 2 end:${this.pageData[2].end}`);
this.transList1 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList2 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList3 = `all 0s ${AnimationEffect.Basic}`;
} else {
this.transList1 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList2 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList3 = `all 0.3s ${AnimationEffect.Basic}`;
}
} else if (lastPageIndex === 3 && curPageIndex === 2) {
// move 1 list left
this.hList3ScrollPx += this.scaleW;
if (this.pageData[lastPageIndex - 1].end !== this.detailslen - 1) {
this.hList1ScrollPx -= this.hPagePx;
this.pageData[0].start = this.pageData[1].start - this.listNum;
this.pageData[0].end = this.pageData[1].start - 1;
console.log(`SingleLineList pageData 0 start:${this.pageData[0].start}`);
console.log(`SingleLineList pageData 0 end:${this.pageData[0].end}`);
this.transList1 = `all 0s ${AnimationEffect.Basic}`;
this.transList2 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList3 = `all 0.3s ${AnimationEffect.Basic}`;
} else {
this.transList1 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList2 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList3 = `all 0.3s ${AnimationEffect.Basic}`;
}
} else if (lastPageIndex === 1 && curPageIndex === 3) {
// move 2 list left
this.hList1ScrollPx += this.scaleW;
if (this.pageData[lastPageIndex - 1].end !== this.detailslen - 1) {
this.hList2ScrollPx -= this.hPagePx;
this.pageData[1].start = this.pageData[2].start - this.listNum;
this.pageData[1].end = this.pageData[2].start - 1;
console.log(`SingleLineList pageData 1 start:${this.pageData[1].start}`);
console.log(`SingleLineList pageData 1 end:${this.pageData[1].end}`);
this.transList1 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList2 = `all 0s ${AnimationEffect.Basic}`;
this.transList3 = `all 0.3s ${AnimationEffect.Basic}`;
} else {
this.transList1 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList2 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList3 = `all 0.3s ${AnimationEffect.Basic}`;
}
} else if (lastPageIndex === 2 && curPageIndex === 1) {
// move 3 list left
this.hList2ScrollPx += this.scaleW;
if (this.pageData[0].start > 0 && this.pageData[lastPageIndex - 1].end !== this.detailslen - 1) {
this.hList3ScrollPx -= this.hPagePx;
this.pageData[2].start = this.pageData[0].start - this.listNum;
this.pageData[2].end = this.pageData[0].start - 1;
console.log(`SingleLineList pageData 2 start:${this.pageData[2].start}`);
console.log(`SingleLineList pageData 2 end:${this.pageData[2].end}`);
this.transList1 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList2 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList3 = `all 0s ${AnimationEffect.Basic}`;
} else {
this.transList1 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList2 = `all 0.3s ${AnimationEffect.Basic}`;
this.transList3 = `all 0.3s ${AnimationEffect.Basic}`;
}
}
}
moveLastItemR() {
if (this.getFocusIndex() === this.detailslen - 1) {
console.log('[SingleLineList.js:moveLastItem] Right.');
const lastItemScrollPx = this.getLastItemScrollPx();
this.hScrollPx += this.hListPx;
this.hScrollPx -= lastItemScrollPx;
}
}
moveLastItemL() {
if (this.getFocusIndex() === this.detailslen - 1 - this.listShowNum) {
console.log('[SingleLineList.js:moveLastItem] Left.');
const lastItemScrollPx = this.getLastItemScrollPx();
this.hScrollPx -= this.hListPx;
this.hScrollPx += lastItemScrollPx;
}
}
focusMove(direct) {
let pageIndex = parseInt(this.focus.charAt(this.focus.length - 1), 10);
const lastPageIndex = pageIndex;
if ((pageIndex >= 3 && direct === 1)) {
pageIndex = 1;
} else if ((pageIndex <= 1 && direct === -1)) {
pageIndex = 3;
} else {
pageIndex += direct;
}
const curPageIndex = pageIndex;
this.moveList(lastPageIndex, curPageIndex);
const position = this.refs[this.focus].keyFocusOut();
this.focus = `LIST${pageIndex}`;
if (direct > 0) { // right
this.refs[this.focus].keyFocusInByIndex(0);
} else { // left
this.refs[this.focus].keyFocusInByIndex(this.listNum - 1);
}
}
adjustListPosition(event) {
const { details, gap, width, transLeft } = this.props;
const pageIndex = parseInt(this.focus.charAt(this.focus.length - 1), 10);
const listIndex = this.refs[this.focus].getFocusIndex();
const totalLength = (details[0].OSD.layout.w + gap) * this.detailslen;
const barLength = width - (transLeft * 2);
const hiddenPx = totalLength - barLength;
let scrollBarPx = 0;
let i = 0;
for (i = 0; i < this.listShowNum; i++) {
if (this.showData[i].pageIndex === pageIndex && this.showData[i].listIndex === listIndex) {
break;
}
}
console.log(`SingleLineList adjustListPosition i:${i}`);
// if need move
if (i === this.listShowNum) {
switch (event.keyCode) {
case KEY.LEFT:
this.hScrollPx += this.hListPx;
this.moveLastItemL();
scrollBarPx = this.hScrollPx;
if (scrollBarPx < 0) {
scrollBarPx *= -1;
}
this.scrollHPercent = scrollBarPx / hiddenPx;
// update show data
for (i = this.listShowNum - 1; i >= 1; i--) {
this.showData[i].pageIndex = this.showData[i - 1].pageIndex;
this.showData[i].listIndex = this.showData[i - 1].listIndex;
}
this.showData[0].pageIndex = pageIndex;
this.showData[0].listIndex = listIndex;
break;
case KEY.RIGHT:
this.hScrollPx -= this.hListPx;
this.moveLastItemR();
scrollBarPx = this.hScrollPx;
if (scrollBarPx < 0) {
scrollBarPx *= -1;
}
if (this.getFocusIndex() === this.detailslen - 1) {
this.scrollHPercent = 1;
} else {
this.scrollHPercent = scrollBarPx / hiddenPx;
}
for (i = 0; i < this.listShowNum - 1; i++) {
this.showData[i].pageIndex = this.showData[i + 1].pageIndex;
this.showData[i].listIndex = this.showData[i + 1].listIndex;
}
this.showData[this.listShowNum - 1].pageIndex = pageIndex;
this.showData[this.listShowNum - 1].listIndex = listIndex;
break;
default:
// false: pass event to base component, true: not pass
}
}
this.setState({
scrollHPercent: this.scrollHPercent, // Calculated when component mounted, because index is found by ref name, so it can only be calculated after component mounted.
hScrollPx: this.hScrollPx,
hList1ScrollPx: this.hList1ScrollPx,
hList2ScrollPx: this.hList2ScrollPx,
hList3ScrollPx: this.hList3ScrollPx,
transList1: this.transList1,
transList2: this.transList2,
transList3: this.transList3,
});
/* for (i = 0; i < this.listShowNum; i++) {
console.log(`SingleLineList adjustListPosition all i:${i}, pageIndex:${this.showData[i].pageIndex}, listIndex:${this.showData[i].listIndex}`);
}*/
}
handleKey(event) {
// when ever loading is showing, should not response keypress except for 'exit' key.
console.log(`[SingleLineList.js] handleKey keyCode:${event.keyCode}`);
if (this.detailslen <= this.listNum * 3 || !this.props.morefetchEnable) { // If not exceed 3 pages, no need to use morefetch
this.refs[this.focus].handleKey(event);
return true;
}
let pageIndex = 0;
const scroll = 'SCROLL';
const list1 = 'LIST1';
const list2 = 'LIST2';
const list3 = 'LIST3';
switch (event.keyCode) {
case KEY.LEFT:
if ((this.refs[this.focus].getFocusIndex() === 0)
&& (this.focus === 'LIST1')
&& (this.pageData[0].start === 0)) {
console.log('SingleLineList on the first one!');
if ((event.type === 'keydown' && this.lastKey === 'keydown')
|| (event.type === 'keyup' && this.lastKey === 'keydown')
|| (event.type === 'keyup' && this.lastKey === 'keyup')) {
this.lastKey = event.type;
return false;
}
this.lastKey = event.type;
this.refs[this.focus].handleBounce(-1);
} else {
if (event.type === 'keyup') {
return false;
}
if (this.refs[this.focus].getFocusIndex() === 0) {
this.focusMove(-1);
} else {
this.refs[this.focus].handleKey(event);
}
this.adjustListPosition(event);
this.playTTS(TTSTYPE.ITEM);
}
if (this.refs[scroll]) {
this.refs[scroll].showBar();
}
break;
case KEY.RIGHT:
if (this.getFocusIndex() === this.detailslen - 1) {
console.log('SingleLineList on the last one!');
if ((event.type === 'keydown' && this.lastKey === 'keydown')
|| (event.type === 'keyup' && this.lastKey === 'keydown')
|| (event.type === 'keyup' && this.lastKey === 'keyup')) {
this.lastKey = event.type;
return false;
}
this.lastKey = event.type;
this.refs[list1].handleBounce(1);
this.refs[list2].handleBounce(1);
this.refs[list3].handleBounce(1);
} else {
if (event.type === 'keyup') {
return false;
}
pageIndex = parseInt(this.focus.charAt(this.focus.length - 1), 10);
if (this.pageData[pageIndex - 1].end !== this.detailslen - 1
&& this.refs[this.focus].getFocusIndex() === this.listNum - 1) {
this.focusMove(1);
} else {
this.refs[this.focus].handleKey(event);
}
this.adjustListPosition(event);
this.playTTS(TTSTYPE.ITEM);
}
if (this.refs[scroll]) {
this.refs[scroll].showBar();
}
break;
default:
// false: pass event to base component, true: not pass
}
return true;
}
render() {
console.log('SingleLineList render');
const { morefetchEnable, width, height, transLeft, scrollBarEnable, focusScale, maxScale, gap, details, enter, enterCB } = this.props;
const { top, contentTop, scrollBarTop, initFocus, initIndex, bounceEnable, bounceDelay, ttsEnable, ttsText, transRight, firstItemMoveEnable, title } = this.props;
const { titleAni } = this.state;
// app list
this.getListData(this.commonList1Data, 0);
let transLeftParm = 0;
let scrollBarEnableParam = false;
let morefetchEnableParam = true;
let transRightParam = 0;
let titleParam;
let firstItemMoveEnableParam = firstItemMoveEnable;
if (this.detailslen <= this.listNum * 3 || !morefetchEnable) { // If not exceed 3 pages, no need to use morefetch
transLeftParm = transLeft;
scrollBarEnableParam = true;
morefetchEnableParam = false;
transRightParam = transRight;
titleParam = title;
}
if (this.pageData[0].start !== 0) {
firstItemMoveEnableParam = true; // morefetch needs to move in the first item
}
const list1Component = (<CommonList
details={this.commonList1Data}
initFocus={initFocus}
initIndex={initIndex}
transLeft={transLeftParm}
transRight={transRightParam}
ref='LIST1'
enter={enter}
enterCB={enterCB}
transition={`all 0.2s ${AnimationEffect.Basic}`}
width={width}
height={height}
top={top}
contentTop={contentTop}
scrollBarTop={scrollBarTop}
focusScale={focusScale}
maxScale={maxScale}
gap={gap}
scrollBarEnable={scrollBarEnableParam}
morefetchEnable={morefetchEnableParam}
bounceEnable={bounceEnable}
bounceDelay={bounceDelay}
ttsEnable={ttsEnable}
ttsText={ttsText}
firstItemMoveEnable={firstItemMoveEnableParam}
title={titleParam}
/>);
if (this.detailslen <= this.listNum * 3 || !morefetchEnable) { // If not exceed 3 pages, no need to use morefetch
return (<div>
{list1Component}
</div>
);
}
const { scrollHPercent, hScrollPx, hList1ScrollPx, hList2ScrollPx, hList3ScrollPx, transList1, transList2, transList3 } = this.state;
this.getListData(this.commonList2Data, 1);
this.getListData(this.commonList3Data, 2);
const list2Component = (<CommonList
details={this.commonList2Data}
initFocus={false}
initIndex={initIndex}
transLeft={0}
transRight={0}
ref='LIST2'
enter={enter}
enterCB={enterCB}
transition={`all 0.2s ${AnimationEffect.Basic}`}
width={width}
height={height}
top={top}
contentTop={contentTop}
scrollBarTop={scrollBarTop}
focusScale={focusScale}
maxScale={maxScale}
gap={gap}
scrollBarEnable={scrollBarEnableParam}
morefetchEnable={morefetchEnableParam}
bounceEnable={bounceEnable}
bounceDelay={bounceDelay}
ttsEnable={ttsEnable}
title={titleParam}
/>);
const list3Component = (<CommonList
details={this.commonList3Data}
initFocus={false}
initIndex={initIndex}
transLeft={0}
transRight={0}
ref='LIST3'
enter={enter}
enterCB={enterCB}
transition={`all 0.2s ${AnimationEffect.Basic}`}
width={width}
height={height}
top={top}
contentTop={contentTop}
scrollBarTop={scrollBarTop}
focusScale={focusScale}
maxScale={maxScale}
gap={gap}
scrollBarEnable={scrollBarEnableParam}
morefetchEnable={morefetchEnableParam}
bounceEnable={bounceEnable}
bounceDelay={bounceDelay}
ttsEnable={ttsEnable}
/>);
if (height === 0) {
this.listheight = details[0].OSD.layout.h * maxScale;
} else {
this.listheight = height;
}
// list style
const listStyle = {
position: 'relative',
width,
height: this.listheight, // list height
overflow: 'hidden',
top,
};
const contentStyle = {
position: 'absolute',
transform: `translateX(${hScrollPx}px)`,
transition: `all 0.3s ${AnimationEffect.Basic}`,
};
const list1Style = {
position: 'absolute',
transform: `translateX(${hList1ScrollPx}px) translateZ(10px)`,
transition: transList1,
};
const list2Style = {
position: 'absolute',
transform: `translateX(${hList2ScrollPx}px) translateZ(10px)`,
transition: transList2,
};
const list3Style = {
position: 'absolute',
transform: `translateX(${hList3ScrollPx}px) translateZ(10px)`,
transition: transList3,
};
if (scrollBarTop === 0) {
this.scrollBarTop = details[0].OSD.layout.h * maxScale;
} else {
this.scrollBarTop = scrollBarTop;
}
// scrollbar
let scrollbarComponent = null;
const totalLength = (details[0].OSD.layout.w + gap) * this.detailslen;
const scrollLeft = firstItemMoveEnable ? transLeft : (transLeft - this.halfScaleW);
const barLength = width - (scrollLeft * 2);
if (scrollBarEnable && this.hasFocus && totalLength > barLength) {
scrollbarComponent = (<ScrollBar
ref='SCROLL'
left={scrollLeft}
top={this.scrollBarTop}
barType='h'
bgWidth={barLength}
bgHeight={3}
barPercent={barLength / totalLength}
scrollPercent={scrollHPercent}
/>);
}
// TTS
let TTSComponent = null;
if (ttsEnable) {
TTSComponent = <TTS ref={(TTSnode) => { this.TTSnode = TTSnode; }} ttsEnable={ttsEnable} ttsText={ttsText} />;
}
// title
const titleStyle = {
position: 'absolute',
};
let titleComponent = null;
if (title !== undefined && title !== null) {
if (this.titleAni !== '') {
titleStyle.animationName = titleAni;
titleStyle.animationDelay = '0.083s';
titleStyle.animationIterationCount = '1';
titleStyle.animationDuration = '0.7s';
titleStyle.animationTimingFunction = 'cubic-bezier(0.3,0,0.15,1)';
titleStyle.animationFillMode = 'forwards';
}
titleComponent = (<ScrollText
top={title.t}
left={title.l}
width={title.w}
height={title.h}
lineHeight={`${title.h}px`}
scroll={false}
fontSize={title.fontSize}
fontFamily={title.fontFamily}
color={title.color}
>
{title.text}
</ScrollText>);
}
return (<div>
<div style={listStyle}>
<div style={titleStyle}>
{titleComponent}
</div>
<div style={contentStyle}>
<div style={list1Style}>
{list1Component}
</div>
<div style={list2Style}>
{list2Component}
</div>
<div style={list3Style}>
{list3Component}
</div>
</div>
</div>
{scrollbarComponent}
{TTSComponent}
</div>
);
}
}
SingleLineList.defaultProps = {
morefetchEnable: true, // flag for whether to use morefetch function
width: 1920, // width of display window of the list.
height: 0,
transLeft: 0, // when you want to move the list, but don't want to move display window, use this value.
transRight: 0, // lastItem margin right
top: 0, // same meaning as html top. it's used for display window.
contentTop: 0,
scrollBarTop: 0,
focusScale: 1.2,
maxScale: 1.3,
gap: 2,
scrollBarEnable: true,
enter: false, // if enter pressed.
enterCB: null, // enter call back.
initFocus: false,
initIndex: 0,
bounceEnable: true, // bounce back animation name. aviable value: bounce1/bounce2.
bounceDelay: 0, // delay time for bounce animation.
ttsEnable: false,
ttsText: '',
firstItemMoveEnable: true,
title: undefined,
};
SingleLineList.propTypes = {
morefetchEnable: PropTypes.bool, // flag for whether to use morefetch function
width: PropTypes.number,
height: PropTypes.number,
transLeft: PropTypes.number,
transRight: PropTypes.number,
top: PropTypes.number,
contentTop: PropTypes.number,
scrollBarTop: PropTypes.number,
focusScale: PropTypes.number,
maxScale: PropTypes.number,
gap: PropTypes.number,
scrollBarEnable: PropTypes.bool,
enter: PropTypes.bool,
enterCB: PropTypes.func,
initFocus: PropTypes.bool, // List has focus or not
initIndex: PropTypes.number,
bounceEnable: PropTypes.bool, // bounce back animation name. aviable value: bounce1/bounce2.
bounceDelay: PropTypes.number, // delay time for bounce animation.
ttsEnable: PropTypes.bool,
ttsText: PropTypes.string,
firstItemMoveEnable: PropTypes.bool,
title: PropTypes.shape({
l: PropTypes.number,
t: PropTypes.number,
w: PropTypes.number,
h: PropTypes.number,
fontSize: PropTypes.number,
text: PropTypes.string,
fontFamily: PropTypes.string,
color: PropTypes.string,
}),
details: PropTypes.arrayOf(PropTypes.shape({
OSD: PropTypes.shape({ // UI content for ImageItem
layout: PropTypes.shape({
l: PropTypes.number.isRequired,
t: PropTypes.number.isRequired,
w: PropTypes.number.isRequired,
h: PropTypes.number.isRequired,
}),
image: PropTypes.array,
icon: PropTypes.array,
text: PropTypes.array,
ttsText: PropTypes.string,
progress: PropTypes.shape({
l: PropTypes.number,
t: PropTypes.number,
w: PropTypes.number,
h: PropTypes.number,
rate: PropTypes.number,
}),
}),
})).isRequired,
};