diff --git a/api/Playlists.php b/api/Playlists.php
index 6e80cf3f..55c7942f 100644
--- a/api/Playlists.php
+++ b/api/Playlists.php
@@ -680,15 +680,13 @@ public function deleteResource(RequestInterface $request): ResponseInterface {
}
private function injectMetadata($api, $rqMeta, $rsMeta, $listId, $size, $entry) {
- ob_start();
$action = $rqMeta->getOptional("action", "");
- PlaylistBuilder::newInstance([
+ $fragment = PlaylistBuilder::newInstance([
"action" => $action,
"editMode" => true,
"authUser" => true
])->observe($entry);
- $rsMeta->set("html", ob_get_contents());
- ob_end_clean();
+ $rsMeta->set("html", $fragment);
// seq is one of:
// -1 client playlist is out of sync with the service
diff --git a/ui/PlaylistBuilder.php b/ui/PlaylistBuilder.php
index 6f69fe5a..2c5aa06f 100644
--- a/ui/PlaylistBuilder.php
+++ b/ui/PlaylistBuilder.php
@@ -32,13 +32,7 @@ class PlaylistBuilder extends PlaylistObserver {
private const PARAMS = [ "action", "editMode", "authUser" ];
protected $params;
- protected $break;
-
- protected static function timestampToLocale($timestamp) {
- // colon is included in 24hr format for symmetry with fxtime
- $timeSpec = UI::isUsLocale() ? 'h:i a' : 'H:i';
- return $timestamp ? date($timeSpec, $timestamp) : '';
- }
+ protected $template;
public static function newInstance(array $params) {
// validate all parameters are present
@@ -54,88 +48,35 @@ public static function newInstance(array $params) {
return new PlaylistBuilder($params);
}
- protected function makeAlbumLink($entry, $includeLabel) {
- $albumName = $entry->getAlbum();
- $labelName = $entry->getLabel();
-
- if(empty($albumName) && empty($labelName))
- return "";
-
- $albumTitle = $entry->getTag() ?
- "" . htmlentities($albumName) . "" :
- UI::smartURL($albumName);
-
- if($includeLabel)
- $albumTitle .= " / " . UI::smartURL($labelName) . "";
-
- return $albumTitle;
- }
-
- protected function makeEditDiv($entry) {
- $href = "?id=" . $entry->getId() . "&subaction=" . $this->params["action"] . "&seq=editTrack";
- $editLink = "";
- $dnd = "
";
- return "" . $dnd . $editLink . "
";
+ protected function renderBlock($block, $entry) {
+ return $this->template->renderBlock($block, [
+ "params" => $this->params,
+ "entry" => $entry
+ ]);
}
protected function __construct(array $params) {
+ $templateFact = new TemplateFactoryUI();
+ $this->template = $templateFact->load('list/block-event.html');
$this->params = $params;
+ $this->params['break'] = false;
+ $this->params['usLocale'] = UI::isUsLocale();
$this->on('comment', function($entry) {
- $editCell = $this->params["editMode"] ? "" .
- $this->makeEditDiv($entry) . " | " : "";
- $created = $entry->getCreatedTimestamp();
- $timeplayed = self::timestampToLocale($created);
- echo "\n";
- $this->break = false;
+ $fragment = $this->renderBlock('comment', $entry);
+ $this->params['break'] = false;
+ return $fragment;
})->on('logEvent', function($entry) {
- $created = $entry->getCreatedTimestamp();
- $timeplayed = self::timestampToLocale($created);
- if($this->params["authUser"]) {
- // display log entries only for authenticated users
- $editCell = $this->params["editMode"] ? "" .
- $this->makeEditDiv($entry) . " | " : "";
- echo "" . $editCell .
- "$timeplayed | " .
- "".$entry->getLogEventType()." | " .
- "".$entry->getLogEventCode()." | " .
- "
\n";
- $this->break = false;
- } else if(!$this->break) {
- echo "" .
- "$timeplayed |
|
\n";
- $this->break = true;
- }
+ $fragment = $this->renderBlock('logEvent', $entry);
+ $this->params['break'] = !$this->params['authUser'];
+ return $fragment;
})->on('setSeparator', function($entry) {
- if($this->params["editMode"] || !$this->break) {
- $editCell = $this->params["editMode"] ? "" .
- $this->makeEditDiv($entry) . " | " : "";
- $created = $entry->getCreatedTimestamp();
- $timeplayed = self::timestampToLocale($created);
- echo "" . $editCell .
- "$timeplayed |
|
\n";
- $this->break = true;
- }
+ $fragment = $this->renderBlock('setSeparator', $entry);
+ $this->params['break'] = true;
+ return $fragment;
})->on('spin', function($entry) {
- $editCell = $this->params["editMode"] ? "" .
- $this->makeEditDiv($entry) . " | " : "";
- $created = $entry->getCreatedTimestamp();
- $timeplayed = self::timestampToLocale($created);
- $reviewCell = $entry->getReviewed() ? "" : "";
- $artistName = $entry->getTag() ? PlaylistEntry::swapNames($entry->getArtist()) : $entry->getArtist();
-
- $albumLink = $this->makeAlbumLink($entry, true);
- echo "" . $editCell .
- "$timeplayed | " .
- "" . UI::smartURL($artistName) . " | " .
- "" . UI::smartURL($entry->getTrack()) . " | " .
- "$reviewCell | " .
- "$albumLink | " .
- "
\n";
- $this->break = false;
+ $fragment = $this->renderBlock('spin', $entry);
+ $this->params['break'] = false;
+ return $fragment;
});
}
}
diff --git a/ui/Playlists.php b/ui/Playlists.php
index f1dc42e1..2dd24605 100644
--- a/ui/Playlists.php
+++ b/ui/Playlists.php
@@ -263,48 +263,28 @@ private function getDJAirNames() {
return $airNames;
}
- // make header for edit & view playlist
- private function makePlaylistHeader($isEditMode) {
- $editCol = $isEditMode ? " | " : "";
- $header = "" . $editCol . "Time | " .
- "Artist | Track | | Album/Label |
";
- return $header;
- }
-
private function emitPlaylistBody($playlist, $editMode) {
- $header = $this->makePlaylistHeader($editMode);
- $editCell = "";
- echo "\n";
- echo "" . $header . "";
-
$api = Engine::api(IPlaylist::class);
- $entries = $api->getTracks($playlist, $editMode)->asArray();
- Engine::api(ILibrary::class)->markAlbumsReviewed($entries);
+ $tracks = $api->getTracks($playlist, $editMode)->asArray();
+ Engine::api(ILibrary::class)->markAlbumsReviewed($tracks);
$observer = PlaylistBuilder::newInstance([
"action" => $this->subaction,
"editMode" => $editMode,
"authUser" => $this->session->isAuth("u")
]);
- echo "\n";
- if($entries != null && sizeof($entries) > 0) {
- foreach($entries as $entry)
- $observer->observe(new PlaylistEntry($entry));
- }
- echo "
\n";
- if($editMode) {
- UI::emitJS('js/playlists.track.js');
- } else {
- $show = $api->getPlaylist($playlist);
- if($api->isNowWithinShow($show))
- UI::emitJS('js/playlists.live.js');
- }
+ $entries = array_map(function($track) {
+ return new PlaylistEntry($track);
+ }, $tracks);
+
+ $this->addVar("observer", $observer);
+ $this->addVar("entries", $entries);
+ $this->addVar("editMode", $editMode);
}
private function emitPlaylistBanner($playlistId, $playlist, $editMode) {
$showName = $playlist['description'];
- $djId = $playlist['id'];
$djName = $playlist['airname'] ?? "None";
$showDateTime = self::makeShowDateAndTime($playlist);
@@ -312,280 +292,108 @@ private function emitPlaylistBanner($playlistId, $playlist, $editMode) {
$this->extra = "Share Playlist: ";
- if(!$editMode && $this->session->isAuth("v"))
- $showDateTime .= " ";
-
- $djName = htmlentities($djName, ENT_QUOTES, 'UTF-8');
- $djLink = $djId ? "$djName" : $djName;
-
- echo " ".htmlentities($showName, ENT_QUOTES, 'UTF-8')." with $djLink{$showDateTime}
\n";
-?>
-
- emitPlaylistBody($playlistId, true);
+ $this->addVar("showDateTime", $showDateTime);
}
private function emitTagForm($playlistId, $message) {
$playlist = Engine::api(IPlaylist::class)->getPlaylist($playlistId, 1);
$this->emitPlaylistBanner($playlistId, $playlist, true);
$this->emitTrackAdder($playlistId, $playlist);
+ $this->setTemplate('list/entry-add.html');
}
private function emitTrackAdder($playlistId, $playlist, $editTrack = false) {
- $isLiveShow = !$editTrack && Engine::api(IPlaylist::class)->isNowWithinShow($playlist);
- $nmeAr = Engine::param('nme');
- $nmeOpts = '';
- $nmePrefix = self::NME_PREFIX;
- if ($nmeAr) {
- foreach ($nmeAr as $nme)
- $nmeOpts = $nmeOpts . "";
- }
-
- ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- data-focus/>
-
-
-
- getTimestampWindow($playlistId);
- $time = null;
- $api->getTracksWithObserver($playlistId,
- (new PlaylistObserver())->on('comment logEvent setSeparator spin', function($entry) use(&$time, $editTrack) {
- $created = $entry->getCreatedTime();
- if($created) $time = $created;
- return $editTrack === $entry->getId();
- })
- );
- if(!$time) {
- $startTime = $api->getTimestampWindow($playlistId, false)['start'];
- $time = $startTime->format('H:i:s');
- }
+ $api = Engine::api(IPlaylist::class);
- // this is probably unnecessary, as desktop browsers *should*
- // degrade 'tel' to 'text', *but* as this is a hack to
- // deal with the lack of keyDown support in mobile input
- // type=text, we'll include 'tel' only for mobile devices...
- $ttype = preg_match('/tablet|mobile|android/i',
- $_SERVER['HTTP_USER_AGENT'] ?? '') ? "tel" : "text";
-
- // colon is included in 24hr format for symmetry with fxtime,
- // which it is referencing
- $timeSpec = UI::isUsLocale() ? 'g:i a' : 'H:i';
- $startAMPM = $window['start']->format($timeSpec);
- $endAMPM = $window['end']->format($timeSpec);
- $timeMsg = "($startAMPM - $endAMPM)";
-
- echo "
-
- format('H:i')."' max='".$window['end']->format('H:i')."' data-live='".($isLiveShow?1:0)."' data-last-val='$time' />
- $timeMsg
-
\n";
- ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- addVar('NME_PREFIX', self::NME_PREFIX);
+ $this->addVar('BASE_URL', Engine::getBaseURL());
+
+ /* TZO is server equivalent of javascript Date.getTimezoneOffset() */
+ $this->addVar('TZO', round(date('Z')/-60, 2));
+ $this->addVar('playlistId', $playlistId);
+ $this->addvar('playlist', $playlist);
+ $this->addVar('editTrack', $editTrack);
+ $this->addVar('isLive', $api->isNowWithinShow($playlist));
+
+ $this->addVar('MAX_FIELD_LENGTH', PlaylistEntry::MAX_FIELD_LENGTH);
+ $this->addVar('MAX_COMMENT_LENGTH', PlaylistEntry::MAX_COMMENT_LENGTH);
+ $this->addVar('nmes', Engine::param('nme'));
+
+ $window = $api->getTimestampWindow($playlistId);
+ $time = null;
+ $api->getTracksWithObserver($playlistId,
+ (new PlaylistObserver())->on('comment logEvent setSeparator spin', function($entry) use(&$time, $editTrack) {
+ $created = $entry->getCreatedTime();
+ if($created) $time = $created;
+ return $editTrack === $entry->getId();
+ })
+ );
+ if(!$time) {
+ $startTime = $api->getTimestampWindow($playlistId, false)['start'];
+ $time = $startTime->format('H:i:s');
+ }
+ $this->addVar('time', $time);
+
+ // this is probably unnecessary, as desktop browsers *should*
+ // degrade 'tel' to 'text', *but* as this is a hack to
+ // deal with the lack of keyDown support in mobile input
+ // type=text, we'll include 'tel' only for mobile devices...
+ $ttype = preg_match('/tablet|mobile|android/i',
+ $_SERVER['HTTP_USER_AGENT'] ?? '') ? "tel" : "text";
+ $this->addVar("ttype", $ttype);
+
+ // colon is included in 24hr format for symmetry with fxtime,
+ // which it is referencing
+ $timeSpec = UI::isUsLocale() ? 'g:i a' : 'H:i';
+ $startAMPM = $window['start']->format($timeSpec);
+ $endAMPM = $window['end']->format($timeSpec);
+ $timeMsg = "($startAMPM - $endAMPM)";
+ $this->addVar("window", $window);
+ $this->addVar("timeMsg", $timeMsg);
}
private function emitEditForm($playlistId, $id, $album) {
- ?>
- Editing highlighted item
-
- getType()) {
- case PlaylistEntry::TYPE_SET_SEPARATOR:
- $type = "set-separator";
- break;
- case PlaylistEntry::TYPE_COMMENT:
- $type = "comment-entry";
- echo "\n";
- break;
- case PlaylistEntry::TYPE_LOG_EVENT:
- $type = self::NME_PREFIX . $entry->getLogEventType();
- echo "\n";
- break;
- default:
- $type = "manual-entry";
- foreach (['tag', 'artist', 'album', 'label', 'title'] as $field)
- echo "\n";
- break;
- }
- echo "\n";
- echo "\n";
-
$playlist = Engine::api(IPlaylist::class)->getPlaylist($playlistId, 1);
$showName = $playlist['description'];
$djName = $playlist['airname'] ?? "None";
$this->title = "$showName with $djName " . self::timestampToDate($playlist['showdate']);
$this->emitTrackAdder($playlistId, $playlist, $id);
+ $this->addVar("entry", $entry);
+ $this->setTemplate('list/entry-edit.html');
}
public function emitEditor() {
- $playlist = $_REQUEST["playlist"] ?? null;
+ $playlistId = $_REQUEST["playlist"] ?? null;
$seq = $_REQUEST["seq"] ?? null;
$id = $_REQUEST["id"] ?? null;
- ?>
-
-
- getTrack($id);
if($albuminfo) {
// if editing a track, always get the playlist from
// the track, even if one is supplied in the request
- $playlist = $albuminfo['list'];
+ $playlistId = $albuminfo['list'];
}
}
$message = "";
- if(is_null($playlist) || !$this->isOwner($playlist)) {
+ if(is_null($playlistId) || !$this->isOwner($playlistId)) {
$seq = "error";
$message = "access error";
}
switch ($seq) {
case "editTrack":
- $this->emitEditForm($playlist, $id, $albuminfo);
+ $this->emitEditForm($playlistId, $id, $albuminfo);
break;
default:
- $this->emitTagForm($playlist, $message);
+ $this->emitTagForm($playlistId, $message);
break;
}
- ?>
- |
-
- editPlaylist($playlist, $id); ?>
- |
-
- emitPlaylistBody($playlistId, true);
}
private function insertTrack($playlistId, $tag, $artist, $track, $album, $label, $spinTime) {
@@ -873,6 +681,10 @@ private function viewList($playlistId) {
$this->emitPlaylistBanner($playlistId, $row, false);
$this->emitPlaylistBody($playlistId, false);
+
+ $this->addVar("playlist", $row);
+ $this->addVar("playlistId", $playlistId);
+ $this->setTemplate('list/view.html');
}
public function emitViewDJ() {
diff --git a/ui/TemplateFactoryUI.php b/ui/TemplateFactoryUI.php
index 4f6859ff..1b98426b 100644
--- a/ui/TemplateFactoryUI.php
+++ b/ui/TemplateFactoryUI.php
@@ -33,6 +33,9 @@ public function __construct() {
$filter = new \Twig\TwigFilter('smartURL', [ '\ZK\UI\UICommon', 'smartURL' ], [ 'is_safe' => [ 'html' ] ]);
$this->twig->addFilter($filter);
+
+ $filter = new \Twig\TwigFilter('markdown', [ '\ZK\UI\UICommon', 'markdown' ], [ 'is_safe' => [ 'html' ] ]);
+ $this->twig->addFilter($filter);
}
public function setContext($menu = null, $menuItem = null, $html = null) {
diff --git a/ui/templates/default/list/block-banner.html b/ui/templates/default/list/block-banner.html
new file mode 100644
index 00000000..cfb246c9
--- /dev/null
+++ b/ui/templates/default/list/block-banner.html
@@ -0,0 +1,30 @@
+{% set showName = playlist.description %}
+{% set djId = playlist.id %}
+{% set djName = playlist.airname ?? "None" %}
+{% set djLink = djId ? "" ~ djName | e ~ "" : djName | e %}
+
+ {{ showName }} with {{ djLink | raw }}{{ showDateTime }}
+{%- if editMode and app.session.isAuth('v') -%}
+
"
+{%- endif -%}
+
+
+
diff --git a/ui/templates/default/list/block-body.html b/ui/templates/default/list/block-body.html
new file mode 100644
index 00000000..e7df4dae
--- /dev/null
+++ b/ui/templates/default/list/block-body.html
@@ -0,0 +1,22 @@
+
+
+
+ {{ editMode ? " | " }}
+ Time |
+ Artist |
+ Track |
+ |
+ Album/Label |
+
+
+
+ {%~ for entry in entries %}
+ {{~ observer.observe(entry) | raw }}
+ {%~ endfor %}
+
+
+{% if editMode %}
+
+{% elseif isLive %}
+
+{% endif %}
diff --git a/ui/templates/default/list/block-entry.html b/ui/templates/default/list/block-entry.html
new file mode 100644
index 00000000..e31371bf
--- /dev/null
+++ b/ui/templates/default/list/block-entry.html
@@ -0,0 +1,115 @@
+{% set isLiveShow = not editTrack and isLive %}
+
+
+ {#~ TZO is server equivalent of javascript Date.getTimezoneOffset() #}
+
+
+
+
+
+
+ {%~ if not editTrack %}
+
+ {% endif %}
+
+
+
+
+
+
+
+ {{ timeMsg }}
+
+
+
+
+ {% if editTrack %}
+
+
+
+ {% else %}
+
+
+ {% endif %}
+
+
+
+
+
+
diff --git a/ui/templates/default/list/block-event.html b/ui/templates/default/list/block-event.html
new file mode 100644
index 00000000..25e32ed8
--- /dev/null
+++ b/ui/templates/default/list/block-event.html
@@ -0,0 +1,72 @@
+{% macro makeTime(params, entry) %}
+ {%~ set created = entry.getCreatedTimestamp() %}
+ {%~ set format = params.usLocale ? "h:i a" : "H:i" %}
+ {{ created ? created | date(format) }} |
+{%- endmacro %}
+
+{% macro makeEditDiv(params, entry) %}
+ {%~ if params.editMode %}
+ {%~ set href = "?id=" ~ entry.getId() | e('url') ~ "&subaction=" ~ params.action | e('url') ~ "&seq=editTrack" %}
+ {%~ set editLink = "" %}
+ {%~ set dnd = "" %}
+
+ {{ dnd | raw }}{{ editLink | raw }}
+ |
+ {%~ endif %}
+ {{~ _self.makeTime(params, entry) }}
+{%- endmacro %}
+
+{% macro makeAlbumLink(entry, includeLabel) %}
+ {%~ set albumName = entry.getAlbum() %}
+ {%~ set labelName = entry.getLabel() %}
+ {%~ if albumName | length or labelName | length %}
+ {%~ set albumTitle = entry.getTag() ? "" ~ albumName | e ~ "" : albumName | e %}
+ {%~ if includeLabel %}
+ {%~ set albumTitle = albumTitle ~ " / " ~ labelName | e ~ "" %}
+ {%~ endif %}
+ {{~ albumTitle | raw -}}
+ {%~ endif %}
+{% endmacro %}
+
+{% block comment %}
+
+{% endblock %}
+
+{% block logEvent %}
+ {%~ if params.authUser %}
+
+ {{~ _self.makeEditDiv(params, entry) }}
+ {{ entry.getLogEventType() }} |
+ {{ entry.getLogEventCode() }} |
+
+ {%~ elseif not params.break %}
+
+ {{~ _self.makeTime(params, entry) }}
+
|
+
+ {%~ endif %}
+{% endblock %}
+
+{% block setSeparator %}
+ {%~ if params.editMode or not params.break %}
+
+ {{~ _self.makeEditDiv(params, entry) }}
+
|
+
+ {%~ endif %}
+{% endblock %}
+
+{% block spin %}
+ {%~ set reviewCell = entry.getReviewed() ? "" %}
+ {%~ set artistName = entry.getTag() ? entry.swapNames(entry.getArtist()) : entry.getArtist() %}
+
+ {{~ _self.makeEditDiv(params, entry) }}
+ {{ artistName | smartURL }} |
+ {{ entry.getTrack() | smartURL }} |
+ {{ reviewCell | raw }} |
+ {{ _self.makeAlbumLink(entry, true) }} |
+
+{% endblock %}
diff --git a/ui/templates/default/list/entry-add.html b/ui/templates/default/list/entry-add.html
new file mode 100644
index 00000000..700b2433
--- /dev/null
+++ b/ui/templates/default/list/entry-add.html
@@ -0,0 +1,3 @@
+{% include 'list/block-banner.html' %}
+{% include 'list/block-entry.html' %}
+{% include 'list/block-body.html' %}
diff --git a/ui/templates/default/list/entry-edit.html b/ui/templates/default/list/entry-edit.html
new file mode 100644
index 00000000..cf7b9450
--- /dev/null
+++ b/ui/templates/default/list/entry-edit.html
@@ -0,0 +1,23 @@
+ Editing highlighted item
+
+{% if entry.getType() == constant('TYPE_SET_SEPARATOR', entry) %}
+{% set type='set-separator' %}
+{% elseif entry.getType() == constant('TYPE_COMMENT', entry) %}
+{% set type='comment-entry' %}
+
+{% elseif entry.getType() == constant('TYPE_LOG_EVENT', entry) %}
+{% set type=NME_PREFIX ~ entry.getLogEventType() %}
+
+{% else %}
+{% set type='manual-entry' %}
+{% set album = entry.asArray() %}
+{% for field in ['tag', 'artist', 'album', 'label', 'title'] %}
+
+{% endfor %}
+{% endif %}
+
+
+
+
+{% include 'list/block-entry.html' %}
+{% include 'list/block-body.html' %}
diff --git a/ui/templates/default/list/view.html b/ui/templates/default/list/view.html
new file mode 100644
index 00000000..13324fe2
--- /dev/null
+++ b/ui/templates/default/list/view.html
@@ -0,0 +1,2 @@
+{% include 'list/block-banner.html' %}
+{% include 'list/block-body.html' %}
- formatting help -