diff --git a/tv_apps/tv-epg/index.html b/tv_apps/tv-epg/index.html
index cd2748be3140..feb91fb19670 100644
--- a/tv_apps/tv-epg/index.html
+++ b/tv_apps/tv-epg/index.html
@@ -8,6 +8,7 @@
+
@@ -29,6 +30,7 @@
+
diff --git a/tv_apps/tv-epg/js/epg.js b/tv_apps/tv-epg/js/epg.js
index 6168f3e3429a..5362ffc90de4 100644
--- a/tv_apps/tv-epg/js/epg.js
+++ b/tv_apps/tv-epg/js/epg.js
@@ -99,7 +99,7 @@
};
proto._onScanned = function epg__onScanned(stream) {
- this.videoElement.src = stream;
+ this.videoElement.mozSrcObject = stream;
this.epgController.fetchPrograms(
this.visibleTimeOffset - this.visibleTimeSize,
3 * this.visibleTimeSize
@@ -137,25 +137,16 @@
*/
proto._addProgramSlot = function epg__addProgramSlot(index, time) {
var rowElement;
- var columnElement;
- var textElement;
- var progressElement;
+ var programElement;
var i;
for (i = 0; i < this.programListElement.children.length; i++) {
rowElement = this.programListElement.children[i];
- columnElement = document.createElement('LI');
- columnElement.dataset.duration = '1';
- columnElement.dataset.startTime = time;
- progressElement = document.createElement('DIV');
- progressElement.classList.add('background-progress');
- textElement = document.createElement('DIV');
- textElement.classList.add('title');
- columnElement.appendChild(progressElement);
- columnElement.appendChild(textElement);
+ programElement = document.createElement('epg-program');
+ programElement.startTime = time;
if (index < this.timelineElement.children.length) {
- rowElement.insertBefore(columnElement, rowElement.children[index]);
+ rowElement.insertBefore(programElement, rowElement.children[index]);
} else {
- rowElement.appendChild(columnElement);
+ rowElement.appendChild(programElement);
}
}
};
@@ -181,43 +172,35 @@
proto._updateProgramSlot = function epg__updateProgramSlot(configs) {
var rowElement = this.programListElement.children[configs.row];
- var columnElement = rowElement.children[configs.column];
- var duration = parseInt(columnElement.dataset.duration, 10);
- var progressElement;
- var currentColumn;
+ var programElement = rowElement.children[configs.column];
+ var duration = programElement.duration;
if (configs.title) {
- columnElement.querySelector('.title').textContent = configs.title;
+ programElement.title = configs.title;
}
if (configs.duration) {
duration = configs.duration;
- columnElement.dataset.duration = duration;
+ programElement.duration = duration;
}
if (configs.isVisible) {
- columnElement.classList.remove('hidden');
- this.spatialNavigator.add(columnElement);
- currentColumn = this.initialTime - this.epgController.timelineOffset;
- progressElement = columnElement.querySelector('.background-progress');
- if (configs.column + duration <= currentColumn) {
- progressElement.style.transform = 'scaleX(1)';
- } else {
- progressElement.classList.add('smooth');
- }
+ programElement.show();
+ this.spatialNavigator.add(programElement);
+ programElement.resetProgressElement(this.initialTime);
} else {
- columnElement.classList.add('hidden');
+ programElement.hide();
// If the old focus element only contains partial program segment, we have
// to refocus to the first visible element of the same program.
- if (columnElement === this.spatialNavigator.getFocusedElement()) {
+ if (programElement === this.spatialNavigator.getFocusedElement()) {
this.spatialNavigator.focus(
this.epgController.programTable[configs.column][configs.row].element);
}
- this.spatialNavigator.remove(columnElement);
+ this.spatialNavigator.remove(programElement);
}
if (configs.item) {
- configs.item.element = columnElement;
+ configs.item.element = programElement;
}
};
@@ -236,23 +219,11 @@
var prevPrograms = this.epgController.programTable[timeIndex - 1];
var row;
var programElement;
- var startTime;
- var duration;
- var scaleX;
// Update progress bar in every currently playing program
for (row in playingPrograms) {
programElement = playingPrograms[row].element;
- startTime = parseInt(programElement.dataset.startTime, 10);
- duration = parseInt(programElement.dataset.duration, 10);
-
- // There is a margin between two programs, so scale has to be normalized
- scaleX = (time / this.timelineUnit - startTime) * EPG.COLUMN_WIDTH;
- scaleX = scaleX / (duration * EPG.COLUMN_WIDTH - EPG.COLUMN_MARGIN);
- scaleX = Math.min(scaleX, 1);
- programElement.querySelector('.background-progress').style.transform =
- 'scaleX(' + scaleX + ')';
-
+ programElement.progress = time / this.timelineUnit;
this.timeMarkerElement.style.transform =
'translateX(' +
((time / this.timelineUnit - this.initialTime) * EPG.COLUMN_WIDTH) +
@@ -263,8 +234,7 @@
if (prevPrograms && prevPrograms[row] &&
programElement !== prevPrograms[row].element) {
programElement = prevPrograms[row].element;
- programElement.querySelector('.background-progress').style.transform =
- 'scaleX(1)';
+ programElement.fillProgress();
}
}
};
@@ -287,15 +257,14 @@
};
};
- proto._onFocus = function epg__onFocus(element) {
- var rowElement = element.parentElement;
+ proto._onFocus = function epg__onFocus(programElement) {
+ var rowElement = programElement.parentElement;
var rowIndex = parseInt(rowElement.dataset.row, 10);
var rowOffset = this.epgController.channelOffset;
- var startTime = parseInt(element.dataset.startTime, 10);
+ var startTime = programElement.startTime;
var timelineOffset = this.epgController.timelineOffset;
-
- element.classList.add('focus');
+ programElement.classList.add('focus');
rowElement.classList.remove('hidden');
this._setTitlePadding({
setToNull: true
@@ -373,20 +342,15 @@
var row;
var timeOffset = this.visibleTimeOffset - this.epgController.timelineOffset;
var programElement;
- var programTitleElement;
- var programStartTime;
for(row = rowOffset; row < rowOffset + size; row++) {
if (this.epgController.programTable[timeOffset][row]) {
programElement =
this.epgController.programTable[timeOffset][row].element;
- programTitleElement = programElement.querySelector('.title');
if (opts && opts.setToNull) {
- programTitleElement.style.paddingLeft = null;
+ programElement.titlePadding = null;
} else {
- programStartTime = parseInt(programElement.dataset.startTime, 10);
- programTitleElement.style.paddingLeft =
- EPG.COLUMN_WIDTH * (this.visibleTimeOffset - programStartTime) +
- 'rem';
+ programElement.titlePadding = EPG.COLUMN_WIDTH *
+ (this.visibleTimeOffset - programElement.startTime) + 'rem';
}
}
}
@@ -415,8 +379,8 @@
this.dateElement.textContent = dtf.localeFormat(now, timeFormat);
};
- proto._onUnfocus = function epg__onUnfocus(element) {
- element.classList.remove('focus');
+ proto._onUnfocus = function epg__onUnfocus(programElement) {
+ programElement.classList.remove('focus');
};
proto._onMove = function epg__onMove(key) {
diff --git a/tv_apps/tv-epg/js/epg_program.js b/tv_apps/tv-epg/js/epg_program.js
new file mode 100644
index 000000000000..2133947f848c
--- /dev/null
+++ b/tv_apps/tv-epg/js/epg_program.js
@@ -0,0 +1,90 @@
+/* global EPG */
+
+'use strict';
+
+window.EPGProgram = (function(exports) {
+ var proto = Object.create(HTMLElement.prototype);
+
+ proto.createdCallback = function() {
+ this._duration = 1;
+ this.dataset.duration = '1';
+ this.titleElement = document.createElement('DIV');
+ this.titleElement.classList.add('title');
+ this.appendChild(this.titleElement);
+
+ this.progressElement = document.createElement('DIV');
+ this.progressElement.classList.add('background-progress');
+ this.appendChild(this.progressElement);
+ };
+
+ Object.defineProperty(proto, 'progress', {
+ set: function(time) {
+ if (!this.startTime || !time) {
+ return;
+ }
+
+ var scaleX = (time - this.startTime) * EPG.COLUMN_WIDTH;
+ scaleX = scaleX / (this.duration * EPG.COLUMN_WIDTH - EPG.COLUMN_MARGIN);
+ scaleX = Math.min(scaleX, 1);
+ this.progressElement.style.transform = 'scaleX(' + scaleX + ')';
+ }
+ });
+
+ Object.defineProperty(proto, 'startTime', {
+ set: function(time) {
+ this._startTime = time;
+ },
+ get: function() {
+ return this._startTime;
+ }
+ });
+
+ Object.defineProperty(proto, 'title', {
+ set: function(title) {
+ this.titleElement.textContent = title;
+ }
+ });
+
+ Object.defineProperty(proto, 'titlePadding', {
+ set: function(padding) {
+ this.titleElement.style.paddingLeft = padding;
+ }
+ });
+
+ Object.defineProperty(proto, 'duration', {
+ set: function(duration) {
+ this._duration = duration;
+ this.dataset.duration = duration;
+ },
+ get: function() {
+ return this._duration;
+ }
+ });
+
+ proto.resetProgressElement = function(time) {
+ if (!this.startTime || !time) {
+ return;
+ }
+
+ if (this.startTime + this.duration <= time) {
+ this.fillProgress();
+ } else {
+ this.progressElement.classList.add('smooth');
+ }
+ this.appendChild(this.progressElement);
+ };
+
+ proto.fillProgress = function() {
+ this.progressElement.style.transform = 'scaleX(1)';
+ };
+
+ proto.hide = function() {
+ this.classList.add('hidden');
+ };
+
+ proto.show = function() {
+ this.classList.remove('hidden');
+ };
+
+ return document.registerElement('epg-program', { prototype: proto });
+})(window);
diff --git a/tv_apps/tv-epg/style/epg_program.css b/tv_apps/tv-epg/style/epg_program.css
new file mode 100644
index 000000000000..fc973c521ba7
--- /dev/null
+++ b/tv_apps/tv-epg/style/epg_program.css
@@ -0,0 +1,85 @@
+epg-program {
+ display: inline-block;
+ position: relative;
+ width: 33.5rem;
+ font-size: 2.5rem;
+ line-height: 10.8rem;
+ overflow: hidden;
+ padding-bottom: 0.3rem;
+ padding-right: 0.3rem;
+ border-bottom: 0.1rem #5e5e5e solid;
+ margin-top: 0.3rem;
+ background-color: #404040;
+ height: 11.2rem;
+ background-clip: content-box;
+ box-sizing: border-box;
+ outline: none;
+}
+
+epg-program:after {
+ content: '';
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 0.1rem;
+ background-color: #5e5e5e;
+ height: 10.8rem;
+}
+
+epg-program.focus {
+ background-color: #00caf2;
+}
+
+epg-program.hidden {
+ display: none;
+}
+
+epg-program[data-duration="1"] {
+ width: 33.8rem;
+}
+
+epg-program[data-duration="2"] {
+ width: 67.6rem;
+}
+
+epg-program[data-duration="3"] {
+ width: 101.4rem;
+}
+
+epg-program[data-duration="4"] {
+ width: 135.2rem;
+}
+
+epg-program[data-duration="5"] {
+ width: 169rem;
+}
+
+epg-program[data-duration="6"] {
+ width: 202.8rem;
+}
+
+epg-program[data-duration="7"] {
+ width: 236.9rem;
+}
+
+epg-program > .title {
+ margin-left: 2rem;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ width: calc(100% - 2rem);
+ box-sizing: border-box;
+ position: absolute;
+}
+
+epg-program > .background-progress {
+ position: absolute;
+ background-color: rgba(0, 0, 0, 0.2);
+ height: calc(100% - 0.3rem);
+ transform: scaleX(0);
+ transform-origin: 0;
+ width: calc(100% - 0.3rem);
+}
+
+epg-program > .background-progress.smooth {
+ transition: transform 0.3s;
+}
diff --git a/tv_apps/tv-epg/style/tv_epg.css b/tv_apps/tv-epg/style/tv_epg.css
index 56247f956e92..c95d160aede3 100644
--- a/tv_apps/tv-epg/style/tv_epg.css
+++ b/tv_apps/tv-epg/style/tv_epg.css
@@ -228,91 +228,6 @@ a:hover, a:active, a:focus {
display: none;
}
-#program-list > ul > li {
- display: inline-block;
- position: relative;
- width: 33.5rem;
- font-size: 2.5rem;
- line-height: 10.8rem;
- overflow: hidden;
- padding-bottom: 0.3rem;
- padding-right: 0.3rem;
- border-bottom: 0.1rem #5e5e5e solid;
- margin-top: 0.3rem;
- background-color: #404040;
- height: 11.2rem;
- background-clip: content-box;
- box-sizing: border-box;
-}
-
-#program-list > ul > li:after {
- content: '';
- position: absolute;
- top: 0;
- right: 0;
- width: 0.1rem;
- background-color: #5e5e5e;
- height: 10.8rem;
-}
-
-#program-list > ul > li.focus {
- background-color: #00caf2;
-}
-
-#program-list > ul > li.hidden {
- display: none;
-}
-
-#program-list > ul > li[data-duration="1"] {
- width: 33.8rem;
-}
-
-#program-list > ul > li[data-duration="2"] {
- width: 67.6rem;
-}
-
-#program-list > ul > li[data-duration="3"] {
- width: 101.4rem;
-}
-
-#program-list > ul > li[data-duration="4"] {
- width: 135.2rem;
-}
-
-#program-list > ul > li[data-duration="5"] {
- width: 169rem;
-}
-
-#program-list > ul > li[data-duration="6"] {
- width: 202.8rem;
-}
-
-#program-list > ul > li[data-duration="7"] {
- width: 236.9rem;
-}
-
-#program-list > ul > li > .title {
- margin-left: 2rem;
- overflow: hidden;
- text-overflow: ellipsis;
- width: calc(100% - 2rem);
- box-sizing: border-box;
- position: absolute;
-}
-
-#program-list > ul > li > .background-progress {
- position: absolute;
- background-color: rgba(0, 0, 0, 0.2);
- height: calc(100% - 0.3rem);
- transform: scaleX(0);
- transform-origin: 0;
- width: calc(100% - 0.3rem);
-}
-
-#program-list > ul > li > .background-progress.smooth {
- transition: transform 0.3s;
-}
-
#bottom-container {
width: 100%;
box-sizing: border-box;
diff --git a/tv_apps/tv-epg/test/unit/epg_program_test.js b/tv_apps/tv-epg/test/unit/epg_program_test.js
new file mode 100644
index 000000000000..45d04fd84757
--- /dev/null
+++ b/tv_apps/tv-epg/test/unit/epg_program_test.js
@@ -0,0 +1,102 @@
+'use strict';
+/* jshint browser: true */
+/* global EPGProgram */
+
+require('/js/epg_program.js');
+
+suite('tv-epg/epg_program', function() {
+
+ var epgProgram;
+
+ suiteSetup(function() {
+ window.EPG = {
+ COLUMN_WIDTH: 33.8,
+ COLUMN_MARGIN: 0.6
+ };
+ });
+
+ setup(function() {
+ epgProgram = new EPGProgram();
+ });
+
+ suite('createdCallback', function() {
+ test('Initialization', function() {
+ assert.equal(epgProgram.duration, 1);
+ assert.equal(epgProgram.dataset.duration, '1');
+ assert.isDefined(epgProgram.titleElement);
+ assert.isDefined(epgProgram.progressElement);
+ });
+ });
+
+ suite('resetProgressElement', function() {
+ setup(function() {
+ epgProgram.startTime = 10;
+ epgProgram.duration = 3;
+ });
+
+ test('Program has been played', function() {
+ epgProgram.resetProgressElement(20);
+ assert.equal(epgProgram.progressElement.style.transform, 'scaleX(1)');
+ });
+
+ test('Program is still playing', function() {
+ epgProgram.resetProgressElement(12);
+ assert.equal(epgProgram.progressElement.style.transform, '');
+ assert.isTrue(epgProgram.progressElement.classList.contains('smooth'));
+ });
+ });
+
+ suite('fillProgress', function() {
+ test('Fill color of progress element', function() {
+ epgProgram.fillProgress();
+ assert.equal(epgProgram.progressElement.style.transform, 'scaleX(1)');
+ });
+ });
+
+ suite('startTime', function() {
+ test('Set start time', function() {
+ epgProgram.startTime = 20;
+ assert.equal(epgProgram.startTime, 20);
+ });
+ });
+
+ suite('title', function() {
+ test('Set title of title element', function() {
+ epgProgram.title = 'title';
+ assert.equal(epgProgram.titleElement.textContent, 'title');
+ });
+ });
+
+ suite('setTitlePadding', function() {
+ test('Set padding of title element', function() {
+ epgProgram.titlePadding = '10rem';
+ assert.equal(epgProgram.titleElement.style.paddingLeft, '10rem');
+ });
+ });
+
+ suite('setDuration', function() {
+ test('Set duration of epgProgram', function() {
+ epgProgram.duration = 10;
+ assert.equal(epgProgram.duration, 10);
+ assert.equal(epgProgram.dataset.duration, '10');
+ });
+ });
+
+ suite('hide', function() {
+ test('Hide epgProgram', function() {
+ epgProgram.hide();
+ assert.isTrue(epgProgram.classList.contains('hidden'));
+ });
+ });
+
+ suite('show', function() {
+ test('Show epgProgram', function() {
+ epgProgram.show();
+ assert.isFalse(epgProgram.classList.contains('hidden'));
+ });
+ });
+
+ suiteTeardown(function() {
+ window.EPG = null;
+ });
+});
diff --git a/tv_apps/tv-epg/test/unit/epg_test.js b/tv_apps/tv-epg/test/unit/epg_test.js
index d3e76c8cf9d9..7b40770e3ce6 100644
--- a/tv_apps/tv-epg/test/unit/epg_test.js
+++ b/tv_apps/tv-epg/test/unit/epg_test.js
@@ -4,9 +4,10 @@
require('/shared/test/unit/mocks/smart-screen/mock_spatial_navigator.js');
require('/shared/test/unit/mocks/smart-screen/mock_key_navigation_adapter.js');
-require('/test/unit/mock_epg_controller.js');
require('/shared/test/unit/mocks/smart-screen/mock_clock.js');
require('/shared/test/unit/mocks/mock_l10n.js');
+require('/test/unit/mock_epg_controller.js');
+require('/js/epg_program.js');
require('/js/epg.js');
@@ -61,26 +62,6 @@ suite('tv-epg/epg', function() {
window.navigator.mozL10n = realL10n;
});
- suite('_onScanned', function() {
- setup(function() {
- var promise = {
- then: function() {
- return promise;
- },
- catch: function() {
- return promise;
- }
- };
- this.sinon.stub(epg.epgController, 'fetchPrograms').returns(promise);
- });
-
- test('Source of video-thumbnail should be assigned', function() {
- var prefix = 'app://tv-epg.gaiamobile.org/test/unit';
- epg._onScanned('new-stream');
- assert.equal(epg.videoElement.src, prefix + '/new-stream');
- });
- });
-
suite('_addTimeline', function() {
setup(function() {
epg.programListElement.appendChild(document.createElement('UL'));
@@ -122,20 +103,12 @@ suite('tv-epg/epg', function() {
});
suite('_updateProgramSlot', function() {
- var columnElement;
- var textElement;
- var progressElement;
+ var programElement;
setup(function() {
var rowElement = document.createElement('UL');
- columnElement = document.createElement('LI');
- textElement = document.createElement('DIV');
- textElement.classList.add('title');
- progressElement = document.createElement('DIV');
- progressElement.classList.add('background-progress');
- columnElement.appendChild(textElement);
- columnElement.appendChild(progressElement);
- rowElement.appendChild(columnElement);
+ programElement = document.createElement('epg-program');
+ rowElement.appendChild(programElement);
epg.programListElement.appendChild(rowElement);
});
@@ -152,9 +125,9 @@ suite('tv-epg/epg', function() {
duration: 10
};
epg._updateProgramSlot(configs);
- assert.equal(textElement.textContent, 'program1');
- assert.isTrue(columnElement.classList.contains('hidden'));
- assert.equal(columnElement.dataset.duration, '10');
+ assert.equal(programElement.titleElement.textContent, 'program1');
+ assert.isTrue(programElement.classList.contains('hidden'));
+ assert.equal(programElement.dataset.duration, '10');
});
test('Visible column with item', function() {
@@ -166,9 +139,9 @@ suite('tv-epg/epg', function() {
duration: 10
};
epg._updateProgramSlot(configs);
- assert.equal(textElement.textContent, 'program1');
- assert.isFalse(columnElement.classList.contains('hidden'));
- assert.equal(columnElement.dataset.duration, '10');
+ assert.equal(programElement.titleElement.textContent, 'program1');
+ assert.isFalse(programElement.classList.contains('hidden'));
+ assert.equal(programElement.dataset.duration, '10');
});
teardown(function() {
@@ -219,7 +192,7 @@ suite('tv-epg/epg', function() {
};
}
});
- columnElement = document.createElement('DIV');
+ columnElement = document.createElement('epg-program');
rowElement = document.createElement('DIV');
rowElement.appendChild(columnElement);
epg.visibleChannelOffset = 10;
@@ -268,7 +241,7 @@ suite('tv-epg/epg', function() {
'rem, 0rem) translateZ(0.01rem)';
epg.epgController.timelineOffset = 4;
- columnElement.dataset.startTime = epg.visibleTimeOffset - 1;
+ columnElement.startTime = epg.visibleTimeOffset - 1;
epg._onFocus(columnElement);
assert.equal(
epg.timelineElement.style.transform, timelineAnswer);
@@ -284,7 +257,7 @@ suite('tv-epg/epg', function() {
'rem, 0rem) translateZ(0.01rem)';
epg.epgController.timelineOffset = 14;
- columnElement.dataset.startTime = epg.visibleTimeOffset + 4;
+ columnElement.startTime = epg.visibleTimeOffset + 4;
epg._onFocus(columnElement);
assert.equal(
epg.timelineElement.style.transform, timelineAnswer);
@@ -296,13 +269,9 @@ suite('tv-epg/epg', function() {
suite('_setTitlePadding', function() {
var programElement;
- var titleElement;
setup(function() {
- programElement = document.createElement('DIV');
- programElement.dataset.startTime = 0;
- titleElement = document.createElement('DIV');
- titleElement.classList.add('title');
- programElement.appendChild(titleElement);
+ programElement = document.createElement('epg-program');
+ programElement.startTime = 0;
epg.visibleTimeOffset = 1;
epg.epgController.timelineOffset = 0;
epg.epgController.programTable = {
@@ -318,12 +287,12 @@ suite('tv-epg/epg', function() {
epg._setTitlePadding({
setToNull: true
});
- assert.equal(titleElement.style.paddingLeft, '');
+ assert.equal(programElement.titleElement.style.paddingLeft, '');
});
test('Set padding-left of title element', function() {
epg._setTitlePadding();
- assert.equal(titleElement.style.paddingLeft, '33.8rem');
+ assert.equal(programElement.titleElement.style.paddingLeft, '33.8rem');
});
});
});