Frontent dev env (#247)

* Added frontend development files/environment

* More items-categories related removals

* Improvements in pages templates (inc. static pages)

* Improvements in video player

* Added empty home page message + cta

* Updates in media, playlist and management pages

* Improvements in material icons font loading

* Replaced media & playlists links in frontend dev-env

* frontend package version update

* chnaged frontend dev url port

* static files update

* Changed default position of theme switcher

* enabled frontend docker container
This commit is contained in:
Yiannis Stergiou
2021-07-11 18:01:34 +03:00
committed by GitHub
parent 060bb45725
commit aa6520daac
555 changed files with 201927 additions and 66002 deletions

View File

@@ -0,0 +1,90 @@
import Dispatcher from '../dispatcher.js';
export function loadMediaData() {
Dispatcher.dispatch({
type: 'LOAD_MEDIA_DATA',
});
}
export function likeMedia() {
Dispatcher.dispatch({
type: 'LIKE_MEDIA',
});
}
export function dislikeMedia() {
Dispatcher.dispatch({
type: 'DISLIKE_MEDIA',
});
}
export function reportMedia(reportDescription) {
Dispatcher.dispatch({
type: 'REPORT_MEDIA',
reportDescription: !!reportDescription ? reportDescription.replace(/\s/g, '') : '',
});
}
export function copyShareLink(inputElem) {
Dispatcher.dispatch({
type: 'COPY_SHARE_LINK',
inputElement: inputElem,
});
}
export function copyEmbedMediaCode(inputElem) {
Dispatcher.dispatch({
type: 'COPY_EMBED_MEDIA_CODE',
inputElement: inputElem,
});
}
export function removeMedia() {
Dispatcher.dispatch({
type: 'REMOVE_MEDIA',
});
}
export function submitComment(commentText) {
Dispatcher.dispatch({
type: 'SUBMIT_COMMENT',
commentText,
});
}
export function deleteComment(commentId) {
Dispatcher.dispatch({
type: 'DELETE_COMMENT',
commentId,
});
}
export function createPlaylist(playlist_data) {
Dispatcher.dispatch({
type: 'CREATE_PLAYLIST',
playlist_data,
});
}
export function addMediaToPlaylist(playlist_id, media_id) {
Dispatcher.dispatch({
type: 'ADD_MEDIA_TO_PLAYLIST',
playlist_id,
media_id,
});
}
export function removeMediaFromPlaylist(playlist_id, media_id) {
Dispatcher.dispatch({
type: 'REMOVE_MEDIA_FROM_PLAYLIST',
playlist_id,
media_id,
});
}
export function addNewPlaylist(playlist_data) {
Dispatcher.dispatch({
type: 'APPEND_NEW_PLAYLIST',
playlist_data,
});
}

View File

@@ -0,0 +1,22 @@
import Dispatcher from '../dispatcher.js';
export function initPage(page) {
Dispatcher.dispatch({
type: 'INIT_PAGE',
page,
});
}
export function toggleMediaAutoPlay() {
Dispatcher.dispatch({
type: 'TOGGLE_AUTO_PLAY',
});
}
export function addNotification(notification, notificationId) {
Dispatcher.dispatch({
type: 'ADD_NOTIFICATION',
notification,
notificationId,
});
}

View File

@@ -0,0 +1,41 @@
import Dispatcher from '../dispatcher.js';
export function loadPlaylistData() {
Dispatcher.dispatch({
type: 'LOAD_PLAYLIST_DATA',
});
}
export function toggleSave() {
Dispatcher.dispatch({
type: 'TOGGLE_SAVE',
});
}
export function updatePlaylist(playlist_data) {
Dispatcher.dispatch({
type: 'UPDATE_PLAYLIST',
playlist_data,
});
}
export function removePlaylist() {
Dispatcher.dispatch({
type: 'REMOVE_PLAYLIST',
});
}
export function removedMediaFromPlaylist(media_id, playlist_id) {
Dispatcher.dispatch({
type: 'MEDIA_REMOVED_FROM_PLAYLIST',
media_id,
playlist_id,
});
}
export function reorderedMediaInPlaylist(newMediaData) {
Dispatcher.dispatch({
type: 'PLAYLIST_MEDIA_REORDERED',
playlist_media: newMediaData,
});
}

View File

@@ -0,0 +1,19 @@
import Dispatcher from '../dispatcher.js';
export function toggleLoop() {
Dispatcher.dispatch({
type: 'TOGGLE_LOOP',
});
}
export function toggleShuffle() {
Dispatcher.dispatch({
type: 'TOGGLE_SHUFFLE',
});
}
export function toggleSave() {
Dispatcher.dispatch({
type: 'TOGGLE_SAVE',
});
}

View File

@@ -0,0 +1,13 @@
import Dispatcher from '../dispatcher.js';
export function load_author_data() {
Dispatcher.dispatch({
type: 'LOAD_AUTHOR_DATA',
});
}
export function remove_profile() {
Dispatcher.dispatch({
type: 'REMOVE_PROFILE',
});
}

View File

@@ -0,0 +1,8 @@
import Dispatcher from '../dispatcher.js';
export function requestPredictions(query) {
Dispatcher.dispatch({
type: 'REQUEST_PREDICTIONS',
query,
});
}

View File

@@ -0,0 +1,36 @@
import Dispatcher from '../dispatcher.js';
export function set_viewer_mode(inTheaterMode) {
Dispatcher.dispatch({
type: 'SET_VIEWER_MODE',
inTheaterMode,
});
}
export function set_player_volume(playerVolume) {
Dispatcher.dispatch({
type: 'SET_PLAYER_VOLUME',
playerVolume,
});
}
export function set_player_sound_muted(playerSoundMuted) {
Dispatcher.dispatch({
type: 'SET_PLAYER_SOUND_MUTED',
playerSoundMuted,
});
}
export function set_video_quality(quality) {
Dispatcher.dispatch({
type: 'SET_VIDEO_QUALITY',
quality,
});
}
export function set_video_playback_speed(playbackSpeed) {
Dispatcher.dispatch({
type: 'SET_VIDEO_PLAYBACK_SPEED',
playbackSpeed,
});
}

View File

@@ -0,0 +1,7 @@
export * as MediaPageActions from './MediaPageActions';
export * as PageActions from './PageActions';
export * as PlaylistPageActions from './PlaylistPageActions';
export * as PlaylistViewActions from './PlaylistViewActions';
export * as ProfilePageActions from './ProfilePageActions';
export * as SearchFieldActions from './SearchFieldActions';
export * as VideoViewerActions from './VideoViewerActions';

View File

@@ -0,0 +1,67 @@
import { logErrorAndReturnError, logWarningAndReturnError } from '../helpers/';
function supportLocalstorage() {
var mod = 'test-slug';
try {
localStorage.setItem(mod, mod);
localStorage.removeItem(mod);
return true;
} catch (e) {
return false;
}
}
export function BrowserCache(prefix, default_expire_seconds) {
var default_expire_seconds = parseInt(default_expire_seconds, 10) || 3600;
if (!supportLocalstorage) {
console.warn(['Current browser does not support localStorage.']);
}
return !prefix
? logErrorAndReturnError(['Cache object prefix is required'])
: {
prefix: prefix,
seconds: default_expire_seconds,
set: function (key, value, expire_seconds, ret) {
if (supportLocalstorage) {
expire_seconds = expire_seconds ? expire_seconds : default_expire_seconds;
if (!expire_seconds) {
ret = logWarningAndReturnError(['Invalid cache expiration value', expire_seconds]);
}
try {
localStorage.setItem(
prefix + '[' + key + ']',
JSON.stringify({
value: value,
expire: new Date().getTime() + expire_seconds * 1000,
})
);
ret = !0;
} catch (error) {
ret = logWarningAndReturnError([error]);
}
}
return ret;
},
get: function (key, ret) {
ret = supportLocalstorage ? localStorage.getItem(prefix + '[' + key + ']') : null;
ret = ret ? JSON.parse(ret) : null;
ret = null !== ret ? (void 0 !== ret.expire && ret.expire > new Date().getTime() ? ret.value : null) : ret;
return ret;
},
clear: function () {
var k;
if (supportLocalstorage && Object.keys(localStorage).length) {
for (k in localStorage) {
if (localStorage.hasOwnProperty(k)) {
if (0 === k.indexOf(prefix)) {
localStorage.removeItem(k);
}
}
}
}
return !0;
},
};
}

View File

@@ -0,0 +1,85 @@
import { isPositiveIntegerOrZero } from '../helpers/';
const _MediaDurationInfoData = {};
export class MediaDurationInfo {
constructor(seconds) {
_MediaDurationInfoData[
Object.defineProperty(this, 'id', { value: 'MediaDurationInfo_' + Object.keys(_MediaDurationInfoData).length }).id
] = {
fn: {
infoToString: function (v) {
return v < 10 ? '0' + v : v;
},
},
};
if (isPositiveIntegerOrZero(seconds)) {
this.update(seconds);
}
}
update(seconds) {
_MediaDurationInfoData[this.id].toString = void 0;
_MediaDurationInfoData[this.id].ariaLabel = void 0;
if (isPositiveIntegerOrZero(seconds)) {
_MediaDurationInfoData[this.id].days = Math.floor(seconds / 86400);
_MediaDurationInfoData[this.id].seconds = seconds % 86400;
_MediaDurationInfoData[this.id].date = _MediaDurationInfoData[this.id].seconds
? new Date(_MediaDurationInfoData[this.id].seconds * 1000)
: null;
_MediaDurationInfoData[this.id].hours = _MediaDurationInfoData[this.id].date
? 24 * _MediaDurationInfoData[this.id].days + _MediaDurationInfoData[this.id].date.getUTCHours()
: 0;
_MediaDurationInfoData[this.id].minutes = _MediaDurationInfoData[this.id].date
? _MediaDurationInfoData[this.id].date.getUTCMinutes()
: 0;
_MediaDurationInfoData[this.id].seconds = _MediaDurationInfoData[this.id].date
? _MediaDurationInfoData[this.id].date.getSeconds()
: 0;
}
}
toString() {
if (void 0 === _MediaDurationInfoData[this.id].toString) {
_MediaDurationInfoData[this.id].toString =
(0 < _MediaDurationInfoData[this.id].hours ? _MediaDurationInfoData[this.id].hours + ':' : '') +
(0 < _MediaDurationInfoData[this.id].hours && 10 > _MediaDurationInfoData[this.id].minutes ? '0' : '') +
_MediaDurationInfoData[this.id].minutes +
':' +
_MediaDurationInfoData[this.id].fn.infoToString(_MediaDurationInfoData[this.id].seconds);
}
return _MediaDurationInfoData[this.id].toString;
}
ariaLabel() {
if (void 0 === _MediaDurationInfoData[this.id].ariaLabel) {
let r = [];
if (0 < _MediaDurationInfoData[this.id].hours) {
r.push(_MediaDurationInfoData[this.id].hours + ' hours');
}
if (0 < _MediaDurationInfoData[this.id].minutes) {
r.push(_MediaDurationInfoData[this.id].minutes + ' minutes');
}
if (0 < _MediaDurationInfoData[this.id].seconds) {
r.push(_MediaDurationInfoData[this.id].seconds + ' seconds');
}
_MediaDurationInfoData[this.id].ariaLabel = r.join(', ');
}
return _MediaDurationInfoData[this.id].ariaLabel;
}
// LINK: https://en.wikipedia.org/wiki/ISO_8601#Durations
ISO8601() {
return (
'P0Y0M0DT' +
_MediaDurationInfoData[this.id].hours +
'H' +
_MediaDurationInfoData[this.id].minutes +
'M' +
_MediaDurationInfoData[this.id].seconds +
'S'
);
}
}

View File

@@ -0,0 +1,467 @@
import { formatViewsNumber, quickSort, greaterCommonDivision, addClassname, removeClassname } from '../helpers/';
import ItemsInlineSlider from '../../components/item-list/includes/itemLists/ItemsInlineSlider';
import { MediaDurationInfo } from './MediaDurationInfo';
const _MediaDurationInfo = new MediaDurationInfo();
function itemDuration(duration) {
return '<span class="more-media-duration"><span>' + duration + '</span></span>';
}
function itemThumb(img, duration) {
return img
? '<span class="more-media-item-thumb" style="background-image:url(\'' +
img +
'\');">' +
itemDuration(duration) +
'</span>'
: '';
}
function itemTitle(title) {
return '<span class="more-media-title">' + title + '</span>';
}
function itemAuthor(author) {
return '<span class="more-media-author">' + author + '</span>';
}
function itemViews(views, hideViews) {
return hideViews ? '' : '<span class="more-media-views">' + views + '</span>';
}
function itemMeta(author, views, hideViews) {
return '<span class="more-media-meta">' + itemAuthor(author) + itemViews(views, hideViews) + '</span>';
}
function itemContent(title, author, views, hideViews) {
return '<span class="more-media-item-content">' + itemTitle(title) + itemMeta(author, views, hideViews) + '</span>';
}
function generateRatiosGrids(columnsArr, rowsArr, itemsLength, viewportWidth, viewportHeight) {
let i = 0,
j,
rw,
rh,
gcd,
ret = {};
let defaultRatioWidth = 16;
let defaultRatioheight = 9;
while (i < columnsArr.length) {
j = 0;
while (j < rowsArr.length) {
rw = defaultRatioWidth * columnsArr[i];
rh = defaultRatioheight * rowsArr[j];
gcd = greaterCommonDivision(rw, rh);
if (1 < gcd) {
rw = rw / gcd;
rh = rh / gcd;
}
if (columnsArr[i] * (rowsArr[j] - 1) < itemsLength) {
ret[rw + '/' + rh] = ret[rw + '/' + rh] || { val: rw / rh, grid: [] };
ret[rw + '/' + rh].grid.push([columnsArr[i], rowsArr[j]]);
}
j += 1;
}
i += 1;
}
return ret;
}
function matchedRatioGrids(ratios, ww, wh, pw, ph, pr, itemWidthBreakpoint) {
let dist = [],
pntr = {},
ret = [];
let x, k, availableGrids;
if (3 * itemWidthBreakpoint <= pw) {
ret = 1.6 < pr ? [4, 3] : [3, 4];
} else if (1.5 * itemWidthBreakpoint >= pw) {
if (160 >= ph) {
ret = [1, 1];
} else if (320 >= ph) {
ret = [1, 2];
} else if (480 >= ph) {
ret = [1, 3];
} else if (640 >= ph) {
ret = [1, 4];
} else if (800 >= ph) {
ret = [1, 6];
} else {
ret = [1, 6];
}
} else if (2.5 * itemWidthBreakpoint >= pw) {
ret = [2, 1];
if (160 >= ph) {
ret = [2, 1];
} else if (320 >= ph) {
ret = [2, 2];
} else if (480 >= ph) {
ret = [2, 3];
} else if (640 >= ph) {
ret = [2, 4];
} else if (800 >= ph) {
ret = [2, 5];
} else {
ret = [2, 6];
}
}
if (!ret.length) {
for (k in ratios) {
if (ratios.hasOwnProperty(k)) {
x = Math.abs(pr - ratios[k].val);
dist.push(x);
pntr[x] = k;
}
}
availableGrids = ratios[pntr[quickSort(dist, 0, dist.length - 1)[0]]].grid;
if (1 < availableGrids.length) {
dist = [];
pntr = {};
k = 0;
while (k < availableGrids.length) {
x = Math.abs(pw - availableGrids[k][0] * itemWidthBreakpoint);
dist.push(x);
pntr[x] = k;
k += 1;
}
ret = availableGrids[pntr[quickSort(dist, 0, dist.length - 1)[0]]];
} else {
ret = availableGrids[0];
}
if (2 * itemWidthBreakpoint >= pw) {
ret[0] = Math.min(2, ret[0]);
} else if (3 * itemWidthBreakpoint >= pw) {
ret[0] = Math.min(3, ret[0]);
}
if (390 >= ph) {
ret[1] = Math.min(2, ret[1]);
} else if (590 >= ph) {
ret[1] = Math.min(3, ret[1]);
}
}
return ret;
}
function gridClassname(itemsLength, container) {
if (!itemsLength || !container || !container.firstChild) {
return '';
}
const ww = window.outerWidth;
const wh = window.outerHeight;
const child = container.firstChild;
const pw = child.offsetWidth;
const ph = child.offsetHeight;
const pr = pw / ph;
let ret = matchedRatioGrids(
generateRatiosGrids([1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], itemsLength, parseInt(ww, 10), parseInt(wh, 10)),
ww,
wh,
pw,
ph,
pr,
250
);
return ret.length ? ' grid-col-' + ret[0] + ' grid-row-' + ret[1] : '';
}
function buildItemsElements(itemsData, items, wrapper, inEmbed, hideViews) {
let i = 0;
while (i < itemsData.length) {
_MediaDurationInfo.update(itemsData[i].duration);
items[i] = document.createElement('div');
items[i].setAttribute('class', 'more-media-item before-more-media-item-load');
items[i].setAttribute('style', '--n: ' + i);
items[i].innerHTML =
'<a href="' +
itemsData[i].url +
'" title="' +
itemsData[i].title +
'"' +
(inEmbed ? 'target="_blank"' : '') +
'>' +
itemThumb(itemsData[i].thumbnail_url, _MediaDurationInfo.toString()) +
itemContent(
itemsData[i].title,
itemsData[i].author_name,
formatViewsNumber(itemsData[i].views) + ' ' + (1 >= itemsData[i].views ? 'view' : 'views'),
hideViews
) +
'</a>';
wrapper.appendChild(items[i]);
i += 1;
}
}
export function PlayerRecommendedMedia(itemsData, inEmbed, hideViews) {
inEmbed = inEmbed || false;
let container = null;
function updateSlider(afterItemsUpdate) {
if (!inlineSlider) {
if (!domElems.contentInner.offsetWidth) {
return;
}
inlineSlider = new ItemsInlineSlider(domElems.contentInner, '.more-media-item');
disableItemsRevealAnim();
}
inlineSlider.updateDataState(itemsData.length, true, true);
updateSliderButtonsView();
}
function disableItemsRevealAnim() {
setTimeout(function () {
let i = 0;
while (i < domElems.items.length) {
domElems.items[i].setAttribute('class', 'more-media-item');
domElems.items[i].setAttribute('style', null);
i += 1;
}
}, domElems.items.length * 75 + 200); // NOTE: 200ms is reveal animation duration and 75ms is reveal animation delay (in CSS, with class selector '.before-more-media-item-load' ).
}
function updateSliderButtonsView() {
domElems.prevSlide.style.display = inlineSlider.hasPreviousSlide() ? '' : 'none';
domElems.nextSlide.style.display = inlineSlider.hasNextSlide() ? '' : 'none';
}
function toggleInlineVisibility(ev) {
ev.preventDefault();
ev.stopPropagation();
state.openInlineMoreMedia = !state.openInlineMoreMedia;
(state.openInlineMoreMedia ? removeClassname : addClassname)(domElems.wrapper, 'hidden-inline-more-media');
updateSlider(false);
}
function clickPreviousBtn(ev) {
ev.preventDefault();
ev.stopPropagation();
inlineSlider.previousSlide();
updateSliderButtonsView();
inlineSlider.scrollToCurrentSlide();
}
function clickNextBtn(ev) {
ev.preventDefault();
ev.stopPropagation();
inlineSlider.nextSlide();
updateSliderButtonsView();
inlineSlider.scrollToCurrentSlide();
}
function wrapperClassname() {
if (null === container) {
return;
}
let ret = 'more-media';
switch (state.displayType) {
case 'full':
ret += ' full-wrapper';
break;
case 'inline-small':
ret += ' inline-slider-small';
break;
case 'inline':
ret += ' inline-slider';
break;
}
ret += state.openInlineMoreMedia ? '' : ' hidden-inline-more-media';
return ret + gridClassname(itemsData.length, container);
}
function updateWrapperParentStyle() {
switch (state.displayType) {
case 'full':
domElems.wrapper.parentNode.style.top = '';
break;
case 'inline-small':
case 'inline':
domElems.wrapper.parentNode.style.top = 'auto';
break;
}
}
function updateWrapperClassname() {
domElems.wrapper.setAttribute('class', wrapperClassname());
}
let inlineSlider;
const domElems = {
wrapper: document.createElement('div'),
title: document.createElement('h2'),
openBtn: document.createElement('button'),
closeBtn: document.createElement('button'),
prevSlide: document.createElement('div'),
nextSlide: document.createElement('div'),
prevSlideBtn: null,
nextSlideBtn: null,
content: document.createElement('div'),
contentInner: document.createElement('div'),
items: [],
};
const state = {
isInited: false,
displayType: 'inline',
openInlineMoreMedia: true,
};
domElems.title.innerHTML = 'More videos';
domElems.openBtn.innerHTML = 'More videos';
domElems.prevSlide.innerHTML =
'<button class="circle-icon-button"><span><span><i class="vjs-icon-navigate-before"></i></span></span></button>';
domElems.nextSlide.innerHTML =
'<button class="circle-icon-button"><span><span><i class="vjs-icon-navigate-next"></i></span></span></button>';
domElems.title.setAttribute('class', 'more-media-wrap-title');
domElems.openBtn.setAttribute('class', 'open-more-videos');
domElems.closeBtn.setAttribute('class', 'close-more-videos vjs-icon-close');
domElems.prevSlide.setAttribute('class', 'prev-slide');
domElems.nextSlide.setAttribute('class', 'next-slide');
domElems.content.appendChild(domElems.contentInner);
domElems.wrapper.appendChild(domElems.title);
domElems.wrapper.appendChild(domElems.openBtn);
domElems.wrapper.appendChild(domElems.closeBtn);
domElems.wrapper.appendChild(domElems.content);
domElems.content.appendChild(domElems.prevSlide);
domElems.content.appendChild(domElems.nextSlide);
domElems.prevSlideBtn = domElems.prevSlide.querySelector('button');
domElems.nextSlideBtn = domElems.nextSlide.querySelector('button');
function bindEvents() {
if (domElems.prevSlideBtn) {
domElems.prevSlideBtn.addEventListener('click', clickPreviousBtn);
}
if (domElems.nextSlideBtn) {
domElems.nextSlideBtn.addEventListener('click', clickNextBtn);
}
domElems.openBtn.addEventListener('click', toggleInlineVisibility);
domElems.closeBtn.addEventListener('click', toggleInlineVisibility);
}
function unbindEvents() {
if (domElems.prevSlideBtn) {
domElems.prevSlideBtn.removeEventListener('click', clickPreviousBtn);
}
if (domElems.nextSlideBtn) {
domElems.nextSlideBtn.removeEventListener('click', clickNextBtn);
}
domElems.openBtn.removeEventListener('click', toggleInlineVisibility);
domElems.closeBtn.removeEventListener('click', toggleInlineVisibility);
}
this.html = function () {
return domElems.wrapper;
};
this.onResize = function () {
updateWrapperClassname();
switch (state.displayType) {
case 'inline':
updateSlider(false);
break;
}
};
this.initWrappers = function (wrapper) {
container = wrapper;
updateWrapperParentStyle();
updateWrapperClassname();
};
this.init = function () {
if (!state.itemsAreBuilt) {
state.itemsAreBuilt = true;
buildItemsElements(itemsData, domElems.items, domElems.contentInner, inEmbed, hideViews);
}
switch (state.displayType) {
case 'inline':
if (inlineSlider) {
updateSlider(false);
disableItemsRevealAnim();
} else {
updateSlider(true);
}
break;
}
};
this.destroy = function () {
unbindEvents();
};
this.updateDisplayType = function (type) {
let newType, i;
switch (type) {
case 'full':
case 'inline':
case 'inline-small':
newType = type;
break;
}
if (newType && newType !== state.displayType) {
state.displayType = newType;
updateWrapperParentStyle();
updateWrapperClassname();
i = 0;
while (i < domElems.items.length) {
domElems.items[i].setAttribute('class', 'more-media-item before-more-media-item-load');
domElems.items[i].setAttribute('style', '--n: ' + i);
i += 1;
}
switch (newType) {
case 'full':
disableItemsRevealAnim();
break;
}
}
};
bindEvents();
}

View File

@@ -0,0 +1,140 @@
import { addClassname, removeClassname } from '../helpers/';
export function UpNextLoaderView(nextItemData) {
var timerTimeout;
var onTimerComplete = function () {
window.location.href = nextItemData.url;
};
var showView = function () {
removeClassname(this.vjsPlayerElem, 'vjs-mediacms-up-next-hidden');
}.bind(this);
var hideView = function () {
this.cancelTimer();
addClassname(this.vjsPlayerElem, 'vjs-mediacms-up-next-hidden');
}.bind(this);
var domElems = {
nextMediaPoster: document.createElement('div'),
wrapper: document.createElement('div'),
inner: document.createElement('div'),
innerContent: document.createElement('div'),
upNextLabel: document.createElement('div'),
nextMediaTitle: document.createElement('div'),
nextMediaAuthor: document.createElement('div'),
cancelNext: document.createElement('div'),
cancelNextButton: document.createElement('button'),
goNext: document.createElement('div'),
};
domElems.nextMediaPoster.setAttribute('class', 'next-media-poster');
domElems.wrapper.setAttribute('class', 'up-next-loader');
domElems.inner.setAttribute('class', 'up-next-loader-inner');
domElems.goNext.setAttribute('class', 'go-next');
domElems.cancelNext.setAttribute('class', 'up-next-cancel');
domElems.upNextLabel.setAttribute('class', 'up-next-label');
domElems.nextMediaTitle.setAttribute('class', 'next-media-title');
domElems.nextMediaAuthor.setAttribute('class', 'next-media-author');
domElems.upNextLabel.innerHTML = 'Up Next';
domElems.nextMediaTitle.innerHTML = nextItemData.title;
domElems.nextMediaAuthor.innerHTML = nextItemData.author_name;
domElems.goNext.innerHTML =
'<a href="' +
nextItemData.url +
'"><svg class="radial-timer"><circle r="30" cx="32" cy="32"></circle><circle r="25" cx="28" cy="28"></circle></svg><span></span><i class="material-icons">skip_next</i></a>';
domElems.cancelNextButton.innerHTML = 'CANCEL';
domElems.cancelNextButton.addEventListener('click', hideView);
domElems.nextMediaPoster.style.backgroundImage = "url('" + nextItemData.thumbnail_url + "')";
domElems.cancelNext.appendChild(domElems.cancelNextButton);
domElems.innerContent.appendChild(domElems.upNextLabel);
domElems.innerContent.appendChild(domElems.nextMediaTitle);
domElems.innerContent.appendChild(domElems.nextMediaAuthor);
domElems.innerContent.appendChild(domElems.goNext);
domElems.innerContent.appendChild(domElems.cancelNext);
domElems.inner.appendChild(domElems.innerContent);
domElems.wrapper.appendChild(domElems.nextMediaPoster);
domElems.wrapper.appendChild(domElems.inner);
var pauseTimerOnScroll = false;
function onScrollHandler() {
var rect = this.vjsPlayerElem.getBoundingClientRect();
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if (0 >= this.vjsPlayerElem.offsetHeight - 56 + rect.top) {
// NOTE: 56 pixels is the value of pages header bar height.
if (!pauseTimerOnScroll) {
this.cancelTimer(true);
}
pauseTimerOnScroll = true;
} else {
if (pauseTimerOnScroll) {
this.startTimer();
}
pauseTimerOnScroll = false;
}
}
onScrollHandler = onScrollHandler.bind(this);
function startOnScrollHandler() {
window.addEventListener('scroll', onScrollHandler);
}
function stopOnScrollHandler() {
window.removeEventListener('scroll', onScrollHandler);
}
this.vjsPlayerElem = null;
this.html = function () {
return domElems.wrapper;
};
this.startTimer = function () {
showView();
timerTimeout = setTimeout(onTimerComplete, 10 * 1000);
if (this.vjsPlayerElem) removeClassname(this.vjsPlayerElem, 'vjs-mediacms-canceled-next');
startOnScrollHandler();
};
this.cancelTimer = function (onScrollPause) {
onScrollPause = !!onScrollPause;
if (!onScrollPause) {
stopOnScrollHandler();
}
clearTimeout(timerTimeout);
timerTimeout = null;
if (this.vjsPlayerElem) addClassname(this.vjsPlayerElem, 'vjs-mediacms-canceled-next');
};
this.setVideoJsPlayerElem = function (el) {
if (!el) return;
this.vjsPlayerElem = el;
addClassname(this.vjsPlayerElem, 'vjs-mediacms-has-up-next-view');
};
this.showTimerView = function (beginTimer) {
beginTimer = !!beginTimer;
if (beginTimer) {
this.startTimer();
} else {
showView();
}
};
this.hideTimerView = function () {
hideView();
};
}

View File

@@ -0,0 +1,4 @@
export * from './BrowserCache';
export * from './MediaDurationInfo';
export * from './PlayerRecommendedMedia';
export * from './UpNextLoaderView';

View File

@@ -0,0 +1,2 @@
export { default as months } from './months';
export { default as weekdays } from './weekdays';

View File

@@ -0,0 +1,14 @@
export default [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];

View File

@@ -0,0 +1 @@
export default ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

View File

@@ -0,0 +1,5 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
export const ApiUrlContext = createContext(mediacmsConfig(window.MediaCMS).api);
export const ApiUrlConsumer = ApiUrlContext.Consumer;

View File

@@ -0,0 +1,129 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
const config = mediacmsConfig(window.MediaCMS);
const links = config.url;
const theme = config.theme;
const user = config.member;
const hasThemeSwitcher = theme.switch.enabled && 'header' === theme.switch.position;
function popupTopNavItems() {
const items = [];
if (!user.is.anonymous) {
if (user.can.addMedia) {
items.push({
link: links.user.addMedia,
icon: 'video_call',
text: 'Upload media',
itemAttr: {
className: 'visible-only-in-small',
},
});
if (user.pages.media) {
items.push({
link: user.pages.media,
icon: 'video_library',
text: 'My media',
});
}
}
items.push({
link: links.signout,
icon: 'exit_to_app',
text: 'Sign out',
});
}
return items;
}
function popupMiddleNavItems() {
const items = [];
if (hasThemeSwitcher) {
items.push({
itemType: 'open-subpage',
icon: 'brightness_4',
iconPos: 'left',
text: 'Switch theme',
buttonAttr: {
className: 'change-page',
'data-page-id': 'switch-theme',
},
});
}
if (user.is.anonymous) {
if (user.can.login) {
items.push({
itemType: 'link',
icon: 'login',
iconPos: 'left',
text: 'Sign in',
link: links.signin,
linkAttr: {
className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small',
},
});
}
if (user.can.register) {
items.push({
itemType: 'link',
icon: 'person_add',
iconPos: 'left',
text: 'Register',
link: links.register,
linkAttr: {
className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small',
},
});
}
} else {
items.push({
link: links.user.editProfile,
icon: 'brush',
text: 'Edit profile',
});
if (user.can.changePassword) {
items.push({
link: links.changePassword,
icon: 'lock',
text: 'Change password',
});
}
}
return items;
}
function popupBottomNavItems() {
const items = [];
if (user.is.admin) {
items.push({
link: links.admin,
icon: 'admin_panel_settings',
text: 'MediaCMS administration',
});
}
return items;
}
export const HeaderContext = createContext({
hasThemeSwitcher,
popupNavItems: {
top: popupTopNavItems(),
middle: popupMiddleNavItems(),
bottom: popupBottomNavItems(),
},
});
export const HeaderConsumer = HeaderContext.Consumer;

View File

@@ -0,0 +1,101 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
import { BrowserCache } from '../classes/';
import { PageStore } from '../stores/';
import { addClassname, removeClassname } from '../helpers/';
import SiteContext from './SiteContext';
let slidingSidebarTimeout;
function onSidebarVisibilityChange(visibleSidebar) {
clearTimeout(slidingSidebarTimeout);
addClassname(document.body, 'sliding-sidebar');
slidingSidebarTimeout = setTimeout(function () {
if ('media' === PageStore.get('current-page')) {
if (visibleSidebar) {
addClassname(document.body, 'overflow-hidden');
} else {
removeClassname(document.body, 'overflow-hidden');
}
} else {
if (!visibleSidebar || 767 < window.innerWidth) {
removeClassname(document.body, 'overflow-hidden');
} else {
addClassname(document.body, 'overflow-hidden');
}
}
if (visibleSidebar) {
addClassname(document.body, 'visible-sidebar');
} else {
removeClassname(document.body, 'visible-sidebar');
}
slidingSidebarTimeout = setTimeout(function () {
slidingSidebarTimeout = null;
removeClassname(document.body, 'sliding-sidebar');
}, 220);
}, 20);
}
export const LayoutContext = createContext();
export const LayoutProvider = ({ children }) => {
const site = useContext(SiteContext);
const cache = new BrowserCache('MediaCMS[' + site.id + '][layout]', 86400);
const enabledSidebar = !!(document.getElementById('app-sidebar') || document.querySelector('.page-sidebar'));
const [visibleSidebar, setVisibleSidebar] = useState(cache.get('visible-sidebar'));
const [visibleMobileSearch, setVisibleMobileSearch] = useState(false);
const toggleMobileSearch = () => {
setVisibleMobileSearch(!visibleMobileSearch);
};
const toggleSidebar = () => {
const newval = !visibleSidebar;
onSidebarVisibilityChange(newval);
setVisibleSidebar(newval);
};
useEffect(() => {
if (visibleSidebar) {
addClassname(document.body, 'visible-sidebar');
} else {
removeClassname(document.body, 'visible-sidebar');
}
if ('media' !== PageStore.get('current-page') && 1023 < window.innerWidth) {
cache.set('visible-sidebar', visibleSidebar);
}
}, [visibleSidebar]);
useEffect(() => {
PageStore.once('page_init', () => {
if ('media' === PageStore.get('current-page')) {
setVisibleSidebar(false);
removeClassname(document.body, 'visible-sidebar');
}
});
setVisibleSidebar(
'media' !== PageStore.get('current-page') &&
1023 < window.innerWidth &&
(null === visibleSidebar || visibleSidebar)
);
}, []);
const value = {
enabledSidebar,
visibleSidebar,
setVisibleSidebar,
visibleMobileSearch,
toggleMobileSearch,
toggleSidebar,
};
return <LayoutContext.Provider value={value}>{children}</LayoutContext.Provider>;
};
export const LayoutConsumer = LayoutContext.Consumer;

View File

@@ -0,0 +1,5 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
export const LinksContext = createContext(mediacmsConfig(window.MediaCMS).url);
export const LinksConsumer = LinksContext.Consumer;

View File

@@ -0,0 +1,5 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
export const MemberContext = createContext(mediacmsConfig(window.MediaCMS).member);
export const MemberConsumer = MemberContext.Consumer;

View File

@@ -0,0 +1,4 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
export const PlaylistsContext = createContext(mediacmsConfig(window.MediaCMS).playlists);

View File

@@ -0,0 +1,5 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
export const ShareOptionsContext = createContext(mediacmsConfig(window.MediaCMS).media.share.options);

View File

@@ -0,0 +1,5 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
export const SidebarContext = createContext(mediacmsConfig(window.MediaCMS).sidebar);
export const SidebarConsumer = SidebarContext.Consumer;

View File

@@ -0,0 +1,7 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
export const SiteContext = createContext(mediacmsConfig(window.MediaCMS).site);
export const SiteConsumer = SiteContext.Consumer;
export default SiteContext;

View File

@@ -0,0 +1,12 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
const notifications = mediacmsConfig(window.MediaCMS).notifications.messages;
const texts = {
notifications,
};
export const TextsContext = createContext(texts);
export const TextsConsumer = TextsContext.Consumer;

View File

@@ -0,0 +1,80 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
import { BrowserCache } from '../classes/';
import { addClassname, removeClassname, supportsSvgAsImg } from '../helpers/';
import { config as mediacmsConfig } from '../settings/config.js';
import SiteContext from './SiteContext';
const config = mediacmsConfig(window.MediaCMS);
function initLogo(logo) {
let light = null;
let dark = null;
if (void 0 !== logo.darkMode) {
if (supportsSvgAsImg() && void 0 !== logo.darkMode.svg && '' !== logo.darkMode.svg) {
dark = logo.darkMode.svg;
} else if (void 0 !== logo.darkMode.img && '' !== logo.darkMode.img) {
dark = logo.darkMode.img;
}
}
if (void 0 !== logo.lightMode) {
if (supportsSvgAsImg() && void 0 !== logo.lightMode.svg && '' !== logo.lightMode.svg) {
light = logo.lightMode.svg;
} else if (void 0 !== logo.lightMode.img && '' !== logo.lightMode.img) {
light = logo.lightMode.img;
}
}
if (null !== light || null !== dark) {
if (null === light) {
light = dark;
} else if (null === dark) {
dark = light;
}
}
return {
light,
dark,
};
}
function initMode(cachedValue, defaultValue) {
return 'light' === cachedValue || 'dark' === cachedValue ? cachedValue : defaultValue;
}
export const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const site = useContext(SiteContext);
const cache = new BrowserCache('MediaCMS[' + site.id + '][theme]', 86400);
const [themeMode, setThemeMode] = useState(initMode(cache.get('mode'), config.theme.mode));
const logos = initLogo(config.theme.logo);
const [logo, setLogo] = useState(logos[themeMode]);
const changeMode = () => {
setThemeMode('light' === themeMode ? 'dark' : 'light');
};
useEffect(() => {
if ('dark' === themeMode) {
addClassname(document.body, 'dark_theme');
} else {
removeClassname(document.body, 'dark_theme');
}
cache.set('mode', themeMode);
setLogo(logos[themeMode]);
}, [themeMode]);
const value = {
logo,
currentThemeMode: themeMode,
changeThemeMode: changeMode,
themeModeSwitcher: config.theme.switch,
};
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
};
export const ThemeConsumer = ThemeContext.Consumer;

View File

@@ -0,0 +1,22 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
export const UserContext = createContext();
const member = mediacmsConfig(window.MediaCMS).member;
export const UserProvider = ({ children }) => {
const value = {
isAnonymous: member.is.anonymous,
username: member.username,
thumbnail: member.thumbnail,
userCan: member.can,
pages: member.pages,
};
return <UserContext.Provider value={value}>{children}</UserContext.Provider>;
};
export const UserConsumer = UserContext.Consumer;
export default UserContext;

View File

@@ -0,0 +1,12 @@
export * from './ApiUrlContext';
export * from './HeaderContext';
export * from './LayoutContext';
export * from './LinksContext';
export * from './MemberContext';
export * from './PlaylistsContext';
export * from './ShareOptionsContext';
export * from './SidebarContext';
export * from './SiteContext';
export * from './TextsContext';
export * from './ThemeContext';
export * from './UserContext';

View File

@@ -0,0 +1,2 @@
const Dispatcher = require('flux').Dispatcher;
module.exports = new Dispatcher();

View File

@@ -0,0 +1,19 @@
export function csrfToken() {
var i,
cookies,
cookie,
cookieVal = null;
if (document.cookie && '' !== document.cookie) {
cookies = document.cookie.split(';');
i = 0;
while (i < cookies.length) {
cookie = cookies[i].trim();
if ('csrftoken=' === cookie.substring(0, 10)) {
cookieVal = decodeURIComponent(cookie.substring(10));
break;
}
i += 1;
}
}
return cookieVal;
}

View File

@@ -0,0 +1,79 @@
export function supportsSvgAsImg() {
// @link: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/svg/asimg.js
return document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#Image', '1.1');
}
export function removeClassname(el, cls) {
if (el.classList) {
el.classList.remove(cls);
} else {
el.className = el.className.replace(new RegExp('(^|\\b)' + cls.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
}
export function addClassname(el, cls) {
if (el.classList) {
el.classList.add(cls);
} else {
el.className += ' ' + cls;
}
}
export function hasClassname(el, cls) {
return el.className && new RegExp('(\\s|^)' + cls + '(\\s|$)').test(el.className);
}
export const cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
export const requestAnimationFrame =
window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
export function BrowserEvents() {
const callbacks = {
document: {
visibility: [],
},
window: {
resize: [],
scroll: [],
},
};
function onDocumentVisibilityChange() {
callbacks.document.visibility.map((fn) => fn());
}
function onWindowResize() {
callbacks.window.resize.map((fn) => fn());
}
function onWindowScroll() {
callbacks.window.scroll.map((fn) => fn());
}
function windowEvents(resizeCallback, scrollCallback) {
if ('function' === typeof resizeCallback) {
callbacks.window.resize.push(resizeCallback);
}
if ('function' === typeof scrollCallback) {
callbacks.window.scroll.push(scrollCallback);
}
}
function documentEvents(visibilityChangeCallback) {
if ('function' === typeof visibilityChangeCallback) {
callbacks.document.visibility.push(visibilityChangeCallback);
}
}
document.addEventListener('visibilitychange', onDocumentVisibilityChange);
window.addEventListener('resize', onWindowResize);
window.addEventListener('scroll', onWindowScroll);
return {
doc: documentEvents,
win: windowEvents,
};
}

View File

@@ -0,0 +1,27 @@
// TODO: Improve or (even better) remove this file code.
import { error as logErrFn, warn as logWarnFn } from './log';
function logAndReturnError(logFn, msgArr, ErrorConstructor) {
let err;
switch (ErrorConstructor) {
case TypeError:
case RangeError:
case SyntaxError:
case ReferenceError:
err = new ErrorConstructor(msgArr[0]);
break;
default:
err = new Error(msgArr[0]);
}
logFn(err.message, ...msgArr.slice(1));
return err;
}
export function logErrorAndReturnError(msgArr, ErrorConstructor) {
return logAndReturnError(logErrFn, msgArr, ErrorConstructor);
}
export function logWarningAndReturnError(msgArr, ErrorConstructor) {
return logAndReturnError(logWarnFn, msgArr, ErrorConstructor);
}

View File

@@ -0,0 +1,5 @@
import * as dispatcher from '../dispatcher.js';
export default function (store, handler) {
dispatcher.register(store[handler].bind(store));
return store;
}

View File

@@ -0,0 +1,11 @@
import urlParse from 'url-parse';
export function formatInnerLink(url, baseUrl) {
let link = urlParse(url, {});
if ('' === link.origin || 'null' === link.origin || !link.origin) {
link = urlParse(baseUrl + '/' + url.replace(/^\//g, ''), {});
}
return link.toString();
}

View File

@@ -0,0 +1,15 @@
import { months as monthList } from '../constants/';
export function formatManagementTableDate(date) {
const day = date.getDate();
const month = monthList[date.getMonth()].substring(0, 3);
const year = date.getFullYear();
const hours = date.getHours();
const minutes = date.getMinutes();
const seconds = date.getSeconds();
let ret = month + ' ' + day + ', ' + year;
ret += ' ' + (hours < 10 ? '0' : '') + hours;
ret += ':' + (minutes < 10 ? '0' : '') + minutes;
ret += ':' + (seconds < 10 ? '0' : '') + seconds;
return ret;
}

View File

@@ -0,0 +1,18 @@
export default function (views_number, fullNumber) {
function formattedValue(val, lim, unit) {
return Number(parseFloat(val / lim).toFixed(val < 10 * lim ? 1 : 0)) + unit;
}
function format(i, views, mult, compare, limit, units) {
while (views >= compare) {
limit *= mult;
compare *= mult;
i += 1;
}
return i < units.length
? formattedValue(views, limit, units[i])
: formattedValue(views * (mult * (i - (units.length - 1))), limit, units[units.length - 1]);
}
return fullNumber ? views_number.toLocaleString() : format(0, views_number, 1000, 1000, 1, ['', 'K', 'M', 'B', 'T']);
}

View File

@@ -0,0 +1,7 @@
export const imageExtension = (img) => {
if (!img) {
return;
}
const ext = img.split('.');
return ext[ext.length - 1];
};

View File

@@ -0,0 +1,14 @@
export * from './dom';
export * from './errors';
export { default as exportStore } from './exportStore';
export { formatInnerLink } from './formatInnerLink';
export * from './formatManagementTableDate';
export { default as formatViewsNumber } from './formatViewsNumber';
export * from './csrfToken';
export { imageExtension } from './imageExtension';
export * from './log';
export * from './math';
export * from './propTypeFilters';
export { default as publishedOnDate } from './publishedOnDate';
export * from './quickSort';
export * from './requests';

View File

@@ -0,0 +1,4 @@
const log = (...x) => console[x[0]](...x.slice(1));
export const warn = (...x) => log('warn', ...x);
export const error = (...x) => log('error', ...x);

View File

@@ -0,0 +1,10 @@
export const isGt = (x, y) => x > y;
export const isZero = (x) => 0 === x;
export const isNumber = (x) => !isNaN(x) && x === 0 + x;
export const isInteger = (x) => x === Math.trunc(x);
export const isPositive = (x) => isGt(x, 0);
export const isPositiveNumber = (x) => isNumber(x) && isPositive(x);
export const isPositiveInteger = (x) => isInteger(x) && isPositive(x);
export const isPositiveIntegerOrZero = (x) => isInteger(x) && (isPositive(x) || isZero(x));
export const greaterCommonDivision = (a, b) => (!b ? a : greaterCommonDivision(b, a % b));

View File

@@ -0,0 +1,38 @@
import { logErrorAndReturnError } from './errors';
import { isPositiveInteger, isPositiveIntegerOrZero } from './math';
export const PositiveIntegerOrZero = (function () {
return function (obj, key, comp) {
return void 0 === obj[key] || isPositiveIntegerOrZero(obj[key])
? null
: logErrorAndReturnError([
'Invalid prop `' +
key +
'` of type `' +
typeof obj[key] +
'` supplied to `' +
(comp || 'N/A') +
'`, expected `positive integer or zero` (' +
obj[key] +
').',
]);
};
})();
export const PositiveInteger = (function () {
return function (obj, key, comp) {
return void 0 === obj[key] || isPositiveInteger(obj[key])
? null
: logErrorAndReturnError([
'Invalid prop `' +
key +
'` of type `' +
typeof obj[key] +
'` supplied to `' +
(comp || 'N/A') +
'`, expected `positive integer` (' +
obj[key] +
').',
]);
};
})();

View File

@@ -0,0 +1,17 @@
import { months } from '../constants';
export default function publishedOnDate(date, type) {
if (date instanceof Date) {
type = 0 + type;
type = 0 < type ? type : 1;
switch (type) {
case 1:
return months[date.getMonth()].substring(0, 3) + ' ' + date.getDate() + ', ' + date.getFullYear();
case 2:
return date.getDate() + ' ' + months[date.getMonth()].substring(0, 3) + ' ' + date.getFullYear();
case 3:
return date.getDate() + ' ' + months[date.getMonth()] + ' ' + date.getFullYear();
}
}
return null;
}

View File

@@ -0,0 +1,35 @@
function swap(arr, i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function partition(arr, pivot, left, right) {
var pivotValue = arr[pivot],
partitionIndex = left;
for (var i = left; i < right; i++) {
if (arr[i] < pivotValue) {
swap(arr, i, partitionIndex);
partitionIndex++;
}
}
swap(arr, right, partitionIndex);
return partitionIndex;
}
export function quickSort(arr, left, right) {
var len = arr.length,
pivot,
partitionIndex;
if (left < right) {
pivot = right;
partitionIndex = partition(arr, pivot, left, right);
//sort left and right
quickSort(arr, left, partitionIndex - 1);
quickSort(arr, partitionIndex + 1, right);
}
return arr;
}

View File

@@ -0,0 +1,135 @@
import axios, { get as axiosGet, post as axiosPost, put as axiosPut } from 'axios';
export async function getRequest(url, sync, callback, errorCallback) {
const requestConfig = {
timeout: null,
maxContentLength: null,
};
function responseHandler(result) {
if (callback instanceof Function) {
callback(result);
}
}
function errorHandler(error) {
if (errorCallback instanceof Function) {
let err = error;
if (void 0 === error.response) {
err = {
type: 'network',
error: error,
};
} else if (void 0 !== error.response.status) {
// TODO: Improve this, it's valid only in case of media requests.
switch (error.response.status) {
case 401:
err = {
type: 'private',
error: error,
message: 'Media is private',
};
break;
case 400:
err = {
type: 'unavailable',
error: error,
message: 'Media is unavailable',
};
break;
}
}
errorCallback(err);
}
}
if (sync) {
await axiosGet(url, requestConfig)
.then(responseHandler)
.catch(errorHandler || null);
} else {
axiosGet(url, requestConfig)
.then(responseHandler)
.catch(errorHandler || null);
}
}
export async function postRequest(url, postData, configData, sync, callback, errorCallback) {
postData = postData || {};
function responseHandler(result) {
if (callback instanceof Function) {
callback(result);
}
}
function errorHandler(error) {
if (errorCallback instanceof Function) {
errorCallback(error);
}
}
if (sync) {
await axiosPost(url, postData, configData || null)
.then(responseHandler)
.catch(errorHandler || null);
} else {
axiosPost(url, postData, configData || null)
.then(responseHandler)
.catch(errorHandler || null);
}
}
export async function putRequest(url, putData, configData, sync, callback, errorCallback) {
putData = putData || {};
function responseHandler(result) {
if (callback instanceof Function) {
callback(result);
}
}
function errorHandler(error) {
if (errorCallback instanceof Function) {
errorCallback(error);
}
}
if (sync) {
await axiosPut(url, putData, configData || null)
.then(responseHandler)
.catch(errorHandler || null);
} else {
axiosPut(url, putData, configData || null)
.then(responseHandler)
.catch(errorHandler || null);
}
}
export async function deleteRequest(url, configData, sync, callback, errorCallback) {
configData = configData || {};
function responseHandler(result) {
if (callback instanceof Function) {
callback(result);
}
}
function errorHandler(error) {
if (errorCallback instanceof Function) {
errorCallback(error);
}
}
if (sync) {
await axios
.delete(url, configData || null)
.then(responseHandler)
.catch(errorHandler || null);
} else {
axios
.delete(url, configData || null)
.then(responseHandler)
.catch(errorHandler || null);
}
}

View File

@@ -0,0 +1,12 @@
export * from './useItem';
export * from './useItemList';
export * from './useItemListInlineSlider';
export * from './useItemListLazyLoad';
export * from './useItemListSync';
export * from './useLayout';
export * from './useManagementTableHeader';
export * from './useMediaFilter';
export * from './useMediaItem';
export * from './usePopup';
export * from './useTheme';
export * from './useUser';

View File

@@ -0,0 +1,60 @@
import React, { useState, useEffect } from 'react';
import { formatInnerLink } from '../helpers/';
import {
ItemDescription,
ItemMain,
ItemMainInLink,
ItemTitle,
ItemTitleLink,
} from '../../components/list-item/includes/items';
import PageStore from '../stores/PageStore.js';
export function useItem(props) {
const [duration, setDuration] = useState('');
const [publishDate, setPublishDate] = useState('');
const [publishDateTime, setPublishDateTime] = useState('');
const itemType = props.type;
const UnderThumbWrapper = props.singleLinkContent ? ItemMainInLink : ItemMain;
const thumbnailUrl =
'' === props.thumbnail ? null : formatInnerLink(props.thumbnail, PageStore.get('config-site').url);
function titleComponent() {
let ariaLabel = props.title;
if ('' !== publishDate) {
ariaLabel += ' ' + publishDate;
}
if ('' !== duration) {
ariaLabel += ' ' + duration;
}
if (props.singleLinkContent) {
return <ItemTitle title={props.title} ariaLabel={ariaLabel} />;
}
return <ItemTitleLink title={props.title} ariaLabel={ariaLabel} link={props.link} />;
}
function descriptionComponent() {
if (props.hasMediaViewer && props.hasMediaViewerDescr) {
return [
<ItemDescription key="1" description={props.meta_description ? props.meta_description.trim() : ' '} />,
<ItemDescription key="2" description={props.description ? props.description.trim() : ' '} />,
];
}
return <ItemDescription description={props.description.trim()} />;
}
useEffect(() => {
if (void 0 !== props.onMount) {
props.onMount();
}
}, []);
return { titleComponent, descriptionComponent, thumbnailUrl, UnderThumbWrapper };
}

View File

@@ -0,0 +1,57 @@
import React, { useState, useEffect } from 'react';
import initItemsList from '../../components/item-list/includes/itemLists/initItemsList';
import '../../components/item-list/ItemList.scss'; // TODO: Remove it from here
export function useItemList(props, itemsListRef) {
let previousItemsLength = 0;
let itemsListInstance = null;
const [items, setItems] = useState([]);
const [countedItems, setCountedItems] = useState(false);
const [listHandler, setListHandler] = useState(null);
function onItemsLoad(itemsArray) {
setItems([...itemsArray]);
}
function onItemsCount(totalItems) {
setCountedItems(true);
if (void 0 !== props.itemsCountCallback) {
props.itemsCountCallback(totalItems);
}
}
function addListItems() {
if (previousItemsLength < items.length) {
if (null === itemsListInstance) {
itemsListInstance = initItemsList([itemsListRef.current])[0];
}
// TODO: Should get item elements from children components.
const itemsElem = itemsListRef.current.querySelectorAll('.item');
if (!itemsElem || !itemsElem.length) {
return;
}
let i = previousItemsLength;
while (i < items.length) {
itemsListInstance.appendItems(itemsElem[i]);
i += 1;
}
previousItemsLength = items.length;
}
}
useEffect(() => {
if (void 0 !== props.itemsLoadCallback) {
props.itemsLoadCallback();
}
}, [items]);
return [items, countedItems, listHandler, setListHandler, onItemsLoad, onItemsCount, addListItems];
}

View File

@@ -0,0 +1,190 @@
import React, { useState, useEffect, useRef } from 'react';
import { addClassname, removeClassname } from '../helpers/';
import { CircleIconButton } from '../../components/_shared';
import ItemsInlineSlider from '../../components/item-list/includes/itemLists/ItemsInlineSlider';
import { useItemList } from './useItemList';
export function useItemListInlineSlider(props) {
const itemsListRef = useRef(null);
const itemsListWrapperRef = useRef(null);
const [items, countedItems, listHandler, setListHandler, onItemsLoad, onItemsCount, addListItems] = useItemList(
props,
itemsListRef
);
const [inlineSlider, setInlineSlider] = useState(null);
const [displayNext, setDisplayNext] = useState(false);
const [displayPrev, setDisplayPrev] = useState(false);
const [resizeDate, setResizeDate] = useState(null);
const [sidebarVisibilityChangeDate, setSidebarVisibilityChangeDate] = useState(null);
let resizeTimeout = null;
let sliderRecalTimeout = null;
let pendingChangeSlide = true; // NOTE: Allow to run method `this.inlineSlider.scrollToCurrentSlide()` on object `this.inlineSlider` initialization.
let classname = {
list: 'items-list',
listOuter: 'items-list-outer list-inline list-slider' + (!!props.className ? ' ' + props.className : ''),
};
function afterItemsLoad() {
updateSlider(true);
}
function renderBeforeListWrap() {
return !displayPrev ? null : (
<span className="previous-slide">
<CircleIconButton buttonShadow={true} onClick={prevSlide}>
<i className="material-icons">keyboard_arrow_left</i>
</CircleIconButton>
</span>
);
}
function renderAfterListWrap() {
return !displayNext ? null : (
<span className="next-slide">
<CircleIconButton buttonShadow={true} onClick={nextSlide}>
<i className="material-icons">keyboard_arrow_right</i>
</CircleIconButton>
</span>
);
}
function winResizeListener() {
setResizeDate(new Date());
}
function sidebarVisibilityChangeListener() {
setSidebarVisibilityChangeDate(new Date());
}
function onWinResize() {
// 767 < window.innerWidth ||
if (null === inlineSlider) {
updateSlider(false);
return;
}
clearTimeout(resizeTimeout);
addClassname(itemsListWrapperRef.current, 'resizing');
inlineSlider.updateDataStateOnResize(items.length, listHandler.loadedAllItems());
inlineSlider.scrollToCurrentSlide();
resizeTimeout = setTimeout(onWinResizeUpdate, 200);
}
function onWinResizeUpdate() {
inlineSlider.updateDataStateOnResize(items.length, listHandler.loadedAllItems());
inlineSlider.scrollToCurrentSlide();
removeClassname(itemsListWrapperRef.current, 'resizing');
resizeTimeout = null;
}
function onSidebarVisibilityChange() {
clearTimeout(sliderRecalTimeout);
sliderRecalTimeout = setTimeout(function () {
updateSliderButtonsView();
sliderRecalTimeout = setTimeout(function () {
sliderRecalTimeout = null;
updateSlider();
}, 50);
}, 150); // NOTE: 200ms is transition duration, set in CSS.
}
function nextSlide() {
inlineSlider.nextSlide();
updateSliderButtonsView();
if (!listHandler.loadedAllItems() && inlineSlider.loadMoreItems()) {
pendingChangeSlide = true;
listHandler.loadItems(inlineSlider.itemsFit());
} else {
inlineSlider.scrollToCurrentSlide();
}
}
function prevSlide() {
inlineSlider.previousSlide();
updateSliderButtonsView();
inlineSlider.scrollToCurrentSlide();
}
function initSlider() {
if (!itemsListWrapperRef.current) {
return;
}
setInlineSlider(new ItemsInlineSlider(itemsListWrapperRef.current, '.item'));
}
function updateSlider(afterItemsUpdate) {
if (null === inlineSlider) {
initSlider();
return;
}
inlineSlider.updateDataState(items.length, listHandler.loadedAllItems(), !afterItemsUpdate);
if (!listHandler.loadedAllItems() && inlineSlider.loadItemsToFit()) {
listHandler.loadItems(inlineSlider.itemsFit());
} else {
updateSliderButtonsView();
if (pendingChangeSlide) {
pendingChangeSlide = false;
inlineSlider.scrollToCurrentSlide();
}
}
}
function updateSliderButtonsView() {
if (!inlineSlider) {
return;
}
setDisplayNext(inlineSlider.hasNextSlide());
setDisplayPrev(inlineSlider.hasPreviousSlide());
}
useEffect(() => {
addListItems();
afterItemsLoad();
}, [items]);
useEffect(() => {
updateSlider(true);
}, [inlineSlider]);
useEffect(() => {
onWinResize();
}, [resizeDate]);
useEffect(() => {
onSidebarVisibilityChange();
}, [sidebarVisibilityChangeDate]);
return [
items,
countedItems,
listHandler,
classname,
setListHandler,
onItemsCount,
onItemsLoad,
winResizeListener,
sidebarVisibilityChangeListener,
itemsListWrapperRef,
itemsListRef,
renderBeforeListWrap,
renderAfterListWrap,
];
}

View File

@@ -0,0 +1,82 @@
import React, { useState, useEffect, useRef } from 'react';
import { PageStore } from '../stores/';
import { useItemList } from './useItemList';
export function useItemListLazyLoad(props) {
const itemsListRef = useRef(null);
const itemsListWrapperRef = useRef(null);
const [items, countedItems, listHandler, setListHandler, onItemsLoad, onItemsCount, addListItems] = useItemList(
props,
itemsListRef
);
const [topScroll, setTopScroll] = useState(window.scrollY + 2 * window.outerHeight);
let classname = {
list: 'items-list',
listOuter: 'items-list-outer' + ('string' === typeof props.className ? ' ' + props.className.trim() : ''),
};
function afterItemsLoad() {
if (null === itemsListRef.current) {
return;
}
onWindowScroll();
if (listHandler.loadedAllItems()) {
PageStore.removeListener('window_scroll', onWindowScroll);
}
}
function renderBeforeListWrap() {
return null;
}
function renderAfterListWrap() {
return null;
}
function onWindowScroll() {
setTopScroll(window.scrollY + 2 * window.outerHeight);
}
function onDocumentVisibilityChange() {
if (!document.hidden) {
// NOTE: The delay fixes the problem that occurs when the list loads within a non-focused browser's tab.
setTimeout(onWindowScroll, 10);
}
}
useEffect(() => {
addListItems();
afterItemsLoad();
}, [items]);
useEffect(() => {
if (null === itemsListRef.current || null === listHandler) {
return;
}
if (topScroll >= itemsListRef.current.offsetTop + itemsListRef.current.offsetHeight) {
listHandler.loadItems();
}
}, [items, topScroll]);
return [
items,
countedItems,
listHandler,
setListHandler,
classname,
onItemsCount,
onItemsLoad,
onWindowScroll,
onDocumentVisibilityChange,
itemsListWrapperRef,
itemsListRef,
renderBeforeListWrap,
renderAfterListWrap,
];
}

View File

@@ -0,0 +1,58 @@
import React, { useEffect, useRef } from 'react';
import { useItemList } from './useItemList';
export function useItemListSync(props) {
const itemsListRef = useRef(null);
const itemsListWrapperRef = useRef(null);
const [items, countedItems, listHandler, setListHandler, onItemsLoad, onItemsCount, addListItems] = useItemList(
props,
itemsListRef
);
let classname = {
list: 'items-list',
listOuter: 'items-list-outer' + ('string' === typeof props.className ? ' ' + props.className.trim() : ''),
};
function onClickLoadMore() {
listHandler.loadItems();
}
function afterItemsLoad() { }
function renderBeforeListWrap() {
return null;
}
function renderAfterListWrap() {
if (!listHandler) {
return null;
}
return 1 > listHandler.totalPages() || listHandler.loadedAllItems() ? null : (
<button className="load-more" onClick={onClickLoadMore}>
SHOW MORE
</button>
);
}
useEffect(() => {
addListItems();
afterItemsLoad();
}, [items]);
return [
countedItems,
items,
listHandler,
setListHandler,
classname,
itemsListWrapperRef,
itemsListRef,
onItemsCount,
onItemsLoad,
renderBeforeListWrap,
renderAfterListWrap,
];
}

View File

@@ -0,0 +1,4 @@
import React, { useContext } from 'react';
import { LayoutContext } from '../contexts/';
export const useLayout = () => useContext(LayoutContext);

View File

@@ -0,0 +1,45 @@
import React, { useState, useEffect } from 'react';
export function useManagementTableHeader(props) {
const [sort, setSort] = useState(props.sort);
const [order, setOrder] = useState(props.order);
const [isSelected, setIsSelected] = useState(props.selected);
function sortByColumn(ev) {
const colId = ev.currentTarget.getAttribute('id');
const newSort = colId;
const newOrder = sort === colId ? ('desc' === order ? 'asc' : 'desc') : 'desc';
setSort(newSort);
setOrder(newOrder);
if (void 0 !== props.onClickColumnSort) {
props.onClickColumnSort(newSort, newOrder);
}
}
function checkAll() {
const newSelected = !isSelected;
setIsSelected(!newSelected);
if (void 0 !== props.onCheckAllRows) {
props.onCheckAllRows(newSelected, props.type);
}
}
useEffect(() => {
setSort(props.sort);
}, [props.sort]);
useEffect(() => {
setOrder(props.order);
}, [props.order]);
useEffect(() => {
setIsSelected(props.selected);
}, [props.selected]);
return [sort, order, isSelected, sortByColumn, checkAll];
}

View File

@@ -0,0 +1,9 @@
import React, { useRef, useState } from 'react';
import { usePopup } from './usePopup';
export function useMediaFilter(initialValue) {
const containerRef = useRef(null);
const [value, setValue] = useState(initialValue);
const [popupContentRef, PopupContent, PopupTrigger] = usePopup();
return [containerRef, value, setValue, popupContentRef, PopupContent, PopupTrigger];
}

View File

@@ -0,0 +1,79 @@
import React from 'react';
import { format } from 'timeago.js';
import { formatInnerLink } from '../helpers/';
import { PageStore } from '../stores/';
import {
MediaItemAuthor,
MediaItemAuthorLink,
MediaItemMetaViews,
MediaItemMetaDate,
MediaItemEditLink,
} from '../../components/list-item/includes/items';
import { useItem } from './useItem';
export function itemClassname(defaultClassname, inheritedClassname, isActiveInPlaylistPlayback) {
let classname = defaultClassname;
if ('' !== inheritedClassname) {
classname += ' ' + inheritedClassname;
}
if (isActiveInPlaylistPlayback) {
classname += ' pl-active-item';
}
return classname;
}
export function useMediaItem(props) {
const { titleComponent, descriptionComponent, thumbnailUrl, UnderThumbWrapper } = useItem({ ...props });
function editMediaComponent() {
return <MediaItemEditLink link={props.editLink} />;
}
function authorComponent() {
if (props.hideAuthor) {
return null;
}
if (props.singleLinkContent) {
return <MediaItemAuthor name={props.author_name} />;
}
const authorUrl =
'' === props.author_link ? null : formatInnerLink(props.author_link, PageStore.get('config-site').url);
return <MediaItemAuthorLink name={props.author_name} link={authorUrl} />;
}
function viewsComponent() {
return props.hideViews ? null : <MediaItemMetaViews views={props.views} />;
}
function dateComponent() {
if (props.hideDate) {
return null;
}
const publishDate = format(new Date(props.publish_date));
const publishDateTime =
'string' === typeof props.publish_date
? Date.parse(props.publish_date)
: Date.parse(new Date(props.publish_date));
return <MediaItemMetaDate time={props.publish_date} dateTime={publishDateTime} text={publishDate} />;
}
function metaComponents() {
return props.hideAllMeta ? null : (
<span className="item-meta">
{authorComponent()}
{viewsComponent()}
{dateComponent()}
</span>
);
}
return [titleComponent, descriptionComponent, thumbnailUrl, UnderThumbWrapper, editMediaComponent, metaComponents];
}

View File

@@ -0,0 +1,9 @@
import React, { useRef } from 'react';
import { PopupContent } from '../../components/_shared/popup/PopupContent.jsx';
import { PopupTrigger } from '../../components/_shared/popup/PopupTrigger.jsx';
export function usePopup() {
const popupContentRef = useRef(null);
return [popupContentRef, PopupContent, PopupTrigger];
}

View File

@@ -0,0 +1,4 @@
import React, { useContext } from 'react';
import { ThemeContext } from '../contexts/';
export const useTheme = () => useContext(ThemeContext);

View File

@@ -0,0 +1,4 @@
import React, { useContext } from 'react';
import UserContext from '../contexts/UserContext';
export const useUser = () => useContext(UserContext);

View File

@@ -0,0 +1,66 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { ThemeProvider } from './contexts/ThemeContext';
import { LayoutProvider } from './contexts/LayoutContext';
import { UserProvider } from './contexts/UserContext';
const AppProviders = ({ children }) => (
<LayoutProvider>
<ThemeProvider>
<UserProvider>{children}</UserProvider>
</ThemeProvider>
</LayoutProvider>
);
import { PageHeader, PageSidebar } from '../components/page-layout';
export function renderPage(idSelector, PageComponent) {
const appHeader = document.getElementById('app-header');
const appSidebar = document.getElementById('app-sidebar');
const appContent = idSelector ? document.getElementById(idSelector) : undefined;
if (appContent && PageComponent) {
ReactDOM.render(
<AppProviders>
{appHeader ? ReactDOM.createPortal(<PageHeader />, appHeader) : null}
{appSidebar ? ReactDOM.createPortal(<PageSidebar />, appSidebar) : null}
<PageComponent />
</AppProviders>,
appContent
);
} else if (appHeader && appSidebar) {
ReactDOM.render(
<AppProviders>
{ReactDOM.createPortal(<PageHeader />, appHeader)}
<PageSidebar />
</AppProviders>,
appSidebar
);
} else if (appHeader) {
ReactDOM.render(
<LayoutProvider>
<ThemeProvider>
<UserProvider>
<PageHeader />
</UserProvider>
</ThemeProvider>
</LayoutProvider>,
appSidebar
);
} else if (appSidebar) {
ReactDOM.render(
<AppProviders>
<PageSidebar />
</AppProviders>,
appSidebar
);
}
}
export function renderEmbedPage(idSelector, PageComponent) {
const appContent = idSelector ? document.getElementById(idSelector) : undefined;
if (appContent && PageComponent) {
ReactDOM.render(<PageComponent />, appContent);
}
}

View File

@@ -0,0 +1,59 @@
const urlParse = require('url-parse');
let BASE_URL = null;
let ENDPOINTS = null;
function endpointsIter(ret, endpoints) {
const baseUrl = BASE_URL.toString().replace(/\/+$/, '');
for (let k in endpoints) {
if ('string' === typeof endpoints[k]) {
ret[k] = baseUrl + '/' + endpoints[k].replace(/^\//g, '');
} else {
endpointsIter(ret[k], endpoints[k]);
}
}
}
function formatEndpoints(endpoints) {
const baseUrl = BASE_URL.toString();
const ret = endpoints;
endpointsIter(ret, endpoints);
return ret;
}
export function init(base_url, endpoints) {
BASE_URL = urlParse(base_url);
ENDPOINTS = formatEndpoints({
media: endpoints.media,
featured: endpoints.media + '?show=featured',
recommended: endpoints.media + '?show=recommended',
playlists: endpoints.playlists,
users: endpoints.members,
user: {
liked: endpoints.liked,
history: endpoints.history,
playlists: endpoints.playlists + '?author=',
},
archive: {
tags: endpoints.tags,
categories: endpoints.categories,
},
manage: {
media: endpoints.manage_media,
users: endpoints.manage_users,
comments: endpoints.manage_comments,
},
search: {
query: endpoints.search + '?q=',
titles: endpoints.search + '?show=titles&q=',
tag: endpoints.search + '?t=',
category: endpoints.search + '?c=',
},
});
}
export function endpoints() {
return ENDPOINTS;
}

View File

@@ -0,0 +1,109 @@
import * as api from './api.js';
import * as media from './media.js';
import * as site from './site.js';
import * as theme from './theme.js';
import * as url from './url.js';
import * as member from './member.js';
import * as contents from './contents.js';
import * as pages from './pages.js';
import * as sidebar from './sidebar.js';
import * as taxonomies from './taxonomies.js';
import * as optionsPages from './optionsPages.js';
import * as optionsEmbedded from './optionsEmbedded.js';
import * as playlists from './playlists.js';
import * as notifications from './notifications.js';
let DATA = null;
export function config(glbl) {
if (DATA) {
return DATA;
}
pages.init({ ...glbl.site.pages, ...glbl.site.userPages });
optionsPages.init(glbl.pages.home, glbl.pages.search, glbl.pages.media, glbl.pages.profile, pages.settings());
url.init({
home: glbl.url.home,
admin: !glbl.user.is.anonymous && glbl.user.is.admin ? glbl.url.admin : '',
error404: glbl.url.error404,
embed: glbl.site.url.replace(/\/+$/, '') + '/embed?m=',
latest: glbl.url.latestMedia,
featured: glbl.url.featuredMedia,
recommended: glbl.url.recommendedMedia,
signin: glbl.url.signin,
signout: !glbl.user.is.anonymous ? glbl.url.signout : '',
register: glbl.url.register,
changePassword: !glbl.user.is.anonymous ? glbl.url.changePassword : '',
members: glbl.url.members,
search: {
base: glbl.url.search,
query: glbl.url.search + '?q=',
tag: glbl.url.search + '?t=',
category: glbl.url.search + '?c=',
},
profile: !!glbl.site.devEnv
? {
media: glbl.user.pages.media,
about: glbl.user.pages.about,
playlists: glbl.user.pages.playlists,
}
: {
media: glbl.site.url.replace(/\/$/, '') + '/user/' + glbl.profileId,
about: glbl.site.url.replace(/\/$/, '') + '/user/' + glbl.profileId + '/about',
playlists: glbl.site.url.replace(/\/$/, '') + '/user/' + glbl.profileId + '/playlists',
},
user: {
liked: glbl.url.likedMedia,
history: glbl.url.history,
addMedia: glbl.url.addMedia,
editChannel: glbl.url.editChannel,
editProfile: glbl.url.editProfile,
},
archive: {
tags: glbl.url.tags,
categories: glbl.url.categories,
},
manage: {
media: !glbl.user.is.anonymous ? glbl.url.manageMedia : '',
users: !glbl.user.is.anonymous ? glbl.url.manageUsers : '',
comments: !glbl.user.is.anonymous ? glbl.url.manageComments : '',
},
});
site.init(glbl.site);
contents.init(glbl.contents);
api.init(glbl.site.api, glbl.api);
sidebar.init(glbl.features.sideBar);
taxonomies.init(glbl.site.taxonomies);
member.init(glbl.user, glbl.features);
theme.init(glbl.site.theme, glbl.site.logo);
optionsEmbedded.init(glbl.features.embeddedVideo);
media.init(glbl.features.mediaItem, glbl.features.media.shareOptions);
playlists.init(glbl.features.playlists);
notifications.init(glbl.contents.notifications);
DATA = {
site: site.settings(),
theme: theme.settings(),
member: member.settings(),
media: media.settings(),
playlists: playlists.settings(),
url: url.pages(),
api: api.endpoints(),
sidebar: sidebar.settings(),
contents: contents.settings(),
options: {
pages: optionsPages.settings(),
embedded: optionsEmbedded.settings(),
},
enabled: {
pages: pages.settings(),
taxonomies: taxonomies.settings(),
},
notifications: notifications.settings(),
};
return DATA;
}

View File

@@ -0,0 +1,121 @@
let CONTENTS = null;
function headerContents(contents) {
const ret = {
right: '',
onLogoRight: '',
};
if (void 0 !== contents) {
if ('string' === typeof contents.right) {
ret.right = contents.right.trim();
}
if ('string' === typeof contents.onLogoRight) {
ret.onLogoRight = contents.onLogoRight.trim();
}
}
return ret;
}
function sidebarContents(contents) {
const ret = {
navMenu: {
items: [],
},
mainMenuExtra: {
items: [],
},
belowNavMenu: '',
belowThemeSwitcher: '',
footer: '',
};
if (undefined !== contents) {
if (undefined !== contents.mainMenuExtraItems) {
let i = 0;
while (i < contents.mainMenuExtraItems.length) {
if (
'string' === typeof contents.mainMenuExtraItems[i].text &&
'string' === typeof contents.mainMenuExtraItems[i].link &&
'string' === typeof contents.mainMenuExtraItems[i].icon
) {
ret.mainMenuExtra.items.push({
text: contents.mainMenuExtraItems[i].text,
link: contents.mainMenuExtraItems[i].link,
icon: contents.mainMenuExtraItems[i].icon,
className: contents.mainMenuExtraItems[i].className,
});
}
i += 1;
}
}
if (undefined !== contents.navMenuItems) {
let i = 0;
while (i < contents.navMenuItems.length) {
if (
'string' === typeof contents.navMenuItems[i].text &&
'string' === typeof contents.navMenuItems[i].link &&
'string' === typeof contents.navMenuItems[i].icon
) {
ret.navMenu.items.push({
text: contents.navMenuItems[i].text,
link: contents.navMenuItems[i].link,
icon: contents.navMenuItems[i].icon,
className: contents.navMenuItems[i].className,
});
}
i += 1;
}
}
if ('string' === typeof contents.belowNavMenu) {
ret.belowNavMenu = contents.belowNavMenu.trim();
}
if ('string' === typeof contents.belowThemeSwitcher) {
ret.belowThemeSwitcher = contents.belowThemeSwitcher.trim();
}
if ('string' === typeof contents.footer) {
ret.footer = contents.footer.trim();
}
}
return ret;
}
function uploaderContents(contents) {
const ret = {
belowUploadArea: '',
postUploadMessage: '',
};
if (void 0 !== contents) {
if ('string' === typeof contents.belowUploadArea) {
ret.belowUploadArea = contents.belowUploadArea.trim();
}
if ('string' === typeof contents.postUploadMessage) {
ret.postUploadMessage = contents.postUploadMessage.trim();
}
}
return ret;
}
export function init(contents) {
CONTENTS = {
header: headerContents(contents.header),
sidebar: sidebarContents(contents.sidebar),
uploader: uploaderContents(contents.uploader),
};
}
export function settings() {
return CONTENTS;
}

View File

@@ -0,0 +1,59 @@
let MEDIA = null;
export function init(item, shareOptions) {
MEDIA = {
item: {
displayAuthor: true,
displayViews: true,
displayPublishDate: true,
},
share: {
options: [],
},
};
if (void 0 !== item) {
if (true === item.hideAuthor) {
MEDIA.item.displayAuthor = false;
}
if (true === item.hideViews) {
MEDIA.item.displayViews = false;
}
if (true === item.hideDate) {
MEDIA.item.displayPublishDate = false;
}
}
if (void 0 !== shareOptions) {
const validShareOptions = [
'embed',
'fb',
'tw',
'whatsapp',
'telegram',
'reddit',
'tumblr',
'vk',
'pinterest',
'mix',
'linkedin',
'email',
];
let i = 0;
while (i < shareOptions.length) {
if (-1 < validShareOptions.indexOf(shareOptions[i])) {
MEDIA.share.options.push(shareOptions[i]);
}
i += 1;
}
}
}
export function settings() {
return MEDIA;
}

View File

@@ -0,0 +1,128 @@
let MEMBER = null;
export function init(user, features) {
MEMBER = {
name: null,
username: null,
thumbnail: null,
is: {
admin: false,
anonymous: true,
},
can: {
login: true,
register: true,
addMedia: false,
editProfile: false,
changePassword: true,
deleteProfile: false,
readComment: true,
addComment: false,
deleteComment: false,
editMedia: false,
deleteMedia: false,
editSubtitle: false,
manageMedia: false,
manageUsers: false,
manageComments: false,
reportMedia: false,
downloadMedia: false,
saveMedia: false,
likeMedia: true,
dislikeMedia: true,
shareMedia: true,
contactUser: false,
},
pages: {
home: null,
about: null,
media: null,
playlists: null,
},
};
if (void 0 !== user) {
MEMBER.is.anonymous = true === user.is.anonymous ? true : false;
if (!MEMBER.is.anonymous) {
MEMBER.is.admin = true === user.is.admin;
MEMBER.name = 'string' === typeof user.name ? user.name.trim() : '';
MEMBER.name = '' === MEMBER.name ? null : MEMBER.name;
MEMBER.username = 'string' === typeof user.username ? user.username.trim() : '';
MEMBER.username = '' === MEMBER.username ? null : MEMBER.username;
MEMBER.thumbnail = 'string' === typeof user.thumbnail ? user.thumbnail.trim() : '';
MEMBER.thumbnail = '' === MEMBER.thumbnail ? null : MEMBER.thumbnail;
MEMBER.can.changePassword = false === user.can.changePassword ? false : MEMBER.can.changePassword;
MEMBER.can.deleteProfile = true === user.can.deleteProfile;
MEMBER.can.addComment = true === user.can.addComment;
MEMBER.can.deleteComment = true === user.can.deleteComment;
MEMBER.can.editMedia = true === user.can.editMedia;
MEMBER.can.deleteMedia = true === user.can.deleteMedia;
MEMBER.can.editSubtitle = true === user.can.editSubtitle;
MEMBER.can.manageMedia = true === user.can.manageMedia;
MEMBER.can.manageUsers = true === user.can.manageUsers;
MEMBER.can.manageComments = true === user.can.manageComments;
MEMBER.can.contactUser = true === user.can.contactUser;
if (void 0 !== user.pages) {
if ('string' === typeof user.pages.about) {
MEMBER.pages.about = user.pages.about.trim();
MEMBER.pages.about = '' === MEMBER.pages.about ? null : MEMBER.pages.about;
}
if ('string' === typeof user.pages.media) {
MEMBER.pages.media = user.pages.media.trim();
MEMBER.pages.media = '' === MEMBER.pages.media ? null : MEMBER.pages.media;
}
if ('string' === typeof user.pages.playlists) {
MEMBER.pages.playlists = user.pages.playlists.trim();
MEMBER.pages.playlists = '' === MEMBER.pages.playlists ? null : MEMBER.pages.playlists;
}
}
}
MEMBER.can.addMedia = true === user.can.addMedia;
MEMBER.can.editProfile = true === user.can.editProfile;
MEMBER.can.readComment = false === user.can.readComment ? false : true;
}
if (void 0 !== features) {
if (void 0 !== features.media) {
if (void 0 !== features.media.actions) {
const mediaActions = features.media.actions;
MEMBER.can.addComment = MEMBER.can.addComment && true === mediaActions.comment;
MEMBER.can.likeMedia = false === mediaActions.like ? false : true;
MEMBER.can.dislikeMedia = false === mediaActions.dislike ? false : true;
MEMBER.can.reportMedia = false === mediaActions.report ? false : true;
MEMBER.can.downloadMedia = true === mediaActions.download;
MEMBER.can.saveMedia = true === mediaActions.save;
MEMBER.can.shareMedia = true === mediaActions.share;
}
}
if (void 0 !== features.headerBar) {
if (true === features.headerBar.hideLogin) {
MEMBER.can.login = false;
}
if (true === features.headerBar.hideRegister) {
MEMBER.can.register = false;
}
}
}
}
export function settings() {
return MEMBER;
}

View File

@@ -0,0 +1,32 @@
let NOTIFICATIONS = null;
export function init(settings) {
NOTIFICATIONS = {
messages: {
addToLiked: 'Added to liked media',
removeFromLiked: 'Removed from liked media',
addToDisliked: 'Added to disliked media',
removeFromDisliked: 'Removed from disliked media',
},
};
let k, g;
if (void 0 !== settings) {
for (k in NOTIFICATIONS) {
if (void 0 !== settings[k]) {
if ('messages' === k) {
for (g in NOTIFICATIONS[k]) {
if ('string' === typeof settings[k][g]) {
NOTIFICATIONS[k][g] = settings[k][g];
}
}
}
}
}
}
}
export function settings() {
return NOTIFICATIONS;
}

View File

@@ -0,0 +1,42 @@
let EMBEDDED = null;
export function init(embeddedVideo) {
EMBEDDED = {
video: {
dimensions: {
width: 560,
widthUnit: 'px', // Valid values: 'px', 'percent'
height: 315,
heightUnit: 'px', // Valid values: 'px', 'percent'
},
},
};
if (void 0 !== embeddedVideo) {
if (void 0 !== embeddedVideo.initialDimensions) {
if (!isNaN(embeddedVideo.initialDimensions.width)) {
EMBEDDED.video.dimensions.width = embeddedVideo.initialDimensions.width;
}
if ('string' === typeof embeddedVideo.initialDimensions.widthUnit) {
if ('percent' === embeddedVideo.initialDimensions.widthUnit) {
embeddedVideo.initialDimensions.widthUnit = 'percent';
}
}
if (!isNaN(embeddedVideo.initialDimensions.height)) {
EMBEDDED.video.dimensions.height = embeddedVideo.initialDimensions.height;
}
if ('string' === typeof embeddedVideo.initialDimensions.heightUnit) {
if ('percent' === embeddedVideo.initialDimensions.heightUnit) {
embeddedVideo.initialDimensions.heightUnit = 'percent';
}
}
}
}
}
export function settings() {
return EMBEDDED;
}

View File

@@ -0,0 +1,108 @@
let PAGES = null;
export function init(home, search, media, profile, VALID_PAGES) {
PAGES = {
home: {
sections: {
latest: {
title: '',
},
featured: {
title: '',
},
recommended: {
title: '',
},
},
},
search: {
advancedFilters: false,
},
media: {
categoriesWithTitle: false,
htmlInDescription: false,
displayViews: true,
related: {
initialSize: 10,
},
},
profile: {
htmlInDescription: false,
includeHistory: false,
includeLikedMedia: false,
},
};
if (void 0 !== home) {
if (void 0 !== home.sections) {
if (void 0 !== home.sections.latest) {
if ('string' === typeof home.sections.latest.title) {
PAGES.home.sections.latest.title = home.sections.latest.title.trim();
}
}
if (void 0 !== home.sections.featured) {
if ('string' === typeof home.sections.featured.title) {
PAGES.home.sections.featured.title = home.sections.featured.title.trim();
}
}
if (void 0 !== home.sections.recommended) {
if ('string' === typeof home.sections.recommended.title) {
PAGES.home.sections.recommended.title = home.sections.recommended.title.trim();
}
}
}
}
if (void 0 !== search) {
if (true === search.advancedFilters) {
PAGES.search.advancedFilters = search.advancedFilters;
}
}
if ('' === PAGES.home.sections.latest.title) {
PAGES.home.sections.latest.title = void 0 !== VALID_PAGES.latest ? VALID_PAGES.latest.title : 'Latest';
}
if ('' === PAGES.home.sections.featured.title) {
PAGES.home.sections.featured.title = void 0 !== VALID_PAGES.featured ? VALID_PAGES.featured.title : 'Featured';
}
if ('' === PAGES.home.sections.recommended.title) {
PAGES.home.sections.recommended.title =
void 0 !== VALID_PAGES.recommended ? VALID_PAGES.recommended.title : 'Recommended';
}
if (void 0 !== media) {
if (true === media.categoriesWithTitle) {
PAGES.media.categoriesWithTitle = media.categoriesWithTitle;
}
if (true === media.hideViews) {
PAGES.media.displayViews = false;
}
if (true === media.htmlInDescription) {
PAGES.media.htmlInDescription = media.htmlInDescription;
}
}
if (void 0 !== profile) {
if (true === profile.htmlInDescription) {
PAGES.profile.htmlInDescription = profile.htmlInDescription;
}
if (true === profile.includeHistory) {
PAGES.profile.includeHistory = profile.includeHistory;
}
if (true === profile.includeLikedMedia) {
PAGES.profile.includeLikedMedia = profile.includeLikedMedia;
}
}
}
export function settings() {
return PAGES;
}

View File

@@ -0,0 +1,50 @@
let PAGES = null;
export function init(settings) {
PAGES = {
latest: {
enabled: false,
title: 'Recent uploads',
},
featured: {
enabled: false,
title: 'Featured',
},
recommended: {
enabled: false,
title: 'Recommended',
},
members: {
enabled: false,
title: 'Members',
},
liked: {
enabled: false,
title: 'Liked media',
},
history: {
enabled: false,
title: 'History',
},
};
if (void 0 !== settings) {
for (let k in PAGES) {
if (void 0 !== settings[k]) {
PAGES[k].enabled = true;
if (void 0 !== settings[k].enabled && false === settings[k].enabled) {
PAGES[k].enabled = false;
}
if ('string' === typeof settings[k].title) {
PAGES[k].title = settings[k].title.trim();
}
}
}
}
}
export function settings() {
return PAGES;
}

View File

@@ -0,0 +1,35 @@
let PLAYLISTS = null;
export function init(plists) {
PLAYLISTS = {
mediaTypes: [],
};
if (void 0 !== plists) {
if (void 0 !== plists.mediaTypes) {
if (plists.mediaTypes.length) {
PLAYLISTS.mediaTypes = [];
let i = 0;
while (i < plists.mediaTypes.length) {
switch (plists.mediaTypes[i]) {
case 'audio':
case 'video':
PLAYLISTS.mediaTypes.push(plists.mediaTypes[i]);
break;
}
i += 1;
}
}
}
}
if (!PLAYLISTS.mediaTypes.length) {
PLAYLISTS.mediaTypes = ['audio', 'video'];
}
}
export function settings() {
return PLAYLISTS;
}

View File

@@ -0,0 +1,27 @@
let SIDEBAR = null;
export function init(settings) {
SIDEBAR = {
hideHomeLink: false,
hideTagsLink: false,
hideCategoriesLink: false,
};
if (void 0 !== settings) {
if ('boolean' === typeof settings.hideHomeLink) {
SIDEBAR.hideHomeLink = settings.hideHomeLink;
}
if ('boolean' === typeof settings.hideTagsLink) {
SIDEBAR.hideTagsLink = settings.hideTagsLink;
}
if ('boolean' === typeof settings.hideCategoriesLink) {
SIDEBAR.hideCategoriesLink = settings.hideCategoriesLink;
}
}
}
export function settings() {
return SIDEBAR;
}

View File

@@ -0,0 +1,32 @@
let SITE = null;
export function init(settings) {
SITE = {
id: 'media-cms',
url: '',
api: '',
title: '',
};
if (void 0 !== settings) {
if ('string' === typeof settings.id) {
SITE.id = settings.id.trim();
}
if ('string' === typeof settings.url) {
SITE.url = settings.url.trim();
}
if ('string' === typeof settings.api) {
SITE.api = settings.api.trim();
}
if ('string' === typeof settings.title) {
SITE.title = settings.title.trim();
}
}
}
export function settings() {
return SITE;
}

View File

@@ -0,0 +1,34 @@
let TAXONOMIES = null;
export function init(settings) {
TAXONOMIES = {
tags: {
enabled: false,
title: 'Tags',
},
categories: {
enabled: false,
title: 'Categories',
},
};
if (void 0 !== settings) {
for (let k in TAXONOMIES) {
if (void 0 !== settings[k]) {
TAXONOMIES[k].enabled = true;
if (void 0 !== settings[k].enabled && false === settings[k].enabled) {
TAXONOMIES[k].enabled = false;
}
if ('string' === typeof settings[k].title) {
TAXONOMIES[k].title = settings[k].title.trim();
}
}
}
}
}
export function settings() {
return TAXONOMIES;
}

View File

@@ -0,0 +1,65 @@
let THEME = null;
export function init(theme, logo) {
THEME = {
mode: 'light', // Valid options: 'light', 'dark'.
switch: {
enabled: true,
position: 'header', // Valid options: 'header', 'sidebar'.
},
logo: {
lightMode: {
img: '',
svg: '',
},
darkMode: {
img: '',
svg: '',
},
},
};
if (void 0 !== theme) {
if ('string' === typeof theme.mode) {
THEME.mode = theme.mode.trim();
THEME.mode = 'dark' === THEME.mode ? 'dark' : 'light';
}
if (void 0 !== theme.switch) {
if (false === theme.switch.enabled) {
THEME.switch.enabled = theme.switch.enabled;
}
if ('string' === typeof theme.switch.position) {
THEME.switch.position = theme.switch.position.trim();
THEME.switch.position = 'sidebar' === theme.switch.position ? 'sidebar' : 'header';
}
}
}
if (void 0 !== logo) {
if (void 0 !== logo.lightMode) {
if ('string' === typeof logo.lightMode.img) {
THEME.logo.lightMode.img = logo.lightMode.img.trim();
}
if ('string' === typeof logo.lightMode.svg) {
THEME.logo.lightMode.svg = logo.lightMode.svg.trim();
}
}
if (void 0 !== logo.darkMode) {
if ('string' === typeof logo.darkMode.img) {
THEME.logo.darkMode.img = logo.darkMode.img.trim();
}
if ('string' === typeof logo.darkMode.svg) {
THEME.logo.darkMode.svg = logo.darkMode.svg.trim();
}
}
}
}
export function settings() {
return THEME;
}

View File

@@ -0,0 +1,13 @@
let PAGES = null;
export function init(pages_url) {
PAGES = {};
for (let k in pages_url) {
PAGES[k] = pages_url[k];
}
}
export function pages() {
return PAGES;
}

View File

@@ -0,0 +1,876 @@
import EventEmitter from 'events';
import { exportStore, getRequest, postRequest, putRequest, deleteRequest, csrfToken } from '../helpers';
import { config as mediacmsConfig } from '../settings/config.js';
import UrlParse from 'url-parse';
import PageStore from './PageStore.js';
function extractPlaylistId() {
let playlistId = null;
const getParamsString = window.location.search;
if ('' !== getParamsString) {
let tmp = getParamsString.split('?');
if (2 === tmp.length) {
tmp = tmp[1].split('&');
let x;
let i = 0;
while (i < tmp.length) {
x = tmp[i].split('=');
if ('pl' === x[0]) {
if (2 === x.length) {
playlistId = x[1];
}
break;
}
i += 1;
}
}
}
return playlistId;
}
const MediaPageStoreData = {};
class MediaPageStore extends EventEmitter {
constructor() {
super();
this.mediacms_config = mediacmsConfig(window.MediaCMS);
this._MEDIA = null;
this.pagePlaylistId = null;
this.pagePlaylistData = null;
MediaPageStoreData[
Object.defineProperty(this, 'id', { value: 'MediaPageStoreData_' + Object.keys(MediaPageStoreData).length }).id
] = {
likedMedia: false,
dislikedMedia: false,
reported_times: 0,
while: {
deleteMedia: false,
submitComment: false,
deleteCommentId: null,
},
};
this.removeMediaResponse = this.removeMediaResponse.bind(this);
this.removeMediaFail = this.removeMediaFail.bind(this);
this.submitCommentFail = this.submitCommentFail.bind(this);
this.submitCommentResponse = this.submitCommentResponse.bind(this);
this.removeCommentFail = this.removeCommentFail.bind(this);
this.removeCommentResponse = this.removeCommentResponse.bind(this);
}
loadData() {
if (!MediaPageStoreData[this.id].mediaId) {
let urlParams = (function () {
let ret = new UrlParse(window.location.href).query;
if (!ret) {
ret = [];
} else {
ret = ret.substring(1);
ret.split('&');
ret = ret.length ? ret.split('=') : [];
}
return ret;
})();
if (urlParams.length) {
let i = 0;
while (i < urlParams.length) {
if ('m' === urlParams[i]) {
// NOTE: "m" => media id/token.
MediaPageStoreData[this.id].mediaId = urlParams[i + 1];
}
i += 2;
}
}
}
if (!MediaPageStoreData[this.id].mediaId) {
console.warn('Invalid media id:', MediaPageStoreData[this.id].mediaId);
return false;
}
this.mediaAPIUrl = this.mediacms_config.api.media + '/' + MediaPageStoreData[this.id].mediaId;
this.dataResponse = this.dataResponse.bind(this);
this.dataErrorResponse = this.dataErrorResponse.bind(this);
getRequest(this.mediaAPIUrl, !1, this.dataResponse, this.dataErrorResponse);
}
loadPlaylistData() {
const playlistApiUrl = this.mediacms_config.api.playlists + '/' + this.pagePlaylistId;
this.playlistDataResponse = this.playlistDataResponse.bind(this);
this.playlistDataErrorResponse = this.playlistDataErrorResponse.bind(this);
getRequest(playlistApiUrl, !1, this.playlistDataResponse, this.playlistDataErrorResponse);
}
playlistDataResponse(response) {
if (response && response.data) {
let validPlaylistMedia = false;
let i = 0;
while (i < response.data.playlist_media.length) {
if (MediaPageStoreData[this.id].mediaId === response.data.playlist_media[i].friendly_token) {
validPlaylistMedia = true;
break;
}
i += 1;
}
if (validPlaylistMedia) {
this.pagePlaylistData = response.data;
} else {
this.pagePlaylistId = null;
}
this.emit('loaded_viewer_playlist_data');
} else {
this.pagePlaylistId = null;
}
this.emit('loaded_page_playlist_data');
}
playlistDataErrorResponse(response) {
this.emit('loaded_viewer_playlist_error');
this.emit('loaded_page_playlist_data');
}
loadComments() {
this.commentsAPIUrl = this.mediacms_config.api.media + '/' + MediaPageStoreData[this.id].mediaId + '/comments';
this.commentsResponse = this.commentsResponse.bind(this);
getRequest(this.commentsAPIUrl, !1, this.commentsResponse);
}
loadPlaylists() {
if (!this.mediacms_config.member.can.saveMedia) {
return;
}
this.playlistsAPIUrl = this.mediacms_config.api.user.playlists + this.mediacms_config.member.username;
this.playlistsResponse = this.playlistsResponse.bind(this);
getRequest(this.playlistsAPIUrl, !1, this.playlistsResponse);
}
dataResponse(response) {
if (response && response.data) {
MediaPageStoreData[this.id].data = response.data;
MediaPageStoreData[this.id].reported_times = !!MediaPageStoreData[this.id].data.reported_times;
switch (this.get('media-type')) {
case 'video':
case 'audio':
case 'image':
this.emit('loaded_' + this.get('media-type') + '_data');
break;
}
this.emit('loaded_media_data');
}
this.loadPlaylists();
if (this.mediacms_config.member.can.readComment) {
this.loadComments();
}
}
dataErrorResponse(response) {
if (void 0 !== response.type) {
switch (response.type) {
case 'network':
case 'private':
case 'unavailable':
MediaPageStoreData[this.id].loadErrorType = response.type;
MediaPageStoreData[this.id].loadErrorMessage =
void 0 !== response.message ? response.message : "Αn error occurred while loading the media's data";
this.emit('loaded_media_error');
break;
}
}
}
commentsResponse(response) {
if (response && response.data) {
MediaPageStoreData[this.id].comments = response.data.count ? response.data.results : [];
this.emit('comments_load');
}
}
playlistsResponse(response) {
if (response && response.data) {
let tmp_playlists = response.data.count ? response.data.results : [];
MediaPageStoreData[this.id].playlists = [];
let i = 0;
let cntr = 0;
while (i < tmp_playlists.length) {
(function (pos) {
let _this = this;
if (tmp_playlists[pos].user === this.mediacms_config.member.username) {
let playlistsIndex = MediaPageStoreData[_this.id].playlists.length;
MediaPageStoreData[_this.id].playlists[playlistsIndex] = {
playlist_id: (function (_url_) {
let ret = _url_.split('/');
return 1 < ret.length ? ret[ret.length - 1] : null;
})(tmp_playlists[pos].url),
title: tmp_playlists[pos].title,
description: tmp_playlists[pos].description,
add_date: tmp_playlists[pos].add_date,
};
getRequest(
this.mediacms_config.site.url + '/' + tmp_playlists[pos].api_url.replace(/^\//g, ''),
!1,
function (resp) {
if (!!resp && !!resp.data) {
MediaPageStoreData[_this.id].playlists[playlistsIndex].media_list = [];
let f = 0;
let arr;
while (f < resp.data.playlist_media.length) {
arr = resp.data.playlist_media[f].url.split('m=');
if (2 === arr.length) {
MediaPageStoreData[_this.id].playlists[playlistsIndex].media_list.push(arr[1]);
}
f += 1;
}
}
cntr += 1;
if (cntr === tmp_playlists.length) {
this.emit('playlists_load');
}
}
);
}
}.bind(this)(i));
i += 1;
}
}
}
requestMediaLike() {
if (!MediaPageStoreData[this.id].mediaId) {
console.warn('Invalid media id:', MediaPageStoreData[this.id].mediaId);
return false;
}
const url = this.mediacms_config.api.media + '/' + MediaPageStoreData[this.id].mediaId + '/actions';
this.likeActionResponse = this.likeActionResponse.bind(this);
postRequest(
url,
{
type: 'like',
// `headers` are custom headers to be sent
},
{
headers: {
'X-CSRFToken': csrfToken(),
},
},
false,
this.likeActionResponse,
function () {
this.emit('liked_media_failed_request');
}.bind(this)
);
}
likeActionResponse(response) {
if (response) {
if (response instanceof Error) {
} else if (response.data) {
MediaPageStoreData[this.id].likedMedia = true;
this.emit('liked_media');
}
}
}
requestMediaDislike() {
if (!MediaPageStoreData[this.id].mediaId) {
console.warn('Invalid media id:', MediaPageStoreData[this.id].mediaId);
return false;
}
const url = this.mediacms_config.api.media + '/' + MediaPageStoreData[this.id].mediaId + '/actions';
this.dislikeActionResponse = this.dislikeActionResponse.bind(this);
postRequest(
url,
{
type: 'dislike',
},
{
headers: {
'X-CSRFToken': csrfToken(),
},
},
false,
this.dislikeActionResponse,
function () {
this.emit('disliked_media_failed_request');
}.bind(this)
);
}
dislikeActionResponse(response) {
if (response) {
if (response instanceof Error) {
} else if (response.data) {
MediaPageStoreData[this.id].dislikedMedia = true;
this.emit('disliked_media');
}
}
}
requestMediaReport(descr) {
if (!MediaPageStoreData[this.id].mediaId) {
console.warn('Invalid media id:', MediaPageStoreData[this.id].mediaId);
return false;
}
const url = this.mediacms_config.api.media + '/' + MediaPageStoreData[this.id].mediaId + '/actions';
this.reportActionResponse = this.reportActionResponse.bind(this);
postRequest(
url,
{
type: 'report',
extra_info: descr,
},
{
headers: {
'X-CSRFToken': csrfToken(),
},
},
false,
this.reportActionResponse,
this.reportActionResponse
);
}
reportActionResponse(response) {
if (response) {
if (response instanceof Error) {
} else if (response.data) {
MediaPageStoreData[this.id].reported_times += 1;
this.emit('reported_media');
}
}
}
set(type, value) {
switch (type) {
case 'media-load-error-type':
MediaPageStoreData[this.id].loadErrorType = value;
break;
case 'media-load-error-message':
MediaPageStoreData[this.id].loadErrorMessage = value;
break;
}
}
get(type) {
let tmp,
activeItem,
browserCache,
i,
r = null;
switch (type) {
case 'playlists':
r = MediaPageStoreData[this.id].playlists || [];
break;
case 'media-load-error-type':
r = void 0 !== MediaPageStoreData[this.id].loadErrorType ? MediaPageStoreData[this.id].loadErrorType : null;
break;
case 'media-load-error-message':
r =
void 0 !== MediaPageStoreData[this.id].loadErrorMessage ? MediaPageStoreData[this.id].loadErrorMessage : null;
break;
case 'media-comments':
r = MediaPageStoreData[this.id].comments || [];
break;
case 'media-data':
r = MediaPageStoreData[this.id].data || null;
break;
case 'media-id':
r = MediaPageStoreData[this.id].mediaId;
break;
case 'media-url':
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.url
? MediaPageStoreData[this.id].data.url
: 'N/A';
break;
case 'media-edit-subtitle-url':
r =
void 0 !== MediaPageStoreData[this.id].data &&
'string' === typeof MediaPageStoreData[this.id].data.add_subtitle_url
? MediaPageStoreData[this.id].data.add_subtitle_url
: null;
break;
case 'media-likes':
tmp = MediaPageStoreData[this.id].likedMedia ? 1 : 0;
if (tmp) {
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.likes
? MediaPageStoreData[this.id].data.likes + tmp
: tmp;
} else {
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.likes
? MediaPageStoreData[this.id].data.likes
: 'N/A';
}
break;
case 'media-dislikes':
tmp = MediaPageStoreData[this.id].dislikedMedia ? 1 : 0;
if (tmp) {
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.dislikes
? MediaPageStoreData[this.id].data.dislikes + tmp
: tmp;
} else {
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.dislikes
? MediaPageStoreData[this.id].data.dislikes
: 'N/A';
}
break;
case 'media-summary':
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.summary
? MediaPageStoreData[this.id].data.summary
: null;
break;
case 'media-categories':
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.categories_info
? MediaPageStoreData[this.id].data.categories_info
: [];
break;
case 'media-tags':
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.tags_info
? MediaPageStoreData[this.id].data.tags_info
: [];
break;
case 'media-type':
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.media_type
? MediaPageStoreData[this.id].data.media_type
: null;
break;
case 'media-original-url':
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.original_media_url
? MediaPageStoreData[this.id].data.original_media_url
: null;
break;
case 'media-thumbnail-url':
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.thumbnail_url
? MediaPageStoreData[this.id].data.thumbnail_url
: null;
break;
case 'user-liked-media':
r = MediaPageStoreData[this.id].likedMedia;
break;
case 'user-disliked-media':
r = MediaPageStoreData[this.id].dislikedMedia;
break;
case 'media-author-thumbnail-url':
r =
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.author_thumbnail
? this.mediacms_config.site.url +
'/' +
MediaPageStoreData[this.id].data.author_thumbnail.replace(/^\//g, '')
: null;
break;
case 'playlist-data':
r = this.pagePlaylistData;
break;
case 'playlist-id':
r = this.pagePlaylistId;
break;
case 'playlist-next-media-url':
if (!this.pagePlaylistData) {
break;
}
activeItem = 0;
i = 0;
while (i < this.pagePlaylistData.playlist_media.length) {
if (MediaPageStoreData[this.id].mediaId === this.pagePlaylistData.playlist_media[i].friendly_token) {
activeItem = i;
break;
}
i += 1;
}
let nextItem = activeItem + 1;
if (nextItem === this.pagePlaylistData.playlist_media.length) {
browserCache = PageStore.get('browser-cache');
if (true === browserCache.get('loopPlaylist[' + this.pagePlaylistId + ']')) {
nextItem = 0;
}
}
if (void 0 !== this.pagePlaylistData.playlist_media[nextItem]) {
r = this.pagePlaylistData.playlist_media[nextItem].url + '&pl=' + this.pagePlaylistId;
}
break;
case 'playlist-previous-media-url':
if (!this.pagePlaylistData) {
break;
}
activeItem = 0;
i = 0;
while (i < this.pagePlaylistData.playlist_media.length) {
if (MediaPageStoreData[this.id].mediaId === this.pagePlaylistData.playlist_media[i].friendly_token) {
activeItem = i;
break;
}
i += 1;
}
let previousItem = activeItem - 1;
if (0 === activeItem) {
previousItem = null;
browserCache = PageStore.get('browser-cache');
if (true === browserCache.get('loopPlaylist[' + this.pagePlaylistId + ']')) {
previousItem = this.pagePlaylistData.playlist_media.length - 1;
}
}
if (void 0 !== this.pagePlaylistData.playlist_media[previousItem]) {
r = this.pagePlaylistData.playlist_media[previousItem].url + '&pl=' + this.pagePlaylistId;
}
break;
}
return r;
}
isVideo() {
return 'video' === this.get('media-type');
}
onPlaylistCreationCompleted(response) {
if (response && response.data) {
this.emit('playlist_creation_completed', response.data);
}
}
onPlaylistCreationFailed() {
this.emit('playlist_creation_failed');
}
onPlaylistMediaAdditionCompleted(playlist_id, response) {
if (response) {
let i = 0;
while (i < MediaPageStoreData[this.id].playlists.length) {
if (playlist_id === MediaPageStoreData[this.id].playlists[i].playlist_id) {
MediaPageStoreData[this.id].playlists[i].media_list.push(MediaPageStoreData[this.id].mediaId);
break;
}
i += 1;
}
this.emit('media_playlist_addition_completed', playlist_id);
}
}
onPlaylistMediaAdditionFailed(playlist_id, response) {
this.emit('media_playlist_addition_failed');
}
onPlaylistMediaRemovalCompleted(playlist_id, response) {
if (response) {
let j, new_playlist_media;
let i = 0;
while (i < MediaPageStoreData[this.id].playlists.length) {
if (playlist_id === MediaPageStoreData[this.id].playlists[i].playlist_id) {
new_playlist_media = [];
j = 0;
while (j < MediaPageStoreData[this.id].playlists[i].media_list.length) {
if (MediaPageStoreData[this.id].mediaId !== MediaPageStoreData[this.id].playlists[i].media_list[j]) {
new_playlist_media.push(MediaPageStoreData[this.id].playlists[i].media_list[j]);
}
j += 1;
}
MediaPageStoreData[this.id].playlists[i].media_list = new_playlist_media;
break;
}
i += 1;
}
this.emit('media_playlist_removal_completed', playlist_id);
}
}
onPlaylistMediaRemovalFailed(playlist_id, response) {
this.emit('media_playlist_removal_failed');
}
actions_handler(action) {
switch (action.type) {
case 'LOAD_MEDIA_DATA':
MediaPageStoreData[this.id].mediaId = window.MediaCMS.mediaId || MediaPageStoreData[this.id].mediaId;
this.pagePlaylistId = extractPlaylistId();
if (this.pagePlaylistId) {
this.loadPlaylistData();
this.loadData();
} else {
this.emit('loaded_page_playlist_data');
this.loadData();
}
break;
case 'LIKE_MEDIA':
if (!MediaPageStoreData[this.id].likedMedia && !MediaPageStoreData[this.id].dislikedMedia) {
this.requestMediaLike();
}
break;
case 'DISLIKE_MEDIA':
if (!MediaPageStoreData[this.id].likedMedia && !MediaPageStoreData[this.id].dislikedMedia) {
this.requestMediaDislike();
}
break;
case 'REPORT_MEDIA':
if (!MediaPageStoreData[this.id].reported_times) {
if ('' !== action.reportDescription) {
this.requestMediaReport(action.reportDescription);
}
}
break;
case 'COPY_SHARE_LINK':
if (action.inputElement instanceof HTMLElement) {
action.inputElement.select();
document.execCommand('copy');
this.emit('copied_media_link');
}
break;
case 'COPY_EMBED_MEDIA_CODE':
if (action.inputElement instanceof HTMLElement) {
action.inputElement.select();
document.execCommand('copy');
this.emit('copied_embed_media_code');
}
break;
case 'REMOVE_MEDIA':
if (MediaPageStoreData[this.id].while.deleteMedia) {
return;
}
MediaPageStoreData[this.id].while.deleteMedia = true;
deleteRequest(
this.mediaAPIUrl,
{ headers: { 'X-CSRFToken': csrfToken() } },
false,
this.removeMediaResponse,
this.removeMediaFail
);
break;
case 'SUBMIT_COMMENT':
if (MediaPageStoreData[this.id].while.submitComment) {
return;
}
MediaPageStoreData[this.id].while.submitComment = true;
postRequest(
this.commentsAPIUrl,
{ text: action.commentText },
{ headers: { 'X-CSRFToken': csrfToken() } },
false,
this.submitCommentResponse,
this.submitCommentFail
);
break;
case 'DELETE_COMMENT':
if (null !== MediaPageStoreData[this.id].while.deleteCommentId) {
return;
}
MediaPageStoreData[this.id].while.deleteCommentId = action.commentId;
deleteRequest(
this.commentsAPIUrl + '/' + action.commentId,
{ headers: { 'X-CSRFToken': csrfToken() } },
false,
this.removeCommentResponse,
this.removeCommentFail
);
break;
case 'CREATE_PLAYLIST':
postRequest(
this.mediacms_config.api.playlists,
{
title: action.playlist_data.title,
description: action.playlist_data.description,
},
{
headers: {
'X-CSRFToken': csrfToken(),
},
},
false,
this.onPlaylistCreationCompleted.bind(this),
this.onPlaylistCreationFailed.bind(this)
);
break;
case 'ADD_MEDIA_TO_PLAYLIST':
putRequest(
this.mediacms_config.api.playlists + '/' + action.playlist_id,
{
type: 'add',
media_friendly_token: action.media_id,
},
{
headers: {
'X-CSRFToken': csrfToken(),
},
},
false,
this.onPlaylistMediaAdditionCompleted.bind(this, action.playlist_id),
this.onPlaylistMediaAdditionFailed.bind(this, action.playlist_id)
);
break;
case 'REMOVE_MEDIA_FROM_PLAYLIST':
putRequest(
this.mediacms_config.api.playlists + '/' + action.playlist_id,
{
type: 'remove',
media_friendly_token: action.media_id,
},
{
headers: {
'X-CSRFToken': csrfToken(),
},
},
false,
this.onPlaylistMediaRemovalCompleted.bind(this, action.playlist_id),
this.onPlaylistMediaRemovalFailed.bind(this, action.playlist_id)
);
break;
case 'APPEND_NEW_PLAYLIST':
MediaPageStoreData[this.id].playlists.push(action.playlist_data);
this.emit('playlists_load');
break;
}
}
removeMediaResponse(response) {
if (response && 204 === response.status) {
this.emit('media_delete', MediaPageStoreData[this.id].mediaId);
}
}
removeMediaFail() {
this.emit('media_delete_fail', MediaPageStoreData[this.id].mediaId);
setTimeout(
function (ins) {
MediaPageStoreData[ins.id].while.deleteMedia = null;
},
100,
this
);
}
removeCommentFail(err) {
this.emit('comment_delete_fail', MediaPageStoreData[this.id].while.deleteCommentId);
setTimeout(
function (ins) {
MediaPageStoreData[ins.id].while.deleteCommentId = null;
},
100,
this
);
}
removeCommentResponse(response) {
if (response && 204 === response.status) {
let k;
let newComments = [];
for (k in MediaPageStoreData[this.id].comments) {
if (MediaPageStoreData[this.id].comments.hasOwnProperty(k)) {
if (MediaPageStoreData[this.id].while.deleteCommentId !== MediaPageStoreData[this.id].comments[k].uid) {
newComments.push(MediaPageStoreData[this.id].comments[k]);
}
}
}
MediaPageStoreData[this.id].comments = newComments;
newComments = null;
this.emit('comment_delete', MediaPageStoreData[this.id].while.deleteCommentId);
}
setTimeout(
function (ins) {
MediaPageStoreData[ins.id].while.deleteCommentId = null;
},
100,
this
);
}
submitCommentFail(err) {
this.emit('comment_submit_fail');
setTimeout(
function (ins) {
MediaPageStoreData[ins.id].while.submitComment = false;
},
100,
this
);
}
submitCommentResponse(response) {
if (response && 201 === response.status && response.data && Object.keys(response.data)) {
MediaPageStoreData[this.id].comments.push(response.data);
this.emit('comment_submit', response.data.uid);
}
setTimeout(
function (ins) {
MediaPageStoreData[ins.id].while.submitComment = false;
},
100,
this
);
}
}
export default exportStore(new MediaPageStore(), 'actions_handler');

View File

@@ -0,0 +1,155 @@
import EventEmitter from 'events';
import { BrowserCache } from '../classes/';
import { BrowserEvents, exportStore } from '../helpers';
import { config as mediaCmsConfig } from '../settings/config.js';
function uniqid() {
let a = new Uint32Array(3);
window.crypto.getRandomValues(a);
return (
performance.now().toString(36) +
Array.from(a)
.map((A) => A.toString(36))
.join('')
).replace(/./g, '' + Math.random() + Intl.DateTimeFormat().resolvedOptions().timeZone + Date.now());
}
function Notifications(initialNotifications) {
let stack = [];
function push(msg) {
if ('string' === typeof msg) {
stack.push([uniqid(), msg]);
}
}
function messages() {
return [...stack];
}
function clear() {
stack = [];
}
function size() {
return stack.length;
}
initialNotifications.map(push);
return {
size,
push,
clear,
messages,
};
}
let browserCache;
let page_config = null;
let mediacms_config = null;
const mediacms_api_endpoint_url = (k) => mediacms_config.api[k] || null;
class PageStore extends EventEmitter {
constructor(page) {
super();
mediacms_config = mediaCmsConfig(window.MediaCMS);
browserCache = new BrowserCache(mediacms_config.site.id, 86400); // Keep cache data "fresh" for one day.
page_config = {
mediaAutoPlay: browserCache.get('media-auto-play'),
};
page_config.mediaAutoPlay = null !== page_config.mediaAutoPlay ? page_config.mediaAutoPlay : true;
this.browserEvents = BrowserEvents();
this.browserEvents.doc(this.onDocumentVisibilityChange.bind(this));
this.browserEvents.win(this.onWindowResize.bind(this), this.onWindowScroll.bind(this));
this.notifications = Notifications(
void 0 !== window.MediaCMS && void 0 !== window.MediaCMS.notifications ? window.MediaCMS.notifications : []
);
}
onDocumentVisibilityChange() {
this.emit('document_visibility_change');
}
onWindowScroll() {
this.emit('window_scroll');
}
onWindowResize() {
this.emit('window_resize');
}
initPage(page) {
page_config.currentPage = page;
}
get(type) {
let r;
switch (type) {
case 'browser-cache':
r = browserCache;
break;
case 'media-auto-play':
r = page_config.mediaAutoPlay;
break;
case 'config-contents':
r = mediacms_config.contents;
break;
case 'config-enabled':
r = mediacms_config.enabled;
break;
case 'config-media-item':
r = mediacms_config.media.item;
break;
case 'config-options':
r = mediacms_config.options;
break;
case 'config-site':
r = mediacms_config.site;
break;
case 'api-playlists':
r = mediacms_api_endpoint_url(type.split('-')[1]);
break;
case 'notifications-size':
r = this.notifications.size();
break;
case 'notifications':
r = this.notifications.messages();
this.notifications.clear();
break;
case 'current-page':
r = page_config.currentPage;
break;
}
return r;
}
actions_handler(action) {
switch (action.type) {
case 'INIT_PAGE':
this.initPage(action.page);
this.emit('page_init');
break;
case 'TOGGLE_AUTO_PLAY':
page_config.mediaAutoPlay = !page_config.mediaAutoPlay;
browserCache.set('media-auto-play', page_config.mediaAutoPlay);
this.emit('switched_media_auto_play');
break;
case 'ADD_NOTIFICATION':
this.notifications.push(action.notification);
this.emit('added_notification');
break;
}
}
}
export default exportStore(new PageStore(), 'actions_handler');

View File

@@ -0,0 +1,236 @@
import React from 'react';
import EventEmitter from 'events';
import { publishedOnDate, exportStore, getRequest, postRequest, deleteRequest, csrfToken } from '../helpers';
import { config as mediacmsConfig } from '../settings/config.js';
const PlaylistPageStoreData = {};
class PlaylistPageStore extends EventEmitter {
constructor() {
super();
this.mediacms_config = mediacmsConfig(window.MediaCMS);
PlaylistPageStoreData[
Object.defineProperty(this, 'id', {
value: 'PlaylistPageStoreData_' + Object.keys(PlaylistPageStoreData).length,
}).id
] = {
playlistId: null,
data: {},
};
this.data = {
savedPlaylist: false,
publishDate: new Date(2018, 3, 14, 1, 13, 22, 0),
publishDateLabel: null,
};
this.onPlaylistUpdateCompleted = this.onPlaylistUpdateCompleted.bind(this);
this.onPlaylistUpdateFailed = this.onPlaylistUpdateFailed.bind(this);
this.onPlaylistRemovalCompleted = this.onPlaylistRemovalCompleted.bind(this);
this.onPlaylistRemovalFailed = this.onPlaylistRemovalFailed.bind(this);
}
loadData() {
if (!PlaylistPageStoreData[this.id].playlistId) {
console.warn('Invalid playlist id:', PlaylistPageStoreData[this.id].playlistId);
return false;
}
this.playlistAPIUrl = this.mediacms_config.api.playlists + '/' + PlaylistPageStoreData[this.id].playlistId;
this.dataResponse = this.dataResponse.bind(this);
this.dataErrorResponse = this.dataErrorResponse.bind(this);
getRequest(this.playlistAPIUrl, !1, this.dataResponse, this.dataErrorResponse);
}
dataResponse(response) {
if (response && response.data) {
PlaylistPageStoreData[this.id].data = response.data;
this.emit('loaded_playlist_data');
}
}
dataErrorResponse(response) {
this.emit('loaded_playlist_error');
if (void 0 !== response.type) {
/*switch( response.type ){
case "network":
case "private":
case "unavailable":
MediaPageStoreData[this.id].loadErrorType = response.type;
MediaPageStoreData[this.id].loadErrorMessage = void 0 !== response.message ? response.message : "Αn error occurred while loading the media's data";
this.emit('loaded_media_error');
break;
}*/
}
}
get(type) {
switch (type) {
case 'playlistId':
return PlaylistPageStoreData[this.id].playlistId || null;
break;
case 'logged-in-user-playlist':
return (
!this.mediacms_config.member.is.anonymous &&
PlaylistPageStoreData[this.id].data.user === this.mediacms_config.member.username
);
case 'playlist-media':
return PlaylistPageStoreData[this.id].data.playlist_media || [];
case 'visibility':
return 'public';
case 'visibility-icon':
switch (this.get('visibility')) {
case 'unlisted':
return <i className="material-icons">insert_link</i>;
case 'private':
return <i className="material-icons">lock</i>;
}
return null;
case 'total-items':
return PlaylistPageStoreData[this.id].data.playlist_media.length || 0;
case 'views-count':
return 'N/A';
case 'title':
return PlaylistPageStoreData[this.id].data.title || null;
case 'edit-link':
return '#';
case 'thumb':
if (
PlaylistPageStoreData[this.id].data.playlist_media &&
PlaylistPageStoreData[this.id].data.playlist_media.length
) {
return PlaylistPageStoreData[this.id].data.playlist_media[0].thumbnail_url;
}
return null;
case 'description':
return PlaylistPageStoreData[this.id].data.description || null;
case 'author-username':
return PlaylistPageStoreData[this.id].data.user || null; // TODO: Recheck this, is this same with 'author-name'?
case 'author-name':
return PlaylistPageStoreData[this.id].data.user || null;
case 'author-link':
return PlaylistPageStoreData[this.id].data.user
? this.mediacms_config.site.url + '/user/' + PlaylistPageStoreData[this.id].data.user
: null;
case 'author-thumb':
if (!PlaylistPageStoreData[this.id].data.user_thumbnail_url) {
return null;
}
return (
this.mediacms_config.site.url +
'/' +
PlaylistPageStoreData[this.id].data.user_thumbnail_url.replace(/^\//g, '')
);
case 'saved-playlist':
return this.data.savedPlaylist;
case 'date-label':
if (!PlaylistPageStoreData[this.id].data || !PlaylistPageStoreData[this.id].data.add_date) {
return null;
}
this.data.publishDateLabel =
this.data.publishDateLabel ||
'Created on ' + publishedOnDate(new Date(PlaylistPageStoreData[this.id].data.add_date), 3);
return this.data.publishDateLabel;
}
return null;
}
onPlaylistUpdateCompleted(response) {
if (response && response.data) {
PlaylistPageStoreData[this.id].data.title = response.data.title;
PlaylistPageStoreData[this.id].data.description = response.data.description;
this.emit('playlist_update_completed', response.data);
}
}
onPlaylistUpdateFailed() {
this.emit('playlist_update_failed');
}
onPlaylistRemovalCompleted(response) {
if (response && void 0 !== response.status && 403 !== response.status) {
this.emit('playlist_removal_completed', response);
} else {
this.onPlaylistRemovalFailed();
}
}
onPlaylistRemovalFailed() {
this.emit('playlist_removal_failed');
}
actions_handler(action) {
switch (action.type) {
case 'LOAD_PLAYLIST_DATA':
PlaylistPageStoreData[this.id].playlistId =
window.MediaCMS.playlistId ||
(function (url) {
var arr = url.split('/');
return arr.length ? arr[arr.length - 1] : null;
})(window.location.href);
this.loadData();
break;
case 'TOGGLE_SAVE':
this.data.savedPlaylist = !this.data.savedPlaylist;
this.emit('saved-updated');
break;
case 'UPDATE_PLAYLIST':
postRequest(
this.playlistAPIUrl,
{
title: action.playlist_data.title,
description: action.playlist_data.description,
},
{
headers: {
'X-CSRFToken': csrfToken(),
},
},
false,
this.onPlaylistUpdateCompleted,
this.onPlaylistUpdateFailed
);
break;
case 'REMOVE_PLAYLIST':
deleteRequest(
this.playlistAPIUrl,
{
headers: {
'X-CSRFToken': csrfToken(),
},
},
false,
this.onPlaylistRemovalCompleted,
this.onPlaylistRemovalFailed
);
break;
case 'PLAYLIST_MEDIA_REORDERED':
PlaylistPageStoreData[this.id].data.playlist_media = action.playlist_media;
this.emit('reordered_media_in_playlist');
break;
case 'MEDIA_REMOVED_FROM_PLAYLIST':
const new_playlist_media = [];
let i = 0;
while (i < PlaylistPageStoreData[this.id].data.playlist_media.length) {
if (action.media_id !== PlaylistPageStoreData[this.id].data.playlist_media[i].url.split('=')[1]) {
new_playlist_media.push(PlaylistPageStoreData[this.id].data.playlist_media[i]);
}
i += 1;
}
PlaylistPageStoreData[this.id].data.playlist_media = new_playlist_media;
this.emit('removed_media_from_playlist');
break;
}
}
}
export default exportStore(new PlaylistPageStore(), 'actions_handler');

View File

@@ -0,0 +1,76 @@
import EventEmitter from 'events';
import { exportStore } from '../helpers';
import PageStore from './PageStore';
import MediaPageStore from './MediaPageStore';
class PlaylistViewStore extends EventEmitter {
constructor() {
super();
this.data = {
playlistId: null,
enabledLoop: null,
enabledShuffle: null,
savedPlaylist: false,
response: null,
};
this.browserCache = PageStore.get('browser-cache');
}
get(type) {
switch (type) {
case 'logged-in-user-playlist':
// TODO: Continue here.
return false;
case 'enabled-loop':
if (null === this.data.playlistId) {
this.data.playlistId = MediaPageStore.get('playlist-id');
this.data.enabledLoop = this.browserCache.get('loopPlaylist[' + this.data.playlistId + ']');
this.data.enabledLoop = null === this.data.enabledLoop ? true : this.data.enabledLoop;
}
return this.data.enabledLoop;
case 'enabled-shuffle':
if (null === this.data.playlistId) {
this.data.playlistId = MediaPageStore.get('playlist-id');
this.data.enabledShuffle = this.browserCache.get('shufflePlaylist[' + this.data.playlistId + ']');
this.data.enabledShuffle = null === this.data.enabledShuffle ? false : this.data.enabledShuffle;
}
return this.data.enabledShuffle;
case 'saved-playlist':
return this.data.savedPlaylist;
}
return null;
}
actions_handler(action) {
switch (action.type) {
case 'TOGGLE_LOOP':
if (null === this.data.playlistId) {
this.data.playlistId = MediaPageStore.get('playlist-id');
this.data.enabledLoop = this.browserCache.get('loopPlaylist[' + this.data.playlistId + ']');
this.data.enabledLoop = null === this.data.enabledLoop ? true : this.data.enabledLoop;
}
this.data.enabledLoop = !this.data.enabledLoop;
this.browserCache.set('loopPlaylist[' + this.data.playlistId + ']', this.data.enabledLoop);
this.emit('loop-repeat-updated');
break;
case 'TOGGLE_SHUFFLE':
if (null === this.data.playlistId) {
this.data.playlistId = MediaPageStore.get('playlist-id');
this.data.enabledShuffle = this.browserCache.get('shufflePlaylist[' + this.data.playlistId + ']');
this.data.enabledShuffle = null === this.data.enabledShuffle ? false : this.data.enabledShuffle;
}
this.data.enabledShuffle = !this.data.enabledShuffle;
this.browserCache.set('shufflePlaylist[' + this.data.playlistId + ']', this.data.enabledShuffle);
this.emit('shuffle-updated');
break;
case 'TOGGLE_SAVE':
this.data.savedPlaylist = !this.data.savedPlaylist;
this.emit('saved-updated');
break;
}
}
}
export default exportStore(new PlaylistViewStore(), 'actions_handler');

View File

@@ -0,0 +1,106 @@
import EventEmitter from 'events';
import { exportStore, getRequest, deleteRequest, csrfToken } from '../helpers';
import { config as mediacmsConfig } from '../settings/config.js';
class ProfilePageStore extends EventEmitter {
constructor() {
super();
this.mediacms_config = mediacmsConfig(window.MediaCMS);
this.authorData = null;
this.authorQuery = void 0;
this.onDataLoad = this.onDataLoad.bind(this);
this.onDataLoadFail = this.onDataLoadFail.bind(this);
this.removeProfileResponse = this.removeProfileResponse.bind(this);
this.removeProfileFail = this.removeProfileFail.bind(this);
this.removingProfile = false;
}
removeProfileResponse(response) {
if (response && 204 === response.status) {
this.emit('profile_delete', this.authorData.username);
}
}
removeProfileFail() {
this.emit('profile_delete_fail', this.authorData.username);
setTimeout(
function (ins) {
this.removingProfile = false;
},
100,
this
);
}
get(type) {
switch (type) {
case 'author-data':
return this.authorData;
case 'author-query':
if (void 0 === this.authorQuery) {
this.authorQuery = null;
let getArgs = window.location.search;
if (getArgs && '' !== getArgs) {
getArgs = getArgs.split('?')[1].split('=');
let i = 0;
while (i < getArgs.length) {
if ('aq' === getArgs[i]) {
this.authorQuery = getArgs[i + 1] || null;
break;
}
i += 1;
}
}
}
return this.authorQuery;
}
}
onDataLoad(response) {
if (response && response.data) {
this.authorData = response.data;
this.authorData.id = this.authorData.username;
this.authorData.name = '' !== this.authorData.name ? this.authorData.name : this.authorData.username;
this.emit('load-author-data');
}
}
onDataLoadFail(response) {
// TODO: Continue here.
}
actions_handler(action) {
switch (action.type) {
case 'REMOVE_PROFILE':
if (this.removingProfile) {
return;
}
this.removingProfile = true;
let deleteAPIurl = this.mediacms_config.api.users + '/' + this.authorData.username;
deleteRequest(
deleteAPIurl,
{ headers: { 'X-CSRFToken': csrfToken() } },
false,
this.removeProfileResponse,
this.removeProfileFail
);
break;
case 'LOAD_AUTHOR_DATA':
getRequest(
this.mediacms_config.api.users + '/' + window.MediaCMS.profileId,
!1,
this.onDataLoad,
this.onDataLoadFail
);
break;
}
}
}
export default exportStore(new ProfilePageStore(), 'actions_handler');

View File

@@ -0,0 +1,102 @@
import EventEmitter from 'events';
import { exportStore, getRequest } from '../helpers';
import { config as mediacmsConfig } from '../settings/config.js';
function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) {
vars[key] = value;
});
return vars;
}
const SearchFieldStoreData = {};
class SearchFieldStore extends EventEmitter {
constructor() {
super();
this.mediacms_config = mediacmsConfig(window.MediaCMS);
const urlvars = getUrlVars();
const query = urlvars['q'];
const categories = urlvars['c'];
const tags = urlvars['t'];
SearchFieldStoreData[
Object.defineProperty(this, 'id', {
value: 'SearchFieldStoreData_' + Object.keys(SearchFieldStoreData).length,
}).id
] = {
searchQuery: query ? decodeURIComponent(query).replace(/\+/g, ' ') : '',
categoriesQuery: categories ? decodeURIComponent(categories).replace(/\+/g, ' ') : '',
tagsQuery: tags ? decodeURIComponent(tags).replace(/\+/g, ' ') : '',
predictions: [],
};
this.dataResponse = this.dataResponse.bind(this);
}
dataResponse(response) {
if (response && response.data) {
let i = 0;
SearchFieldStoreData[this.id].predictions = [];
while (i < response.data.length) {
SearchFieldStoreData[this.id].predictions[i] = response.data[i].title;
i += 1;
}
this.emit(
'load_predictions',
SearchFieldStoreData[this.id].requestedQuery,
SearchFieldStoreData[this.id].predictions
);
if (SearchFieldStoreData[this.id].pendingRequested) {
SearchFieldStoreData[this.id].requestedQuery = SearchFieldStoreData[this.id].pendingRequested.query;
getRequest(SearchFieldStoreData[this.id].pendingRequested.url, !1, this.dataResponse);
SearchFieldStoreData[this.id].pendingRequested = null;
} else {
SearchFieldStoreData[this.id].requestedQuery = null;
}
}
}
get(type) {
switch (type) {
case 'search-query':
return SearchFieldStoreData[this.id].searchQuery;
case 'search-categories':
return SearchFieldStoreData[this.id].categoriesQuery;
case 'search-tags':
return SearchFieldStoreData[this.id].tagsQuery;
}
return null;
}
actions_handler(action) {
switch (action.type) {
case 'REQUEST_PREDICTIONS':
let q = action.query;
let u = this.mediacms_config.api.search.titles + q;
if (SearchFieldStoreData[this.id].requestedQuery) {
if (SearchFieldStoreData[this.id].requestedQuery.q !== q) {
SearchFieldStoreData[this.id].pendingRequested = { query: q, url: u };
}
return;
}
SearchFieldStoreData[this.id].requestedQuery = q;
getRequest(u, !1, this.dataResponse);
break;
}
}
}
export default exportStore(new SearchFieldStore(), 'actions_handler');

View File

@@ -0,0 +1,96 @@
import EventEmitter from 'events';
import { exportStore } from '../helpers/';
import { BrowserCache } from '../classes/';
import { config as mediacmsConfig } from '../settings/config.js';
let browserCache;
const _StoreData = {};
class VideoPlayerStore extends EventEmitter {
constructor() {
super();
this.mediacms_config = mediacmsConfig(window.MediaCMS);
browserCache = new BrowserCache(this.mediacms_config.site.id, 86400); // Keep cache data "fresh" for one day.
_StoreData.inTheaterMode = browserCache.get('in-theater-mode');
_StoreData.inTheaterMode = null !== _StoreData.inTheaterMode ? _StoreData.inTheaterMode : !1;
_StoreData.playerVolume = browserCache.get('player-volume');
_StoreData.playerVolume =
null === _StoreData.playerVolume ? 1 : Math.max(Math.min(Number(_StoreData.playerVolume), 1), 0);
_StoreData.playerSoundMuted = browserCache.get('player-sound-muted');
_StoreData.playerSoundMuted = null !== _StoreData.playerSoundMuted ? _StoreData.playerSoundMuted : !1;
_StoreData.videoQuality = browserCache.get('video-quality');
_StoreData.videoQuality = null !== _StoreData.videoQuality ? _StoreData.videoQuality : 'Auto';
_StoreData.videoPlaybackSpeed = browserCache.get('video-playback-speed');
_StoreData.videoPlaybackSpeed = null !== _StoreData.videoPlaybackSpeed ? _StoreData.videoPlaybackSpeed : !1;
}
get(type) {
let r = null;
switch (type) {
case 'player-volume':
r = _StoreData.playerVolume;
break;
case 'player-sound-muted':
r = _StoreData.playerSoundMuted;
break;
case 'in-theater-mode':
r = _StoreData.inTheaterMode;
break;
case 'video-data':
r = _StoreData.videoData;
break;
case 'video-quality':
r = _StoreData.videoQuality;
break;
case 'video-playback-speed':
r = _StoreData.videoPlaybackSpeed;
break;
}
return r;
}
actions_handler(action) {
switch (action.type) {
case 'TOGGLE_VIEWER_MODE':
_StoreData.inTheaterMode = !_StoreData.inTheaterMode;
this.emit('changed_viewer_mode');
break;
case 'SET_VIEWER_MODE':
_StoreData.inTheaterMode = action.inTheaterMode;
browserCache.set('in-theater-mode', _StoreData.inTheaterMode);
this.emit('changed_viewer_mode');
break;
case 'SET_PLAYER_VOLUME':
_StoreData.playerVolume = action.playerVolume;
browserCache.set('player-volume', action.playerVolume);
this.emit('changed_player_volume');
break;
case 'SET_PLAYER_SOUND_MUTED':
_StoreData.playerSoundMuted = action.playerSoundMuted;
browserCache.set('player-sound-muted', action.playerSoundMuted);
this.emit('changed_player_sound_muted');
break;
case 'SET_VIDEO_QUALITY':
_StoreData.videoQuality = action.quality;
browserCache.set('video-quality', action.quality);
this.emit('changed_video_quality');
break;
case 'SET_VIDEO_PLAYBACK_SPEED':
_StoreData.videoPlaybackSpeed = action.playbackSpeed;
browserCache.set('video-playback-speed', action.playbackSpeed);
this.emit('changed_video_playback_speed');
break;
}
}
}
export default exportStore(new VideoPlayerStore(), 'actions_handler');

View File

@@ -0,0 +1,17 @@
import MediaPageStore from './MediaPageStore';
import PageStore from './PageStore';
import PlaylistPageStore from './PlaylistPageStore';
import PlaylistViewStore from './PlaylistViewStore';
import ProfilePageStore from './ProfilePageStore';
import SearchFieldStore from './SearchFieldStore';
import VideoViewerStore from './VideoViewerStore';
export {
MediaPageStore,
PageStore,
PlaylistPageStore,
PlaylistViewStore,
ProfilePageStore,
SearchFieldStore,
VideoViewerStore,
}