//-------------------------------------------------------------------------------------------------------------------------------- // Playlist Functions //-------------------------------------------------------------------------------------------------------------------------------- var AIRTIME = (function(AIRTIME){ if (AIRTIME.playlist === undefined) { AIRTIME.playlist = {}; } var mod = AIRTIME.playlist, viewport, $lib, $pl, widgetHeight; 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("^[0-9]+(\\.\\d+)?$"); 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 enter a valid time in seconds. Eg. 0.5")); return; } else { hideError(span); } $.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 enter a valid time in seconds. Eg. 0.5")); return; } else { hideError(span); } $.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 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); AIRTIME.tabs.getActiveTab().setName(json.name); AIRTIME.playlist.validatePlaylistElements(); redrawLib(); } mod.setFadeIcon = function() { 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").attr("disabled", "disabled"); } 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").attr("disabled", "disabled"); } else { $pl.find("#spl_crossfade").removeAttr("disabled"); } } $('.zend_form + .spl-no-margin > div:has(*:visible):last').css('margin-left', 0); } mod.getId = function(pl) { pl = (pl === undefined) ? $pl : pl; return parseInt(pl.find(".obj_id").val(), 10); }; mod.getModified = function(pl) { pl = (pl === undefined) ? $pl : pl; 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); } 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(); } //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("input.spl_main_fade_in"); var fadeOut = $pl.find("input.spl_main_fade_out"); if (json.fadeIn == null) { fadeIn.parent().prev().hide(); fadeIn.hide(); } else { fadeIn.parent().prev().show(); fadeIn.show(); fadeIn.val(json.fadeIn); fadeIn.text(json.fadeIn); } if (json.fadeOut == null) { fadeOut.parent().prev().hide(); fadeOut.hide(); } else { fadeOut.parent().prev().show(); fadeOut.show(); fadeOut.val(json.fadeOut); fadeOut.text(json.fadeOut); } if (json.fadeIn != null || json.fadeOut != null) { $pl.find("#crossfade_main").show(); } } }); } }); $pl.on("blur", "input.spl_main_fade_in", function(event){ event.stopPropagation(); var url = baseUrl+"playlist/set-playlist-fades", input = $(this), fadeIn = $.trim(input.val()), lastMod = mod.getModified(), type = $pl.find('.obj_type').val(); if (!isFadeValid(fadeIn)){ showError(input, $.i18n._("Please enter a valid time in seconds. Eg. 0.5")); return; } else { hideError(input); } $.post(url, {format: "json", fadeIn: fadeIn, modified: lastMod, type: type}, function(json){ hideError(input); if (json.modified !== undefined) { mod.setModified(json.modified); } }); }); $pl.on("blur", "input.spl_main_fade_out", function(event){ event.stopPropagation(); var url = baseUrl+"playlist/set-playlist-fades", input = $(this), fadeOut = $.trim(input.val()), lastMod = mod.getModified(), type = $pl.find('.obj_type').val(); if (!isFadeValid(fadeOut)){ showError(input, $.i18n._("Please enter a valid time in seconds. Eg. 0.5")); return; } else { hideError(input); } $.post(url, {format: "json", fadeOut: fadeOut, modified: lastMod, type: type}, function(json){ hideError(input); 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); AIRTIME.tabs.getActiveTab().setName(json.name).close(); var $ws_id = $(".active-tab .obj_id"); $ws_id.attr("value", json.streamId); var $ws_id = $("#ws_delete"); $ws_id.show(); 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"), tab = AIRTIME.tabs.get(tabId); // 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 = tab.tab.find('.tab-name'); var name = playlistNameElem.text().trim(); // TODO: refactor - this code is pretty finicky... if ((name == $.i18n._("Untitled Playlist") || name == $.i18n._("Untitled Smart Block")) && tab.contents.find(".spl_sortable .spl_empty").length == 1) { mod.fnDelete(undefined, tab); } tab.close(); // save settings if we are not closing the "Scheduled Shows" tab if (tabId != "0") { $.ajax( { url : baseUrl+"usersettings/set-library-screen-settings", type : "POST", data : { settings : { playlist : false }, format : "json" }, dataType : "json" }); } }); $pl.find("#save_button").unbind().on("click", 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); AIRTIME.tabs.getActiveTab().setName(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(); } } mod.setFadeIcon(); disableLoadingIcon(); } ); }); $pl.find("#pl-bl-clear-content").unbind().on("click", function(event) { var sUrl = baseUrl+"playlist/empty-content", oData = {}; playlistRequest(sUrl, oData); }); } 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++) { //console.log(aSelected[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._initPlaylistTabEvents = function(newTab) { newTab.assignTabClickHandler(function() { if (!$(this).hasClass('active')) { newTab.switchTo(); var type = newTab.contents.find(".obj_type").val(); if (type == "playlist" || type == "block") { $.post(baseUrl + 'playlist/edit', { format: "json", id: newTab.contents.find(".obj_id").val(), type: type }); } } }); mod.init(); // functions in smart_blockbuilder.js setupUI(); appendAddButton(); appendModAddButton(); removeButtonCheck(); mod.setFadeIcon(); }; mod._initFileMdEvents = function(newTab) { var fileId = newTab.wrapper.find('#file_id').val(); newTab.contents.find(".md-cancel").on("click", function() { newTab.close(); }); newTab.contents.find(".md-save").on("click", function() { var data = newTab.wrapper.find(".edit-md-dialog form").serializeArray(); $.post(baseUrl+'library/edit-file-md', {format: "json", id: fileId, 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(); } }); newTab.close(); }); newTab.contents.find(".md-publish").on("click", function() { AIRTIME.publish.openPublishDialog(fileId); }); newTab.wrapper.find('.edit-md-dialog').on("keyup", function(event) { // Don't submit if the user hits enter in a textarea (description) if ($(event.target).is('input') && event.keyCode === 13) { newTab.wrapper.find('.md-save').click(); } }); mod.setupEventListeners(); }; mod.fnNew = function() { var url = baseUrl+'playlist/new'; stopAudioPreview(); $.post(url, {format: "json", type: 'playlist'}, function(json) { var uid = AIRTIME.library.MediaTypeStringEnum.PLAYLIST+"_"+json.id; AIRTIME.tabs.openTab(json.html, uid, AIRTIME.playlist._initPlaylistTabEvents); redrawLib(); }); }; mod.fnWsNew = function() { var url = baseUrl+'webstream/new'; stopAudioPreview(); $.post(url, {format: "json"}, function(json) { var uid = AIRTIME.library.MediaTypeStringEnum.WEBSTREAM+"_"+json.id; AIRTIME.tabs.openTab(json.html, uid, AIRTIME.playlist._initPlaylistTabEvents); redrawLib(); }); }; mod.fnNewBlock = function() { var url = baseUrl+'playlist/new'; stopAudioPreview(); $.post(url, {format: "json", type: 'block'}, function(json){ var uid = AIRTIME.library.MediaTypeStringEnum.BLOCK+"_"+json.id; AIRTIME.tabs.openTab(json.html, uid, AIRTIME.playlist._initPlaylistTabEvents); redrawLib(); }); }; mod.fileMdEdit = function(json, uid) { AIRTIME.tabs.openTab(json.html, uid, AIRTIME.playlist._initFileMdEvents); }; mod.fnEdit = function(data, url) { stopAudioPreview(); $.post(url, {format: "json", id: data.id, type: data.ftype}, function(json) { AIRTIME.tabs.openTab(json.html, data.tr_id, AIRTIME.playlist._initPlaylistTabEvents); redrawLib(); }); }; mod.fnDelete = function(plid, tab) { var url, id, lastMod, type, pl = tab.contents; stopAudioPreview(); id = (plid === undefined) ? mod.getId(pl) : plid; lastMod = mod.getModified(pl); type = pl.find('.obj_type').val(); url = baseUrl+'playlist/delete'; $.post(url, {format: "json", ids: id, modified: lastMod, type: type}, function(json) { redrawLib(); }); }; mod.fnWsDelete = function(wsid) { var url, id, lastMod; stopAudioPreview(); id = (wsid === undefined) ? mod.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){ var uid = AIRTIME.library.MediaTypeStringEnum.WEBSTREAM+"_"+id; AIRTIME.tabs.openTab(json.html, uid, AIRTIME.playlist._initPlaylistTabEvents); redrawLib(); }); }; mod.disableUI = function() { $lib.block({ message: "", theme: true, applyPlatformOpacityRules: false }); $pl.block({ message: "", theme: true, applyPlatformOpacityRules: false }); }; mod.enableUI = function() { $lib.unblock(); $pl.unblock(); setupUI(); }; mod.playlistResponse = function(json){ if (json.error !== undefined || (json.result !== undefined && json.result != 0)) { if (json.error) { playlistError(json); } AIRTIME.playlist.replaceForm(json); AIRTIME.playlist.init(); } else { setPlaylistContent(json); mod.setFadeIcon(); $pl.find('.errors').hide(); } mod.enableUI(); }; mod.replaceForm = function(json){ $pl.find('.editor_pane_wrapper').html(json.html); var uid = AIRTIME.library.MediaTypeStringEnum.BLOCK+"_"+json.id; AIRTIME.tabs.openTab(json.html, uid, AIRTIME.playlist._initPlaylistTabEvents); }; 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.setupEventListeners = function() { initialEvents(); }; mod.setCurrent = function(pl) { $pl = pl; var type = $pl.find('.obj_type').val(); if ($.inArray(type, Object.keys(AIRTIME.library.MediaTypeFullToStringEnum)) > -1) { $.post(baseUrl + "playlist/change-playlist", { id: mod.getId($pl), type: type }); } }; mod.init = function() { if (!$pl) return; $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(); mod.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(); }; return AIRTIME; }(AIRTIME || {})); $(document).ready(AIRTIME.playlist.onReady);