sintonia/airtime_mvc/public/js/airtime/library/spl.js

1596 lines
54 KiB
JavaScript

//--------------------------------------------------------------------------------------------------------------------------------
// Playlist Functions
//--------------------------------------------------------------------------------------------------------------------------------
var AIRTIME = (function(AIRTIME){
if (AIRTIME.playlist === undefined) {
AIRTIME.playlist = {};
}
var mod = AIRTIME.playlist,
viewport,
$lib,
$pl,
widgetHeight,
$tabCount = 0,
$openTabs = {};
function isTimeValid(time) {
//var regExpr = new RegExp("^\\d{2}[:]\\d{2}[:]\\d{2}([.]\\d{1,6})?$");
var regExpr = new RegExp("^\\d{2}[:]([0-5]){1}([0-9]){1}[:]([0-5]){1}([0-9]){1}([.]\\d{1})?$");
return regExpr.test(time);
}
function isFadeValid(fade) {
var regExpr = new RegExp("^\\d{1}(\\d{1})?([.]\\d{1})?$");
return regExpr.test(fade);
}
function playlistError(json) {
alert(json.error);
}
function stopAudioPreview() {
// stop any preview playing
$('#jquery_jplayer_1').jPlayer('stop');
}
function highlightActive(el) {
$(el).addClass("ui-state-active");
}
function unHighlightActive(el) {
$(el).removeClass("ui-state-active");
}
function showError(el, error) {
$(el).parent().next()
.empty()
.append(error)
.show();
}
function hideError(el) {
$(el).parent().next()
.empty()
.hide();
}
function changeCueIn(event) {
event.stopPropagation();
var span = $(this),
id = span.parent().attr("id").split("_").pop(),
url = baseUrl+"playlist/set-cue",
cueIn = $.trim(span.text()),
li = span.parents("li"),
unqid = li.attr("unqid"),
lastMod = mod.getModified(),
type = $pl.find('.obj_type').val();
if (!isTimeValid(cueIn)){
showError(span, $.i18n._("please put in a time '00:00:00 (.0)'"));
return;
}
$.post(url,
{format: "json", cueIn: cueIn, id: id, modified: lastMod, type: type},
function(json){
if (json.error !== undefined){
playlistError(json);
return;
}
if (json.cue_error !== undefined) {
showError(span, json.cue_error);
return;
}
setPlaylistContent(json);
li = $('.side_playlist.active-tab li[unqid='+unqid+']');
li.find(".cue-edit").toggle();
highlightActive(li);
highlightActive(li.find('.spl_cue'));
});
}
function changeCueOut(event) {
event.stopPropagation();
var span = $(this),
id = span.parent().attr("id").split("_").pop(),
url = baseUrl+"playlist/set-cue",
cueOut = $.trim(span.text()),
li = span.parents("li"),
unqid = li.attr("unqid"),
lastMod = mod.getModified(),
type = $pl.find('.obj_type').val();
if (!isTimeValid(cueOut)){
showError(span, $.i18n._("please put in a time '00:00:00 (.0)'"));
return;
}
$.post(url,
{format: "json", cueOut: cueOut, id: id, modified: lastMod, type: type},
function(json){
if (json.error !== undefined){
playlistError(json);
return;
}
if (json.cue_error !== undefined) {
showError(span, json.cue_error);
return;
}
setPlaylistContent(json);
li = $('.side_playlist.active-tab li[unqid='+unqid+']');
li.find(".cue-edit").toggle();
highlightActive(li);
highlightActive(li.find('.spl_cue'));
});
}
/* used from waveform pop-up */
function changeCues($el, id, cueIn, cueOut) {
var url = baseUrl+"playlist/set-cue",
lastMod = mod.getModified(),
type = $pl.find('.obj_type').val(),
li,
span;
if (!isTimeValid(cueIn)){
$el.find('.cue-in-error').val($.i18n._("please put in a time '00:00:00 (.0)'")).show();
return;
}
else {
$el.find('.cue-in-error').hide();
}
if (!isTimeValid(cueOut)){
$el.find('.cue-out-error').val($.i18n._("please put in a time '00:00:00 (.0)'")).show();
return;
}
else {
$el.find('.cue-out-error').hide();
}
$.post(url,
{format: "json", cueIn: cueIn, cueOut: cueOut, id: id, modified: lastMod, type: type},
function(json){
$el.dialog('destroy');
$el.remove();
if (json.error !== undefined){
playlistError(json);
return;
}
if (json.cue_error !== undefined) {
li = $('.side_playlist.active-tab li[unqid='+id+']');
if (json.code === 0) {
span = $('#spl_cue_in_'+id).find('span');
showError(span, json.cue_error);
span = $('#spl_cue_out_'+id).find('span');
showError(span, json.cue_error);
}
else if (json.code === 1) {
span = $('#spl_cue_in_'+id).find('span');
showError(span, json.cue_error);
}
else if (json.code === 2) {
span = $('#spl_cue_out_'+id).find('span');
showError(span, json.cue_error);
}
return;
}
setPlaylistContent(json);
li = $('.side_playlist.active-tab li[unqid='+id+']');
li.find(".cue-edit").toggle();
highlightActive(li);
highlightActive(li.find('.spl_cue'));
});
}
/* used from waveform pop-up */
function changeCrossfade($el, id1, id2, fadeIn, fadeOut, offset, id) {
var url = baseUrl+"playlist/set-crossfade",
lastMod = mod.getModified(),
type = $pl.find('.obj_type').val();
$.post(url,
{format: "json", fadeIn: fadeIn, fadeOut: fadeOut, id1: id1, id2: id2, offset: offset, modified: lastMod, type: type},
function(json){
$el.dialog('destroy');
$el.remove();
if (json.error !== undefined){
playlistError(json);
return;
}
setPlaylistContent(json);
$li = $pl.find('li[unqid='+id+']');
$li.find('.crossfade').toggle();
highlightActive($li.find('.spl_fade_control'));
});
}
function changeFadeIn(event) {
event.preventDefault();
var span = $(this),
id = span.parent().attr("id").split("_").pop(),
url = baseUrl+"playlist/set-fade",
fadeIn = $.trim(span.text()),
li = span.parents("li"),
unqid = li.attr("unqid"),
lastMod = mod.getModified(),
type = $pl.find('.obj_type').val();
if (!isFadeValid(fadeIn)){
showError(span, $.i18n._("please put in a time in seconds '00 (.0)'"));
return;
}
$.post(url,
{format: "json", fadeIn: fadeIn, id: id, modified: lastMod, type: type},
function(json){
if (json.error !== undefined){
playlistError(json);
return;
}
if (json.fade_error !== undefined) {
showError(span, json.fade_error);
return;
}
setPlaylistContent(json);
li = $pl.find('li[unqid='+unqid+']');
li.find('.crossfade').toggle();
highlightActive(li.find('.spl_fade_control'));
});
}
function changeFadeOut(event) {
event.stopPropagation();
var span = $(this),
id = span.parent().attr("id").split("_").pop(),
url = baseUrl+"playlist/set-fade",
fadeOut = $.trim(span.text()),
li = span.parents("li"),
unqid = li.attr("unqid"),
lastMod = mod.getModified(),
type = $pl.find('.obj_type').val();
if (!isFadeValid(fadeOut)){
showError(span, $.i18n._("please put in a time in seconds '00 (.0)'"));
return;
}
$.post(url,
{format: "json", fadeOut: fadeOut, id: id, modified: lastMod, type: type},
function(json){
if (json.error !== undefined){
playlistError(json);
return;
}
if (json.fade_error !== undefined) {
showError(span, json.fade_error);
return;
}
setPlaylistContent(json);
li = $pl.find('li[unqid='+unqid+']');
li.find('.crossfade').toggle();
highlightActive(li.find('.spl_fade_control'));
});
}
function submitOnEnter(event) {
//enter was pressed
if(event.keyCode === 13) {
event.preventDefault();
$(this).blur();
}
}
function openFadeEditor(event) {
var li;
event.stopPropagation();
li = $(this).parents("li");
li.find(".crossfade").toggle();
if ($(this).hasClass("ui-state-active")) {
unHighlightActive(this);
}
else {
highlightActive(this);
}
}
function openCueEditor(event) {
var li, icon;
event.stopPropagation();
icon = $(this);
li = $(this).parents("li");
li.find(".cue-edit").toggle();
if (li.hasClass("ui-state-active")) {
unHighlightActive(li);
unHighlightActive(icon);
}
else {
highlightActive(li);
highlightActive(icon);
}
}
function updateActiveTabName(newTabName) {
/*
var nameElement = $(this);
//remove any newlines if user somehow snuck them in (easy to do if dragging/dropping text)
nameElement.text(nameElement.text().replace("\n", ""));
var name = $pl.find(".playlist_name_display").val();
*/
$(".nav.nav-tabs .active a > span.tab-name").text(newTabName);
}
function redrawLib() {
var dt = $lib.find("#library_display").dataTable();
dt.fnStandingRedraw();
AIRTIME.library.redrawChosen();
}
function setPlaylistContent(json) {
var $html = $(json.html);
$('#spl_name > a')
.empty()
.append(json.name);
$pl.find('.obj_length')
.empty()
.append(json.length);
$('#fieldset-metadate_change textarea')
.empty()
.val(json.description);
$pl.find('.spl_sortable').off('focusout keydown');
$pl.find('.spl_sortable')
.empty()
.append($html);
setCueEvents();
setFadeEvents();
mod.setModified(json.modified);
updateActiveTabName(json.name);
AIRTIME.playlist.validatePlaylistElements();
redrawLib();
}
function setFadeIcon(){
var contents = $pl.find(".spl_sortable");
var show = contents.is(":visible");
var empty = $pl.find(".spl_empty");
if (!show || empty.length > 0) {
$pl.find("#spl_crossfade").hide();
} else {
//get list of playlist contents
var list = contents.children();
//if first and last items are blocks, hide the fade icon
var first = list.first();
var last = list.last();
if (first.find(':first-child').children().attr('blockid') !== undefined &&
last.find(':first-child').children().attr('blockid') !== undefined) {
$pl.find("#spl_crossfade").hide();
} else {
$pl.find("#spl_crossfade").show();
}
}
$('.zend_form + .spl-no-margin > div:has(*:visible):last').css('margin-left', 0);
}
function getId() {
return parseInt($pl.find(".obj_id").val(), 10);
}
mod.getModified = function() {
return parseInt($pl.find(".obj_lastMod").val(), 10);
}
mod.setModified = function(modified) {
$pl.find(".obj_lastMod").val(modified);
}
function setTitleLabel(title) {
$pl.find(".title_obj_name").text(title);
}
/*
* Should all be moved to builder.js eventually
*/
function buildNewTab(json) {
AIRTIME.library.selectNone();
var tabId = $openTabs[json.type + json.id];
if (tabId !== undefined) {
AIRTIME.showbuilder.switchTab($("#pl-tab-content-" + tabId), $("#pl-tab-" + tabId));
return undefined;
}
$tabCount++;
var wrapper = "<div data-tab-type='" + json.type + "' data-tab-id='" + $tabCount + "' id='pl-tab-content-" + $tabCount + "' class='side_playlist pl-content'><div class='editor_pane_wrapper'></div></div>",
t = $("#show_builder").append(wrapper).find("#pl-tab-content-" + $tabCount),
pane = $(".editor_pane_wrapper:last"),
name = json.type == "md" ? // file
pane.append(json.html).find("#track_title").val() + $.i18n._(" - Metadata Editor")
: pane.append(json.html).find(".playlist_name_display").val(),
tab =
"<li data-tab-id='" + $tabCount + "' data-tab-type='" + json.type + "' id='pl-tab-" + $tabCount + "' role='presentation' class='active'>" +
"<a href='javascript:void(0)'><span class='tab-name'></span>" +
"<span href='#' class='lib_pl_close icon-remove'></span>" +
"</a>" +
"</li>",
tabs = $(".nav.nav-tabs");
if (json.id) {
$openTabs[json.type + json.id] = $tabCount;
}
$(".nav.nav-tabs li").removeClass("active");
tabs.append(tab);
tabs.find("#pl-tab-" + $tabCount + " span.tab-name").text(name);
var newTab = $("#pl-tab-" + $tabCount);
AIRTIME.showbuilder.switchTab(t, newTab);
return {wrapper: pane, tab: newTab, pane: t};
}
function openFileMdEditor(json) {
var newTab = buildNewTab(json);
if (newTab === undefined) {
return;
}
newTab.tab.on("click", function() {
if (!$(this).hasClass('active')) {
AIRTIME.showbuilder.switchTab(newTab.pane, newTab.tab);
}
});
newTab.wrapper.find(".md-cancel").on("click", function() {
closeTab();
});
initialEvents();
}
function openPlaylist(json) {
var newTab = buildNewTab(json);
if (newTab === undefined) {
return;
}
newTab.tab.on("click", function() {
if (!$(this).hasClass('active')) {
AIRTIME.showbuilder.switchTab(newTab.pane, newTab.tab);
$.post(baseUrl+'playlist/edit',
{format: "json", id: newTab.pane.find(".obj_id").val(), type: newTab.pane.find(".obj_type").val()});
}
});
AIRTIME.playlist.init();
// functions in smart_blockbuilder.js
setupUI();
appendAddButton();
appendModAddButton();
removeButtonCheck();
}
function openPlaylistPanel() {
viewport = AIRTIME.utilities.findViewportDimensions();
var screenWidth = Math.floor(viewport.width - 40);
widgetHeight = viewport.height - 185;
$pl.show().width(Math.floor(screenWidth * 0.44));
$pl.height(widgetHeight);
$("#pl_edit").hide();
}
function closeTab(id) {
var curr = $(".active-tab"),
pane = id ? $(".pl-content[data-tab-id='" + id + "']") : curr,
tab = id ? $(".nav.nav-tabs [data-tab-id='" + id + "']") : $(".nav.nav-tabs .active"),
toPane = pane.next().length > 0 ? pane.next() : pane.prev(),
toTab = tab.next().length > 0 ? tab.next() : tab.prev(),
objId = pane.find(".obj_id").val(),
pl = id ? pane : $pl;
delete $openTabs[tab.attr("data-tab-type") + objId]; // Remove the closed tab from our open tabs array
// Remove the relevant DOM elements (the tab and the tab content)
tab.remove();
pl.remove();
if (pane.get(0) == curr.get(0)) { // Closing the current tab, otherwise we don't need to switch tabs
AIRTIME.showbuilder.switchTab(toPane, toTab);
}
}
mod.closeTab = function(id) {
closeTab(id);
};
//Purpose of this function is to iterate over all playlist elements
//and verify whether they can be previewed by the browser or not. If not
//then the playlist element is greyed out
mod.validatePlaylistElements = function(){
$.each($("div .big_play"), function(index, value){
if ($(value).attr('blockId') === undefined) {
var mime = $(value).attr("data-mime-type");
//If mime is undefined it is likely because the file was
//deleted from the library. This case is handled in mod.onReady()
if (mime !== undefined) {
if (isAudioSupported(mime)) {
$(value).bind("click", openAudioPreview);
} else {
$(value).attr("class", "big_play_disabled dark_class");
$(value).qtip({
content: $.i18n._("Your browser does not support playing this file type: ")+ mime,
show: 'mouseover',
hide: {
delay: 500,
fixed: true
},
style: {
border: {
width: 0,
radius: 4
},
classes: "ui-tooltip-dark ui-tooltip-rounded"
},
position: {
my: "left bottom",
at: "right center"
}
})
}
}
} else {
if ($(value).attr('blocktype') === 'dynamic') {
$(value).attr("class", "big_play_disabled dark_class");
$(value).qtip({
content: $.i18n._('Dynamic block is not previewable'),
show: 'mouseover',
hide: {
delay: 500,
fixed: true
},
style: {
border: {
width: 0,
radius: 4
},
classes: "ui-tooltip-dark ui-tooltip-rounded"
},
position: {
my: "left bottom",
at: "right center"
}
})
} else {
$(value).bind("click", openAudioPreview);
}
}
});
};
//sets events dynamically for playlist entries (each row in the playlist)
function setPlaylistEntryEvents() {
$pl.delegate(".spl_sortable .ui-icon-closethick",
{"click": function(ev){
var id;
id = parseInt($(this).attr("id").split("_").pop(), 10);
AIRTIME.playlist.fnDeleteItems([id]);
}});
$pl.delegate(".spl_fade_control",
{"click": openFadeEditor});
$pl.delegate(".spl_cue",
{"click": openCueEditor});
$pl.delegate(".spl_block_expand",
{"click": function(ev){
var id = parseInt($(this).attr("id").split("_").pop(), 10);
var blockId = parseInt($(this).attr("blockId"), 10);
if ($(this).hasClass('close')) {
var sUrl = baseUrl+"playlist/get-block-info";
mod.disableUI();
$.post(sUrl, {format:"json", id:blockId}, function(data){
$html = "";
var isStatic = data.isStatic;
delete data.type;
if (isStatic) {
$.each(data, function(index, ele){
if (ele.track_title !== undefined) {
if (ele.creator === null) {
ele.creator = "";
}
if (ele.track_title === null) {
ele.track_title = "";
}
$html += "<li>" +
"<span class='block-item-title'>"+ele.track_title+" - </span>" +
"<span class='block-item-author'>"+ele.creator+"</span>" +
"<span class='block-item-time'>"+ele.length+"</span>" +
"</li>";
}
})
} else {
for (var key in data.crit){
$.each(data.crit[key], function(index, ele){
var extra = (ele['extra']==null)?"":"- "+ele['extra'];
$html += "<li>" +
"<span class='block-item-title'>"+ele['display_name']+"</span>" +
"<span class='block-item-criteria'>"+ele['display_modifier']+"</span>" +
"<span class='block-item-criteria'>"+ele['value']+"</span>" +
"<span class='block-item-criteria'>"+extra+"</span>" +
"</li>";
});
}
$html += "<li><br /><span class='block-item-title'>"+$.i18n._("Limit to: ")+data.limit.value+" "+data.limit.display_modifier+"</span></li>";
}
$pl.find("#block_"+id+"_info").html($html).show();
mod.enableUI();
});
$(this).removeClass('close');
} else {
$pl.find("#block_"+id+"_info").html("").hide();
$(this).addClass('close');
}
}});
}
//sets events dynamically for the cue editor.
function setCueEvents() {
var temp = $('.active-tab .spl_sortable');
temp.on("focusout", ".spl_cue_in span", changeCueIn);
temp.on("keydown", ".spl_cue_in span", submitOnEnter);
temp.on("focusout", ".spl_cue_out span", changeCueOut);
temp.on("keydown", ".spl_cue_out span", submitOnEnter);
//remove show waveform buttons since web audio api is not supported.
if (!(window.AudioContext || window.webkitAudioContext)) {
temp.find('.pl-waveform-cues-btn')
.parent()
.html($.i18n._("Waveform features are available in a browser supporting the Web Audio API"));
}
}
//sets events dynamically for the fade editor.
function setFadeEvents() {
var temp = $('.active-tab .spl_sortable');
temp.on("focusout", ".spl_fade_in span", changeFadeIn);
temp.on("keydown", ".spl_fade_in span", submitOnEnter);
temp.on("focusout", ".spl_fade_out span", changeFadeOut);
temp.on("keydown", ".spl_fade_out span", submitOnEnter);
//remove show waveform buttons since web audio api is not supported.
if (!(window.AudioContext || window.webkitAudioContext)) {
temp.find('.pl-waveform-fades-btn')
.parent()
.html($.i18n._("Waveform features are available in a browser supporting the Web Audio API"));
}
}
function initialEvents() {
var cachedDescription;
//main playlist fades events
$pl.on("click", "#spl_crossfade", function() {
var lastMod = mod.getModified(),
type = $pl.find('.obj_type').val();
if ($(this).hasClass("ui-state-active")) {
$(this).removeClass("ui-state-active");
$pl.find("#crossfade_main").hide();
}
else {
$(this).addClass("ui-state-active");
var url = baseUrl+'playlist/get-playlist-fades';
$.post(url,
{format: "json", modified: lastMod, type: type},
function(json){
if (json.error !== undefined){
playlistError(json);
}
else {
var fadeIn = $pl.find("span.spl_main_fade_in");
var fadeOut = $pl.find("span.spl_main_fade_out");
if (json.fadeIn == null) {
fadeIn.parent().prev().hide();
fadeIn.hide();
} else {
fadeIn.parent().prev().show();
fadeIn.show();
fadeIn.empty().append(json.fadeIn);
}
if (json.fadeOut == null) {
fadeOut.parent().prev().hide();
fadeOut.hide();
} else {
fadeOut.parent().prev().show();
fadeOut.show();
fadeOut.empty().append(json.fadeOut);
}
if (json.fadeIn != null || json.fadeOut != null) {
$pl.find("#crossfade_main").show();
}
}
});
}
});
$pl.on("blur", "span.spl_main_fade_in", function(event){
event.stopPropagation();
var url = baseUrl+"playlist/set-playlist-fades",
span = $(this),
fadeIn = $.trim(span.text()),
lastMod = mod.getModified(),
type = $pl.find('.obj_type').val();
if (!isFadeValid(fadeIn)){
showError(span, $.i18n._("please put in a time in seconds '00 (.0)'"));
return;
}
$.post(url,
{format: "json", fadeIn: fadeIn, modified: lastMod, type: type},
function(json){
hideError(span);
if (json.modified !== undefined) {
mod.setModified(json.modified);
}
});
});
$pl.on("blur", "span.spl_main_fade_out", function(event){
event.stopPropagation();
var url = baseUrl+"playlist/set-playlist-fades",
span = $(this),
fadeOut = $.trim(span.text()),
lastMod = mod.getModified(),
type = $pl.find('.obj_type').val();
if (!isFadeValid(fadeOut)){
showError(span, $.i18n._("please put in a time in seconds '00 (.0)'"));
return;
}
$.post(url,
{format: "json", fadeOut: fadeOut, modified: lastMod, type: type},
function(json){
hideError(span);
if (json.modified !== undefined) {
mod.setModified(json.modified);
}
});
});
$pl.on("keydown", "span.spl_main_fade_in, span.spl_main_fade_out", submitOnEnter);
$pl.on("click", "#crossfade_main > .ui-icon-closethick", function(){
$pl.find("#spl_crossfade").removeClass("ui-state-active");
$pl.find("#crossfade_main").hide();
});
//end main playlist fades.
//edit playlist name event
$pl.on("keydown", ".playlist_name_display", submitOnEnter);
//$pl.on("blur", ".playlist_name_display", editName);
//edit playlist description events
$pl.on("click", "legend", function(){
var $fs = $(this).parents("fieldset");
if ($fs.hasClass("closed")) {
cachedDescription = $fs.find("textarea").val();
$fs.removeClass("closed");
}
else {
$fs.addClass("closed");
}
});
$pl.on("click", 'button[id="playlist_shuffle_button"]', function(){
obj_id = $pl.find('.obj_id').val();
url = baseUrl+"playlist/shuffle";
enableLoadingIcon();
$.post(url, {format: "json", obj_id: obj_id}, function(json){
if (json.error !== undefined) {
alert(json.error);
} else {
if (json.result == "0") {
$pl.find('.success').text($.i18n._('Playlist shuffled'));
$pl.find('.success').show();
mod.playlistResponse(json);
}
}
disableLoadingIcon();
setTimeout(removeSuccessMsg, 5000);
});
});
$pl.find("#webstream_save").on("click", function(){
//get all fields and POST to server
//description
//stream url
//default_length
//playlist name
var id = $pl.find(".obj_id").attr("value");
var description = $pl.find("#description").val();
var streamurl = $pl.find("#streamurl-element input").val();
var length = $pl.find("#streamlength-element input").val();
var name = $pl.find(".playlist_name_display").val();
//hide any previous errors (if any)
$(".side_playlist.active-tab .errors").empty().hide();
var url = baseUrl+'webstream/save';
$.post(url,
{format: "json", id:id, description: description, url:streamurl, length: length, name: name},
function(json){
if (json.analysis){
for (var s in json.analysis){
var field = json.analysis[s];
if (!field[0]) {
var elemId = "#"+s+"-error";
var $div = $(".side_playlist.active-tab " + elemId).text(field[1]).show();
}
}
} else {
var $status = $(".side_playlist.active-tab .status");
$status.html(json.statusMessage);
$status.show();
setTimeout(function(){$status.fadeOut("slow", function(){$status.empty()})}, 5000);
$pl.find(".title_obj_name").val(name);
updateActiveTabName(name);
var $ws_id = $(".active-tab .obj_id");
$ws_id.attr("value", json.streamId);
var $ws_id = $("#ws_delete");
$ws_id.show();
editName();
var length = $(".side_playlist.active-tab .ws_length");
length.text(json.length);
//redraw the library to show the new webstream
redrawLib();
}
});
});
$pl.find("#webstream_cancel, #cancel_button").on("click", function() {
var tabId = $pl.attr("data-tab-id");
$("li[data-tab-id=" + tabId + "] .lib_pl_close").click();
});
$lib.on("click", "#pl_edit", function() {
openPlaylistPanel();
$.ajax({
url : baseUrl+"usersettings/set-library-screen-settings",
type : "POST",
data : {
settings : {
playlist : true
},
format : "json"
},
dataType : "json"
});
});
// Unbind so each tab is only handled by its own close button
$(".lib_pl_close").unbind().click(function(e) {
e.preventDefault();
e.stopPropagation();
$(this).unbind("click"); // Prevent repeated clicks in quick succession from closing multiple tabs
var tabId = $(this).closest("li").attr("data-tab-id");
//AIRTIME.showbuilder.switchTab($("#pl-tab-content-" + tabId), $("#pl-tab-" + tabId));
//$pl.hide();
// We need to update the text on the add button
AIRTIME.library.checkAddButton();
// We also need to run the draw callback to update how dragged items are drawn
AIRTIME.library.fnDrawCallback();
var playlistNameElem = $pl.find('.playlist_name_display');
var name = "";
if (playlistNameElem.val() !== undefined) {
name = playlistNameElem.val().trim();
}
if ((name == $.i18n._("Untitled Playlist")
|| name == $.i18n._("Untitled Smart Block"))
&& $pl.find(".spl_sortable .spl_empty").length == 1) {
mod.fnDelete(undefined, tabId);
} else {
closeTab(tabId);
}
$.ajax( {
url : baseUrl+"usersettings/set-library-screen-settings",
type : "POST",
data : {
settings : {
playlist : false
},
format : "json"
},
dataType : "json"
});
});
$pl.on("click", "#save_button", function(event) {
/* Smart blocks: get name, description, and criteria
* Playlists: get name, description
*/
var criteria = $pl.find('form').serializeArray(),
block_name = $pl.find('.playlist_name_display').val(),
block_desc = $pl.find('textarea[name="description"]').val(),
save_action = baseUrl+'playlist/save',
obj_id = $pl.find(".obj_id").val(),
obj_type = $pl.find('.obj_type').val(),
lastMod = mod.getModified(),
dt = $('table[id="library_display"]').dataTable();
enableLoadingIcon();
$.post(save_action,
{format: "json", data: criteria, name: block_name, description: block_desc, obj_id: obj_id, type: obj_type, modified: lastMod},
function(json){
if (json.error !== undefined) {
alert(json.error);
} else {
setTitleLabel(json.name);
mod.setModified(json.modified);
if (obj_type == "block") {
callback(json, "save");
} else {
$pl.find('.success').text($.i18n._('Playlist saved'));
$pl.find('.success').show();
setTimeout(removeSuccessMsg, 5000);
dt.fnStandingRedraw();
}
}
setFadeIcon();
disableLoadingIcon();
}
);
});
$pl.find("#pl-bl-clear-content").unbind().on("click", function(event) {
var sUrl = baseUrl+"playlist/empty-content",
oData = {};
playlistRequest(sUrl, oData);
});
$pl.find(".toggle-editor-form").unbind().on("click", function(event) {
$pl.find(".inner_editor_wrapper").slideToggle(200);
var buttonIcon = $(this).find('span.icon-white');
buttonIcon.toggleClass('icon-chevron-up');
buttonIcon.toggleClass('icon-chevron-down');
});
}
function setUpPlaylist() {
var sortableConf;
sortableConf = (function(){
var aReceiveItems,
html,
fnReceive,
fnUpdate;
fnReceive = function(event, ui) {
var aItems = [],
aSelected,
i,
length;
AIRTIME.library.addToChosen(ui.item);
//filter out anything that isn't an audiofile.
aSelected = AIRTIME.library.getSelectedData();
for (i = 0, length = aSelected.length; i < length; i++) {
aItems.push(new Array(aSelected[i].id, aSelected[i].ftype));
}
aReceiveItems = aItems;
html = ui.helper.html();
AIRTIME.library.removeFromChosen(ui.item);
};
fnUpdate = function(event, ui) {
var prev,
aItems = [],
iAfter,
sAddType;
prev = ui.item.prev();
if (prev.hasClass("spl_empty") || prev.length === 0) {
iAfter = undefined;
sAddType = 'before';
}
else {
iAfter = parseInt(prev.attr("id").split("_").pop(), 10);
sAddType = 'after';
}
//item was dragged in from library datatable
if (aReceiveItems !== undefined) {
$pl.find("tr.ui-draggable")
.after(html)
.empty();
aItems = aReceiveItems;
aReceiveItems = undefined;
AIRTIME.playlist.fnAddItems(aItems, iAfter, sAddType);
}
//item was reordered.
else {
aItems.push(parseInt(ui.item.attr("id").split("_").pop(), 10));
AIRTIME.playlist.fnMoveItems(aItems, iAfter);
}
};
return {
items: 'li',
//hack taken from
//http://stackoverflow.com/questions/2150002/jquery-ui-sortable-how-can-i-change-the-appearance-of-the-placeholder-object
placeholder: {
element: function(currentItem) {
return $('<li class="placeholder ui-state-highlight"></li>')[0];
},
update: function(container, p) {
return;
}
},
forcePlaceholderSize: true,
//handle: 'div.list-item-container',
start: function(event, ui) {
ui.placeholder.height(56);
ui.placeholder.css('min-height', 56);
},
axis: "y",
containment: "document",
receive: fnReceive,
update: fnUpdate
};
}());
$pl.find(".spl_sortable").sortable(sortableConf);
AIRTIME.playlist.validatePlaylistElements();
}
mod.fnNew = function() {
var url = baseUrl+'playlist/new';
stopAudioPreview();
$.post(url,
{format: "json", type: 'playlist'},
function(json){
openPlaylist(json);
redrawLib();
});
};
mod.fnWsNew = function() {
var url = baseUrl+'webstream/new';
stopAudioPreview();
$.post(url,
{format: "json"},
function(json){
openPlaylist(json);
redrawLib();
});
};
mod.fnNewBlock = function() {
var url = baseUrl+'playlist/new';
stopAudioPreview();
$.post(url,
{format: "json", type: 'block'},
function(json){
openPlaylist(json);
redrawLib();
});
};
mod.fileMdEdit = function(json) {
openFileMdEditor(json);
};
mod.fnEdit = function(id, type, url) {
//openPlaylistPanel();
stopAudioPreview();
$.post(url,
{format: "json", id: id, type: type},
function(json){
openPlaylist(json);
redrawLib();
});
};
mod.fnDelete = function(plid, tabId) {
var url, id, lastMod, type, pl = (tabId === undefined) ? $pl : $('#pl-tab-content-' + tabId);
stopAudioPreview();
id = (plid === undefined) ? getId() : plid;
lastMod = mod.getModified();
type = pl.find('.obj_type').val();
url = baseUrl+'playlist/delete';
$.post(url,
{format: "json", ids: id, modified: lastMod, type: type},
function(json) {
closeTab(tabId);
redrawLib();
});
};
mod.fnWsDelete = function(wsid) {
var url, id, lastMod;
stopAudioPreview();
id = (wsid === undefined) ? getId() : wsid;
lastMod = mod.getModified();
type = $pl.find('.obj_type').val();
url = baseUrl+'webstream/delete';
$.post(url,
{format: "json", ids: id, modified: lastMod, type: type},
function(json){
openPlaylist(json);
redrawLib();
});
};
mod.disableUI = function() {
$lib.block({
message: "",
theme: true,
applyPlatformOpacityRules: false
});
$pl.block({
message: "",
theme: true,
applyPlatformOpacityRules: false
});
};
mod.fnOpenPlaylist = function(json) {
openPlaylist(json);
};
mod.enableUI = function() {
$lib.unblock();
$pl.unblock();
setupUI();
};
mod.playlistResponse = function(json){
if (json.error !== undefined) {
playlistError(json);
}
else {
setPlaylistContent(json);
setFadeIcon();
}
mod.enableUI();
}
function playlistRequest(sUrl, oData) {
var lastMod,
obj_type = $pl.find('.obj_type').val();
mod.disableUI();
lastMod = mod.getModified();
oData["modified"] = lastMod;
oData["obj_type"] = obj_type;
oData["format"] = "json";
$.post(
sUrl,
oData,
mod.playlistResponse
);
}
mod.fnAddItems = function(aItems, iAfter, sAddType) {
AIRTIME.library.selectNone();
var sUrl = baseUrl+"playlist/add-items";
oData = {"aItems": aItems, "afterItem": iAfter, "type": sAddType};
playlistRequest(sUrl, oData);
};
mod.fnMoveItems = function(aIds, iAfter) {
var sUrl = baseUrl+"playlist/move-items",
oData = {"ids": aIds, "afterItem": iAfter};
playlistRequest(sUrl, oData);
};
mod.fnDeleteItems = function(aItems) {
var sUrl = baseUrl+"playlist/delete-items",
oData = {"ids": aItems};
playlistRequest(sUrl, oData);
};
mod.showFadesWaveform = function(e) {
var $el = $(e.target),
$parent = $el.parents("dl"),
$li = $el.parents("li"),
$fadeOut = $parent.find(".spl_fade_out"),
$fadeIn = $parent.find(".spl_fade_in"),
$html = $($("#tmpl-pl-fades").html()),
tracks = [],
dim = AIRTIME.utilities.findViewportDimensions(),
playlistEditor,
id1, id2,
id = $li.attr("unqid");
function removeDialog() {
playlistEditor.stop();
$html.dialog("destroy");
$html.remove();
}
if ($fadeOut.length > 0) {
tracks.push({
src: $fadeOut.data("fadeout"),
cuein: $fadeOut.data("cuein"),
cueout: $fadeOut.data("cueout"),
fades: [{
shape: $fadeOut.data("type"),
type: "FadeOut",
end: $fadeOut.data("cueout") - $fadeOut.data("cuein"),
start: $fadeOut.data("cueout") - $fadeOut.data("cuein") - $fadeOut.data("length")
}],
states: {
'fadein': false,
'shift': false
}
});
id1 = $fadeOut.data("item");
}
if ($fadeIn.length > 0) {
tracks.push({
src: $fadeIn.data("fadein"),
start: $fadeIn.data("offset"),
cuein: $fadeIn.data("cuein"),
cueout: $fadeIn.data("cueout"),
fades: [{
shape: $fadeIn.data("type"),
type: "FadeIn",
end: $fadeIn.data("length"),
start: 0
}],
states: {
'fadeout': false,
'shift': false
}
});
id2 = $fadeIn.data("item");
}
//set the first track to not be moveable (might only be one track depending on what follows)
//tracks[0].states["shift"] = false;
$html.dialog({
modal: true,
title: $.i18n._("Fade Editor"),
show: 'clip',
hide: 'clip',
width: dim.width - 100,
height: 350,
buttons: [
{text: $.i18n._("Cancel"), class: "btn btn-small", click: removeDialog},
{text: $.i18n._("Save"), class: "btn btn-small btn-inverse", click: function() {
var json = playlistEditor.getJson(),
offset,
fadeIn, fadeOut,
fade;
playlistEditor.stop();
if (json.length === 0)
{
id1 = undefined;
id2 = undefined;
}
else if (json.length === 1) {
fade = json[0]["fades"][0];
if (fade["type"] === "FadeOut") {
fadeOut = fade["end"] - fade["start"];
id2 = undefined; //incase of track decode error.
}
else {
fadeIn = fade["end"] - fade["start"];
id1 = undefined; //incase of track decode error.
}
}
else {
offset = json[0]["end"] - json[1]["start"];
fade = json[0]["fades"][0];
fadeOut = fade["end"] - fade["start"];
fade = json[1]["fades"][0];
fadeIn = fade["end"] - fade["start"];
}
fadeIn = (fadeIn === undefined) ? undefined : fadeIn.toFixed(1);
fadeOut = (fadeOut === undefined) ? undefined : fadeOut.toFixed(1);
changeCrossfade($html, id1, id2, fadeIn, fadeOut, offset, id);
}}
],
open: function (event, ui) {
var config = new Config({
resolution: 15000,
state: "cursor",
mono: true,
timescale: true,
waveHeight: 80,
container: $html[0],
UITheme: "jQueryUI",
timeFormat: 'hh:mm:ss.u'
});
playlistEditor = new PlaylistEditor();
playlistEditor.setConfig(config);
playlistEditor.init(tracks);
},
close: removeDialog,
resizeStop: function(event, ui) {
playlistEditor.resize();
}
});
};
mod.showCuesWaveform = function(e) {
var $el = $(e.target),
$li = $el.parents("li"),
id = $li.attr("unqid"),
$parent = $el.parent(),
uri = $parent.data("uri"),
$html = $($("#tmpl-pl-cues").html()),
cueIn = $li.find('.spl_cue_in').data("cueIn"),
cueOut = $li.find('.spl_cue_out').data("cueOut"),
cueInSec = $li.find('.spl_cue_in').data("cueSec"),
cueOutSec = $li.find('.spl_cue_out').data("cueSec"),
tracks = [{
src: uri,
selected: {
start: cueInSec,
end: cueOutSec
}
}],
dim = AIRTIME.utilities.findViewportDimensions(),
playlistEditor;
function removeDialog() {
playlistEditor.stop();
$html.dialog("destroy");
$html.remove();
}
$html.find('.editor-cue-in').html(cueIn);
$html.find('.editor-cue-out').html(cueOut);
$html.on("click", ".set-cue-in", function(e) {
var cueIn = $html.find('.audio_start').val();
$html.find('.editor-cue-in').html(cueIn);
});
$html.on("click", ".set-cue-out", function(e) {
var cueOut = $html.find('.audio_end').val();
$html.find('.editor-cue-out').html(cueOut);
});
$html.dialog({
modal: true,
title: $.i18n._("Cue Editor"),
show: 'clip',
hide: 'clip',
width: dim.width - 100,
height: 325,
buttons: [
{text: $.i18n._("Cancel"), class: "btn btn-small", click: removeDialog},
{text: $.i18n._("Save"), class: "btn btn-small btn-inverse", click: function() {
var cueIn = $html.find('.editor-cue-in').html(),
cueOut = $html.find('.editor-cue-out').html();
playlistEditor.stop();
changeCues($html, id, cueIn, cueOut);
}}
],
open: function (event, ui) {
var config = new Config({
resolution: 15000,
mono: true,
timescale: true,
waveHeight: 80,
container: $html[0],
UITheme: "jQueryUI",
timeFormat: 'hh:mm:ss.u'
});
playlistEditor = new PlaylistEditor();
playlistEditor.setConfig(config);
playlistEditor.init(tracks);
},
close: removeDialog,
resizeStop: function(event, ui) {
playlistEditor.resize();
}
});
};
mod.setAsActive = function() {
$pl = $(".active-tab");
};
mod.init = function() {
AIRTIME.playlist.setAsActive();
//$pl.delegate("#spl_delete", {"click": function(ev){
// AIRTIME.playlist.fnDelete();
//}});
//
//$pl.delegate("#ws_delete", {"click": function(ev){
// AIRTIME.playlist.fnWsDelete();
//}});
$pl.delegate(".pl-waveform-cues-btn", {"click": function(ev){
AIRTIME.playlist.showCuesWaveform(ev);
}});
$pl.delegate(".pl-waveform-fades-btn", {"click": function(ev){
AIRTIME.playlist.showFadesWaveform(ev);
}});
setPlaylistEntryEvents();
setCueEvents();
setFadeEvents();
setFadeIcon();
initialEvents();
setUpPlaylist();
$pl.find(".ui-icon-alert").qtip({
content: {
text: sprintf($.i18n._("%s is unsure about the status of this file. This can happen when the file is on a remote drive that is unaccessible or the file is in a directory that isn't 'watched' anymore."), PRODUCT_NAME)
},
position: {
adjust: {
resize: true,
method: "flip flip"
},
at: "right center",
my: "left top",
viewport: $(window)
},
style: {
classes: "ui-tooltip-dark"
},
show: 'mouseover',
hide: 'mouseout'
});
};
mod.onReady = function() {
$lib = $("#library_content");
$('#new-playlist').live('click', function(){AIRTIME.playlist.fnNew();});
$('#new-smart-block').live('click', function(){AIRTIME.playlist.fnNewBlock();});
$('#new-webstream').live('click', function(){AIRTIME.playlist.fnWsNew();});
AIRTIME.playlist.init();
};
mod.onResize = function() {
var h = $(".panel-header .nav").height();
$(".pl-content").css("margin-top", h + 5); // 8px extra for padding
$("#show_builder_table_wrapper").css("top", h + 5);
};
return AIRTIME;
}(AIRTIME || {}));
$(document).ready(AIRTIME.playlist.onReady);
$(window).resize(AIRTIME.playlist.onResize);