diff --git a/src/playlist-maker.js b/src/playlist-maker.js index 0c907c6..a9546c9 100644 --- a/src/playlist-maker.js +++ b/src/playlist-maker.js @@ -31,6 +31,10 @@ const isItemObject = (value) => { * A new array with transformed items */ const transformPrimitiveItems = (arr) => { + if (arr.filter(item => isItemObject(item)).length === arr.length) { + return arr; + } + const list = []; let tempItem; @@ -183,6 +187,20 @@ const randomize = (arr) => { return arr; }; +/** + * get the Copied playlist + * + * @private + * @param {Array} arr + * An array. + * + * @return {Array} + * The copied array contains the same items. + */ +const cloneList = (arr) => { + return arr.map((item) => item.originalValue || item).slice(); +}; + /** * Factory function for creating new playlist implementation on the given player. * @@ -247,12 +265,8 @@ export default function factory(player, initialList, initialIndex = 0) { const previousPlaylist = Array.isArray(list) ? list.slice() : null; const nextPlaylist = newList.slice(); - list = nextPlaylist.slice(); - // Transform any primitive and null values in an input list to objects - if (list.filter(item => isItemObject(item)).length !== list.length) { - list = transformPrimitiveItems(list); - } + list = transformPrimitiveItems(nextPlaylist.slice()); // Add unique id to each playlist item. This id will be used // to determine index in cases where there are more than one @@ -294,7 +308,35 @@ export default function factory(player, initialList, initialIndex = 0) { // Always return a shallow clone of the playlist list. // We also want to return originalValue if any item in the list has it. - return list.map((item) => item.originalValue || item).slice(); + return cloneList(list); + }; + + playlist.updateList = function updateList(partialList, positionCb) { + if (changing) { + throw new Error('do not call updateList() during a playlist change'); + } + + if (!Array.isArray(partialList)) { + throw new Error('give first argument an array when calling updateList'); + } + + if (typeof positionCb !== 'function') { + throw new Error('give second argument a callback when calling updateList'); + } + + const formattedPartialList = transformPrimitiveItems(partialList); + + formattedPartialList.forEach(item => { + const position = positionCb(item, list); + + if (position < 0 || position >= list.length) { + return; + } + + Object.assign(list[position], item); + }); + + return cloneList(list); }; // On a new source, if there is no current item, disable auto-advance. diff --git a/test/playlist-maker.test.js b/test/playlist-maker.test.js index 17cf196..618a22f 100644 --- a/test/playlist-maker.test.js +++ b/test/playlist-maker.test.js @@ -36,6 +36,9 @@ const videoList = [{ poster: 'http://media.w3.org/2010/05/video/poster.png' }]; +const videoInitialList = videoList.slice(0, 2).concat([null, null, null]); +const videoPartialList = videoList.slice(2); + QUnit.module('playlist-maker', { beforeEach() { @@ -899,3 +902,42 @@ QUnit.test('playlist.shuffle({rest: true}) works as expected', function(assert) assert.notStrictEqual(list.indexOf(4), -1, '4 is in the list'); assert.strictEqual(spy.callCount, 3, 'the "playlistsorted" event triggered'); }); + +QUnit.test('playlist.updateList() works as expected', function(assert) { + const player = playerProxyMaker(); + const playlist = playlistMaker(player, videoInitialList); + const list = playlist(); + const playlistItemIds = list.map(item => item.playlistItemId_); + + const emptyIndexes = []; + + list.forEach((item, index) => { + if (item.originalValue === null) { + emptyIndexes.push(index); + } + }); + + const modifiedPlaylist = playlist.updateList(videoPartialList, () => { + return emptyIndexes.shift(); + }); + const modifiedPlaylistItemIds = modifiedPlaylist.map(item => item.playlistItemId_); + + assert.deepEqual( + playlistItemIds, + modifiedPlaylistItemIds, + 'the value of playlistItemId_ remains the same as the original one' + ); + + function isItemEqual(src, dst, message) { + assert.equal(src.sources, dst.sources, message); + assert.equal(src.poster, dst.poster, message); + } + + isItemEqual(modifiedPlaylist[2], videoPartialList[0], 'videoPartialList[0] is placed at position 2'); + isItemEqual(modifiedPlaylist[3], videoPartialList[1], 'videoPartialList[1] is placed at position 3'); + isItemEqual(modifiedPlaylist[4], videoPartialList[2], 'videoPartialList[2] is placed at position 4'); + + assert.equal(list[2], modifiedPlaylist[2], 'the updated item at position 2 is still the original item'); + assert.equal(list[3], modifiedPlaylist[3], 'the updated item at position 3 is still the original item'); + assert.equal(list[4], modifiedPlaylist[4], 'the updated item at position 4 is still the original item'); +});