//-------------------------------------------------------------------------------------------------------------------------------- // 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 = "
", 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 = "", 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; } initFileMdEvents(newTab); initialEvents(); } function initFileMdEvents(newTab) { 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(); }); newTab.wrapper.find(".md-save").on("click", function() { var file_id = newTab.wrapper.find('#file_id').val(), data = newTab.wrapper.find("#edit-md-dialog form").serializeArray(); $.post(baseUrl+'library/edit-file-md', {format: "json", id: file_id, data: data}, function() { // don't redraw the library table if we are on calendar page // we would be on calendar if viewing recorded file metadata if ($("#schedule_calendar").length === 0) { oTable.fnStandingRedraw(); } }); AIRTIME.playlist.closeTab(); }); newTab.wrapper.find('#edit-md-dialog').on("keyup", function(event) { if (event.keyCode === 13) { newTab.wrapper.find('.md-save').click(); } }); } 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 += "
  • " + ""+ele.track_title+" - " + ""+ele.creator+"" + ""+ele.length+"" + "
  • "; } }) } else { for (var key in data.crit){ $.each(data.crit[key], function(index, ele){ var extra = (ele['extra']==null)?"":"- "+ele['extra']; $html += "
  • " + ""+ele['display_name']+"" + ""+ele['display_modifier']+"" + ""+ele['value']+"" + ""+extra+"" + "
  • "; }); } $html += "

  • "+$.i18n._("Limit to: ")+data.limit.value+" "+data.limit.display_modifier+"
  • "; } $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 $('
  • ')[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);