scratchpad reloads playlists when logging in/out.

Drag to reorder done on table. template redone to work with jQuery.
This commit is contained in:
naomiaro 2010-09-23 17:04:09 -04:00
parent 1d141c56ae
commit c8e1e7fc9a
9 changed files with 556 additions and 223 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,115 @@
.pl_container {
width:607px;
background:#5286BA;
}
.pl_header {
height: 25px;
color:#ffffff;
font-weight: bold;
padding: 8px 20px 0 20px;
}
.pl_header_left {
float:left;
}
.pl_header_left span {
font-size: 18px;
}
.pl_header_right {
float:right;
}
.pl_header_right span {
font-size: 16px;
padding-left: 20px;
}
.pl_contents {
clear:left;
}
.pl_contents form{
margin:0;
}
#pl_sortable {
list-style-type: none;
padding: 0;
margin: 0;
}
.pl_head {
background-color: #8baed1;
margin-top: 10px;
}
.pl_head span {
display:inline-block;
}
.pl_main {
clear: left;
}
.pl_row {
background-color: #d5e2ee;
clear:left;
cursor:move;
}
.pl_row span {
display:inline-block;
}
.pl_input{
width: 5%;
}
.pl_title{
width: 25%;
}
.pl_artist{
width: 24%;
}
.pl_length{
width: 9%;
}
.pl_cue_in{
width: 9%;
}
.pl_cue_out{
width: 9%;
}
.pl_playlength{
width: 9%;
}
.pl_empty{
text-align: center;
font-weight:bold;
font-size: 18px;
color: #ffffff;
margin: 1em 0;
}
.pl_footer {
clear:left;
font-size: 12px;
padding: 4px 5px 5px 0;
background-color: #8baed1;
text-align: right;
margin-bottom: 8px;
}
.pl_container_button {
text-align: right;
padding: 6px;
}

View File

@ -0,0 +1,52 @@
$(document).ready(function() {
$("#pl_sortable").sortable();
$("#pl_sortable" ).bind( "sortstop", function(event, ui) {
var li, newPos, oldPos;
li = ui.item;
newPos = $(this).children().index(li);
oldPos = li.attr('id').split("_").pop();
$.post("ui_handler.php",
{ 'act': 'PL.moveItem', 'oldPos': oldPos, 'newPos': newPos },
function(data){
var ul = $("#pl_sortable");
if(data.error) {
var size,
tmp_ul;
size = $(ul).children().size();
tmp_ul = $("<ul/>");
for(var i=0; i<size; i++)
{
tmp_ul.append(ul.find("#pl_"+i));
}
//restore the UI to the previous order.
$(ul).empty();
$(ul).html(tmp_ul.contents());
alert(data.error);
}
else {
//redo playlist positional ids.
$(ul).children().each(function(index){
var li = $(this);
li.attr('id', 'pl_'+index);
});
}
},
"json"
);
});
});

View File

@ -128,7 +128,7 @@ switch ($_REQUEST['act']) {
case "SEARCH.newSearch":
$uiHandler->SEARCH->newSearch($_REQUEST);
$NO_REDIRECT = true;
$NO_REDIRECT = true;
$_REQUEST["act"] = "SEARCH";
include("ui_browser.php");
break;
@ -367,7 +367,6 @@ switch ($_REQUEST['act']) {
case "PL.moveItem":
$uiHandler->PLAYLIST->moveItem($_REQUEST['oldPos'], $_REQUEST['newPos']);
$uiHandler->PLAYLIST->setReload();
break;
case "PL.reorder":

View File

@ -6,11 +6,12 @@
<title>Campcaster</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
{* <link rel="stylesheet" href="styles.css"> *}
<link href="styles_campcaster.css" rel="stylesheet" type="text/css" />
<link href="styles_campcaster.css" rel="stylesheet" type="text/css" />
<link href="assets/plupload/plupload.queue.css" rel="stylesheet" type="text/css" />
<link href="css/playlist.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="assets/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="assets/jquery-ui-1.7.3.custom.min.js"></script>
<script type="text/javascript" src="assets/plupload/plupload.full.min.js"></script>
<script type="text/javascript" src="assets/plupload/jquery.plupload.queue.min.js"></script>
@ -21,6 +22,8 @@
{include file="script/collector.js.tpl"}
{include file="script/alttext.js.tpl"}
<script type="text/javascript" src="js/playlist.js"></script>
</head>
<body>

View File

@ -1,97 +1,65 @@
<!-- start playlist editor -->
<div class="container_elements" style="width: 607px;">
<div style="width: 574px;">
<div style="float: left;"><h1>##Playlist Editor## </h1></div>
<div style="float: right;"><h1><a href="{$UI_BROWSER}?act=PL.editMetaData" style="color: #666666">{$PL->title} &nbsp; {niceTime in=$PL->duration} &nbsp;</a></h1></div>
</div>
<div class="head" style="width: 574px;">
<div class="left">&nbsp;</div>
<div class="right">&nbsp;</div>
<div class="clearer">&nbsp;</div>
</div>
<div class="container_table" style="width: 594px;">
<table style="width: 574px;">
<form name="PL">
<!-- start repeat after 14 columns -->
<tr class="blue_head">
<td style="width: 30px"><input type="checkbox" name="all" onClick="collector_switchAll('PL')"></td>
<td style="width: 200px">##Title##</td>
<td style="white-space: nowrap">##Clip length##</td>
<td>##Cue In##</td>
<td>##Cue Out##</td>
<td style="width: 200px">##Artist##</td>
<td style="width: 30px;">##Type##</td>
<td style="width: 30px; border: 0">##Move##</td>
</tr>
<!-- end repeat after 14 columns -->
<!-- start item -->
{foreach from=$PL->getActiveArr($PL->activeId) key='pos' item='i'}
<!-- fade information -->
<tr onClick="return contextmenu('{$i.attrs.id}', {if $i.firstInList == 1}'PL.changeFadeIn'{else}'PL.changeTransition'{/if})" style="background-color: #bbb">
<td></td>
<td colspan="7" style="border: 0; cursor: pointer">##Fade In## {$i.fadein|string_format:"%d"} ms</td>
</tr>
<!-- /fade information -->
<tr class="{cycle values='blue1, blue2'}">
<td><input type="checkbox" class="checkbox" name="{$pos}"/></td>
<td {include file="playlist/actionhandler.tpl"}>{$i.track_title}</td>
<td {include file="playlist/actionhandler.tpl"} style="text-align: right">
{assign var="_playlength" value=$i.cliplength}{niceTime in=$_playlength}
</td>
<td {include file="playlist/actionhandler.tpl"} style="text-align: right">
{assign var="_duration" value=$i.cuein}{niceTime in=$_duration}
</td>
<td {include file="playlist/actionhandler.tpl"} style="text-align: right">
{assign var="_duration" value=$i.cueout}{niceTime in=$_duration}
</td>
<td {include file="playlist/actionhandler.tpl"}>{$i.artist_name}</td>
<td {include file="playlist/actionhandler.tpl"}>
<img src="img/{$i.type}.png" border="0" alt="{$i.ftype|capitalize}" {* include file="sub/alttext.tpl" *} />
</td>
<td style="border: 0">
<a href="#" onClick="hpopup('{$UI_HANDLER}?act=PL.moveItem&oldPos={$pos}&newPos={$pos-1}')"><img src="img/bt_top_xsm.png" alt="##move up##" vspace=1 hspace=1/></a>
<a href="#" onClick="hpopup('{$UI_HANDLER}?act=PL.moveItem&oldPos={$pos}&newPos={$pos+1}')"><img src="img/bt_bottom_xsm.png" alt="##move down##" vspace=1 hspace=1/></a>
</td>
</tr>
<!-- fade information -->
<tr onClick="return contextmenu('{$i.attrs.id}', 'PL.changeFadeOut')" style="background-color: #bbb">
<td></td>
<td colspan="7" style="border: 0; cursor: pointer">##Fade Out## {$i.fadeout|string_format:"%d"} ms</td>
</tr>
<!-- /fade information -->
{/foreach}
{if isset($pos)}
{else}
<tr class="{cycle values='blue1, blue2'}">
<td style="border: 0" colspan="7" align="center">##Empty playlist##</td>
</tr>
{/if}
<!-- end item -->
</form>
</table>
</div>
<div class="footer" style="width: 569px;">
{* <input type="button" class="button_large" onClick="collector_submit('PL', '0&popup[]=PL.changeAllTransitions', '{$UI_BROWSER}', 'chgAllTrans', 400, 150)" value="##Change Fades##" /> *}
<input type="button" class="button_large" onClick="collector_submit('PL', 'PL.removeItem')" value="##Remove Selected##" />
<input type="button" class="button_large" onClick="collector_clearAll('PL', 'PL.removeItem')" value="##Clear Playlist##" />
</div>
<div class="container_button">
<input type="button" class="button_large" value="##Delete Playlist##" onClick="popup('{$UI_BROWSER}?popup[]=PL.confirmDelete', 'PL.deleteActive', 400, 50)">
</div>
<div class="container_button">
<input type="button" class="button_large" value="##Reorder Playlist##" onClick="popup('{$UI_BROWSER}?popup[]=PL.arrangeItems', 'PL.arrangeItems', 533, 600)">
<input type="button" class="button_large" value="##Close Playlist##" onClick="popup('{$UI_BROWSER}?popup[]=PL.confirmRelease', 'PL.confirmRelease', 400, 50)">
<input type="button" class="button_large" value="##Description##" onClick="location.href='{$UI_BROWSER}?act=PL.editMetaData'">
</div>
</div>
<!-- start new and improved! playlist editor -->
<div class="pl_container" >
<div class="pl_header">
<div class="pl_header_left"><span>##Playlist Editor## </span></div>
<div class="pl_header_right"><span>{$PL->title}</span><span>{niceTime in=$PL->duration} </span></div>
</div>
<div class="pl_contents">
<form name="PL">
<div class="pl_head">
<span class="pl_input"><input type="checkbox" name="all" onClick="collector_switchAll('PL')"></span>
<span class="pl_title">##Title##</span>
<span class="pl_artist">##Artist##</span>
<span class="pl_length">##Length##</span>
<span class="pl_cue_in">##Cue In##</span>
<span class="pl_cue_out">##Cue Out##</span>
<span class="pl_playlength">##Playlength##</span>
</div>
<div class="pl_main">
<ul id="pl_sortable">
{foreach from=$PL->getActiveArr($PL->activeId) key='pos' item='i'}
<li class="pl_row" id="pl_{$pos}">
<span class="pl_input">
<input type="checkbox" class="checkbox" name="{$pos}"/>
</span>
<span class="pl_title">
{$i.track_title}
</span>
<span class="pl_artist">
{$i.artist_name}
</span>
<span class="pl_length" >
{assign var="_playlength" value=$i.length}{niceTime in=$_playlength}
</span>
<span class="pl_cue_in">
{assign var="_duration" value=$i.cuein}{niceTime in=$_duration}
</span>
<span class="pl_cue_out">
{assign var="_duration" value=$i.cueout}{niceTime in=$_duration}
</span>
<span class="pl_playlength">
{assign var="_duration" value=$i.cliplength}{niceTime in=$_duration}
</span>
</li>
{/foreach}
{if is_null($pos)}
<li class="pl_empty">##Empty playlist##</li>
{/if}
</ul>
</div>
</form>
</div>
<div class="pl_footer">
<input type="button" class="button_large" onClick="collector_submit('PL', 'PL.removeItem')" value="##Remove Selected##" />
<input type="button" class="button_large" onClick="collector_clearAll('PL', 'PL.removeItem')" value="##Clear Playlist##" />
</div>
<div class="pl_container_button">
<input type="button" class="button_large" value="##Close Playlist##" onClick="popup('{$UI_BROWSER}?popup[]=PL.confirmRelease', 'PL.confirmRelease', 400, 50)">
<input type="button" class="button_large" value="##Description##" onClick="location.href='{$UI_BROWSER}?act=PL.editMetaData'">
<input type="button" class="button_large" value="##Delete Playlist##" onClick="popup('{$UI_BROWSER}?popup[]=PL.confirmDelete', 'PL.deleteActive', 400, 50)">
</div>
</div>
<script type="text/javascript">
document.forms['PL'].elements['all'].checked = false;

View File

@ -55,6 +55,7 @@ class uiPlaylist
private function getPLArray($id)
{
$res = $this->Base->gb->getPlaylistArray($id);
$_SESSION['pl'] = $res;
return $res;
} // fn getPLArray
@ -107,7 +108,6 @@ class uiPlaylist
$this->Base->gb->savePref($this->Base->sessid, UI_PL_ACCESSTOKEN_KEY, $plid);
$this->activeId = $plid;
$_SESSION['pl'] = "Activating playlist with id: " . $this->activeId;
if ($msg && UI_VERBOSE) {
$this->Base->_retMsg('Playlist "$1" opened.', $this->Base->getMetadataValue($plid, UI_MDATA_KEY_TITLE));
@ -302,56 +302,6 @@ class uiPlaylist
return $plid;
} // fn create
/**
* WARNING: THIS FUNCTION IS REALLY SSSLLLLOOOOWWWW!
*
* @param unknown_type $id
* @return array
*/
public function getFlat($id)
{
$this->flat = array();
$this->_plwalk($this->getPLArray($id));
if (count($this->flat) > 0) {
reset($this->flat);
$this->flat[key($this->flat)]['firstInList'] = true;
end($this->flat);
$this->flat[key($this->flat)]['lastInList'] = true;
reset($this->flat);
return $this->flat;
} else {
return array();
}
} // fn getFlat
private function _plwalk($arr, $parent=0, $attrs=0)
{
// Note: the array $this->flat needs to be initialized before
// this function is called.
foreach ($arr['children'] as $node => $sub) {
if ($sub['elementname']===UI_PL_ELEM_PLAYLIST) {
$this->_plwalk($sub, $node, $sub['attrs']);
}
if ($sub['elementname']===UI_FILETYPE_AUDIOCLIP || $sub['elementname']===UI_FILETYPE_PLAYLIST) {
#$this->flat["$parent.$node"] = $sub['attrs'];
#$this->flat["$parent.$node"]['type'] = $sub['elementname'];
$this->flat[$parent] = $this->Base->getMetaInfo(BasicStor::IdFromGunid($sub['attrs']['id']));
$this->flat[$parent]['attrs'] = $attrs;
$this->flat[$parent]['playlength'] = $sub['attrs']['playlength'];
}
if ($sub['elementname']===UI_PL_ELEM_FADEINFO) {
$this->flat[$parent][UI_PL_ELEM_FADEIN] = Playlist::playlistTimeToSeconds($sub['attrs'][UI_PL_ELEM_FADEIN]);
$this->flat[$parent][UI_PL_ELEM_FADEOUT] = Playlist::playlistTimeToSeconds($sub['attrs'][UI_PL_ELEM_FADEOUT]);
$this->flat[$parent]['fadein_ms'] = $sub['attrs'][UI_PL_ELEM_FADEIN] ? Playlist::playlistTimeToSeconds($sub['attrs'][UI_PL_ELEM_FADEIN]) * 1000 : 0;
$this->flat[$parent]['fadeout_ms'] = $sub['attrs'][UI_PL_ELEM_FADEOUT] ? Playlist::playlistTimeToSeconds($sub['attrs'][UI_PL_ELEM_FADEOUT]) * 1000 : 0;
}
}
} // fn _plwalk
public function changeTransition($id, $type, $duration)
{
$pause = $pause;
@ -422,74 +372,22 @@ class uiPlaylist
public function moveItem($oldPos, $newPos)
{
$response = array();
$r = $this->Base->gb->moveAudioClipInPlaylist($this->activeId, $oldPos, $newPos);
if (PEAR::isError($r) || $r === FALSE) {
if (UI_VERBOSE === TRUE) {
print_r($r);
}
$this->Base->_retMsg('Cannot move item.');
return FALSE;
$response["error"] = "Failed to Move file.";
$response["oldPos"] = $oldPos;
$response["newPos"] = $newPos;
}
return TRUE;
else{
$response["error"] = FALSE;
}
die(json_encode($response));
} // fn moveItem
public function reorder($items)
{
// just to be sure items are in right order
asort($items);
$pos = 0;
foreach ($items as $id => $v) {
$pos++;
$r = $this->Base->gb->moveAudioClipInPlaylist($this->token, $id, $pos, $this->Base->sessid);
if (PEAR::isError($r)) {
if (UI_VERBOSE === TRUE) {
print_r($r);
}
$this->Base->_retMsg('Cannot move item.');
return FALSE;
}
}
return TRUE;
} // fn reorder
private function getCurrElement($id)
{
$arr = $this->getFlat($this->activeId);
while ($val = current($arr)) {
if ($val['attrs']['id'] == $id) {
return current($arr);
}
next($arr);
}
} // fn getCurrElement
private function getPrevElement($id)
{
$arr = $this->getFlat($this->activeId);
while ($val = current($arr)) {
if ($val['attrs']['id'] == $id) {
return prev($arr);
}
next($arr);
}
} // fn getPrevElement
private function getNextElement($id)
{
$arr = $this->getFlat($this->activeId);
while ($val = current($arr)) {
if ($val['attrs']['id'] == $id) {
return next($arr);
}
next($arr);
}
} // fn getNextElement
public function changeTransitionForm($id, $type, $mask)
{
$form = new HTML_QuickForm('PL_changeTransition', UI_STANDARD_FORM_METHOD, UI_HANDLER);
@ -600,7 +498,7 @@ class uiPlaylist
$getval = $this->Base->gb->getPLMetadataValue($id, $v['element'], $langid);
if ($getval) {
$mask['playlist'][$k]['default'] = $getval;
$mask['playlist'][$k]['attributes']['onFocus'] = 'MData_confirmChange(this)';
//$mask['playlist'][$k]['attributes']['onFocus'] = 'MData_confirmChange(this)';
};
}
$form = new HTML_QuickForm('editMetaData', UI_STANDARD_FORM_METHOD, UI_HANDLER);

View File

@ -78,12 +78,24 @@ class uiScratchPad
$arr = explode(' ', $spData);
$maxLength = $this->Base->STATIONPREFS[UI_SCRATCHPAD_MAXLENGTH_KEY];
$arr = array_slice($arr, 0, $maxLength);
foreach ($arr as $gunid) {
if (preg_match('/[0-9]{1,20}/', $gunid)) {
$id = BasicStor::IdFromGunid($this->Base->toHex($gunid));
if ($id != FALSE) {
if ($i = $this->Base->getMetaInfo($id)) {
$this->items[] = $i;
foreach ($arr as $item) {
//for audiofiles.
list($type, $savedId) = explode(":", $item);
if($type === 'pl') {
$id = $savedId;
if ($i = $this->Base->getPLMetaInfo($id)) {
$this->items[] = $i;
}
}
else {
$gunid = $savedId;
if (preg_match('/[0-9]{1,20}/', $gunid)) {
$id = BasicStor::IdFromGunid($this->Base->toHex($gunid));
if ($id != FALSE) {
if ($i = $this->Base->getMetaInfo($id)) {
$this->items[] = $i;
}
}
}
}
@ -99,8 +111,12 @@ class uiScratchPad
public function save()
{
foreach ($this->items as $val) {
//$str .= $val['gunid'].':'.$val['added'].' '; // new format
$str .= $this->Base->toInt8($val['gunid']).' '; // Akos old format
if($val['type'] === 'playlist') {
$str .= 'pl:'.$val['id'].' ';
}
else {
$str .= 'ac:'.$this->Base->toInt8($val['gunid']).' ';
}
}
$this->Base->gb->savePref($this->Base->sessid, UI_SCRATCHPAD_KEY, $str);
} // fn save

View File

@ -103,8 +103,6 @@ class Playlist {
return $res;
}
// Recall the object to get all the proper values
//$storedPlaylist = Playlist::Recall($storedPlaylist->id);
return $storedPlaylist->id;
}
@ -533,6 +531,11 @@ class Playlist {
public function delAudioClip($pos)
{
global $CC_CONFIG, $CC_DBC;
if($pos < 0 || $pos >= $this->getNextPos())
return FALSE;
$pos = pg_escape_string($pos);
$CC_DBC->query("BEGIN");
$sql = "DELETE FROM ".$CC_CONFIG['playListContentsTable']. " WHERE playlist_id='{$this->getId()}' AND position='{$pos}'";
@ -565,6 +568,12 @@ class Playlist {
public function moveAudioClip($oldPos, $newPos)
{
global $CC_CONFIG, $CC_DBC;
if($newPos < 0 || $newPos >= $this->getNextPos() || $oldPos < 0 || $oldPos >= $this->getNextPos())
return FALSE;
$oldPos = pg_escape_string($oldPos);
$newPos = pg_escape_string($newPos);
$CC_DBC->query("BEGIN");
$sql = "SELECT * FROM ".$CC_CONFIG['playListContentsTable']. " WHERE playlist_id='{$this->getId()}' AND position='{$oldPos}'";