Merge branch 'devel' of dev.sourcefabric.org:airtime into devel

This commit is contained in:
Rudi Grinberg 2012-09-18 18:21:00 -04:00
commit 33be48e9e3
6 changed files with 452 additions and 422 deletions

View file

@ -41,7 +41,7 @@ class LibraryController extends Zend_Controller_Action
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/buttons/buttons.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/airtime/buttons/buttons.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/utilities/utilities.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/airtime/utilities/utilities.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/library/library.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/airtime/library/library.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($this->view->baseUrl('/js/airtime/library/events/library_playlistbuilder.js'), 'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/airtime/library/events/library_playlistbuilder.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headLink()->appendStylesheet($baseUrl.'/css/media_library.css?'.$CC_CONFIG['airtime_version']); $this->view->headLink()->appendStylesheet($baseUrl.'/css/media_library.css?'.$CC_CONFIG['airtime_version']);
$this->view->headLink()->appendStylesheet($baseUrl.'/css/jquery.contextMenu.css?'.$CC_CONFIG['airtime_version']); $this->view->headLink()->appendStylesheet($baseUrl.'/css/jquery.contextMenu.css?'.$CC_CONFIG['airtime_version']);

View file

@ -363,10 +363,10 @@ function setupUI() {
$(".playlist_type_help_icon").qtip({ $(".playlist_type_help_icon").qtip({
content: { content: {
text: "A static playlist will save the criteria and generate the playlist content immediately." + text: "A static smart block will save the criteria and generate the block content immediately." +
"This allows you to edit and view it in the Playlist Builder before adding it to a show.<br /><br />" + "This allows you to edit and view it in the Library before adding it to a show.<br /><br />" +
"A dynamic playlist will only save the criteria. The playlist content will get generated upon " + "A dynamic smart block will only save the criteria. The block content will get generated upon " +
"adding it to a show. You will not be able to view and edit it in the Playlist Builder." "adding it to a show. You will not be able to view and edit the content in the Library."
}, },
hide: { hide: {
delay: 500, delay: 500,

View file

@ -164,9 +164,15 @@ function buildScheduleDialog (json) {
draggable: true, draggable: true,
modal: true, modal: true,
close: closeDialog, close: closeDialog,
buttons: {"Ok": function() { buttons: [
$(this).dialog("close"); {
}} text: "Ok",
"class": "btn",
click: function() {
$(this).dialog("close");
}
}
]
}); });
//set the start end times so the builder datatables knows its time range. //set the start end times so the builder datatables knows its time range.
@ -207,9 +213,15 @@ function buildContentDialog (json){
height: height, height: height,
modal: true, modal: true,
close: closeDialog, close: closeDialog,
buttons: {"Ok": function() { buttons: [
dialog.remove(); {
}} text: "Ok",
"class": "btn",
click: function() {
dialog.remove();
}
}
]
}); });
dialog.dialog('open'); dialog.dialog('open');

View file

@ -1,370 +1,378 @@
/* /*
author: ApmeM (artem.votincev@gmail.com) author: ApmeM (artem.votincev@gmail.com)
date: 9-June-2010 date: 9-June-2010
version: 1.4 version: 1.4
download: http://code.google.com/p/jq-serverbrowse/ download: http://code.google.com/p/jq-serverbrowse/
*/ */
(function($) { (function($) {
$.fn.serverBrowser = function(settings) { $.fn.serverBrowser = function(settings) {
this.each(function() { this.each(function() {
var config = { var config = {
// Event function // Event function
// Appear when user click 'Ok' button, or doubleclick on file // Appear when user click 'Ok' button, or doubleclick on file
onSelect: function(file) { onSelect: function(file) {
alert('You select: ' + file); alert('You select: ' + file);
}, },
onLoad: function() { onLoad: function() {
return config.basePath; return config.basePath;
}, },
multiselect: false, multiselect: false,
// Image parameters // Image parameters
// System images (loading.gif, unknown.png, folder.png and images from knownPaths) will be referenced to systemImageUrl // System images (loading.gif, unknown.png, folder.png and images from knownPaths) will be referenced to systemImageUrl
// if systemImageUrl is empty or not specified - imageUrl will be taken // if systemImageUrl is empty or not specified - imageUrl will be taken
// All other images (like images for extension) will be taken from imageUrl // All other images (like images for extension) will be taken from imageUrl
imageUrl: 'img/', imageUrl: 'img/',
systemImageUrl: '', systemImageUrl: '',
showUpInList: false, showUpInList: false,
// Path properties // Path properties
// Base path, that links should start from. // Base path, that links should start from.
// If opened path is not under this path, alert will be shown and nothing will be opened // If opened path is not under this path, alert will be shown and nothing will be opened
// Path separator, that will be used to split specified paths and join paths to a string // Path separator, that will be used to split specified paths and join paths to a string
basePath: 'C:', basePath: 'C:',
separatorPath: '/', separatorPath: '/',
// Paths, that will be displayed on the left side of the dialog // Paths, that will be displayed on the left side of the dialog
// This is a link to specified paths on the server // This is a link to specified paths on the server
useKnownPaths: true, useKnownPaths: true,
knownPaths: [{text:'Desktop', image:'desktop.png', path:'C:/Users/All Users/Desktop'}, knownPaths: [{text:'Desktop', image:'desktop.png', path:'C:/Users/All Users/Desktop'},
{text:'Documents', image:'documents.png', path:'C:/Users/All Users/Documents'}], {text:'Documents', image:'documents.png', path:'C:/Users/All Users/Documents'}],
// Images for known extension (like 'png', 'exe', 'zip'), that will be displayed with its real names // Images for known extension (like 'png', 'exe', 'zip'), that will be displayed with its real names
// Images, that is not in this list will be referenced to 'unknown.png' image // Images, that is not in this list will be referenced to 'unknown.png' image
// If list is empty - all images is known. // If list is empty - all images is known.
knownExt: [], knownExt: [],
// Server path to this plugin handler // Server path to this plugin handler
handlerUrl: 'browserDlg.txt', handlerUrl: 'browserDlg.txt',
// JQuery-ui dialog settings // JQuery-ui dialog settings
title: 'Browse', title: 'Browse',
width: 300, width: 300,
height: 300, height: 300,
position: ['center', 'top'], position: ['center', 'top'],
// Administrative parameters used to // Administrative parameters used to
// help programmer or system administrator // help programmer or system administrator
requestMethod: 'POST', requestMethod: 'POST',
}; };
if (settings) $.extend(config, settings); if (settings) $.extend(config, settings);
// Required configuration elements // Required configuration elements
// We need to set some configuration elements without user // We need to set some configuration elements without user
// For example there should be 2 buttons on the bottom, // For example there should be 2 buttons on the bottom,
// And dialog should be opened after button is pressed, not when it created // And dialog should be opened after button is pressed, not when it created
// Also we need to know about dialog resizing // Also we need to know about dialog resizing
$.extend(config, { $.extend(config, {
autoOpen: false, autoOpen: false,
modal: true, modal: true,
buttons: { buttons: [
"Cancel": function() { {
browserDlg.dialog("close"); text: "Cancel",
}, "class": "btn",
"Open": function() { click: function() {
doneOk(); browserDlg.dialog("close");
}, }
}, },
resize: function(event, ui) { {
recalculateSize(event, ui); text: "Open",
}, "class": "btn",
}); click: function() {
doneOk();
function systemImageUrl() }
{ }
if (config.systemImageUrl.length == 0) { ],
return config.imageUrl; resize: function(event, ui) {
} else{ recalculateSize(event, ui);
return config.systemImageUrl; },
} });
}
function systemImageUrl()
var privateConfig = { {
// This stack array will store history navigation data if (config.systemImageUrl.length == 0) {
// When user open new directory, old directory will be added to this list return config.imageUrl;
// If user want, he will be able to move back by this history } else{
browserHistory: [], return config.systemImageUrl;
}
// This array contains all currently selected items }
// When user select element, it will add associated path into this array
// When user deselect element - associated path will be removed var privateConfig = {
// Exception: if 'config.multiselect' is false, only one element will be stored in this array. // This stack array will store history navigation data
selectedItems: [], // When user open new directory, old directory will be added to this list
} // If user want, he will be able to move back by this history
browserHistory: [],
// Main dialog div
// It will be converted into jQuery-ui dialog box using my configuration parameters // This array contains all currently selected items
// It contains 3 divs // When user select element, it will add associated path into this array
var browserDlg = $('<div title="' + config.title + '"></div>').css({'overflow': 'hidden'}).appendTo(document.body); // When user deselect element - associated path will be removed
browserDlg.dialog(config); // Exception: if 'config.multiselect' is false, only one element will be stored in this array.
selectedItems: [],
// First div on the top }
// It contains textbox field and buttons
// User can enter any paths he want to open in this textbox and press enter // Main dialog div
// There is 3 buttons on the panel: // It will be converted into jQuery-ui dialog box using my configuration parameters
var enterPathDiv = $('<div></div>').addClass('ui-widget-content').appendTo(browserDlg).css({'height': '30px', 'width': '100%', 'padding-top': '7px'}); // It contains 3 divs
var browserDlg = $('<div title="' + config.title + '"></div>').css({'overflow': 'hidden'}).appendTo(document.body);
var enterButton = $('<div></div>').css({'float': 'left', 'vertical-align': 'middle', 'margin-left': '6px'}).addClass('ui-corner-all').hover( browserDlg.dialog(config);
function() { $(this).addClass('ui-state-hover'); },
function() { $(this).removeClass('ui-state-hover'); } // First div on the top
); // It contains textbox field and buttons
// User can enter any paths he want to open in this textbox and press enter
var enterLabel = $('<span></span>').text('Look in: ').appendTo(enterButton.clone(false).appendTo(enterPathDiv)); // There is 3 buttons on the panel:
var enterPathDiv = $('<div></div>').addClass('ui-widget-content').appendTo(browserDlg).css({'height': '30px', 'width': '100%', 'padding-top': '7px'});
var enterText = $('<input type="text">').keypress(function(e) {
if (e.keyCode == '13') { var enterButton = $('<div></div>').css({'float': 'left', 'vertical-align': 'middle', 'margin-left': '6px'}).addClass('ui-corner-all').hover(
e.preventDefault(); function() { $(this).addClass('ui-state-hover'); },
loadPath(enterText.val()); function() { $(this).removeClass('ui-state-hover'); }
} );
}).appendTo(enterButton.clone(false).appendTo(enterPathDiv));
var enterLabel = $('<span></span>').text('Look in: ').appendTo(enterButton.clone(false).appendTo(enterPathDiv));
// Back button. var enterText = $('<input type="text">').keypress(function(e) {
// When user click on it, 2 last elements of the history pop from the list, and reload second of them. if (e.keyCode == '13') {
var enterBack = $('<div></div>').addClass('ui-corner-all ui-icon ui-icon-circle-arrow-w').click(function(){ e.preventDefault();
privateConfig.browserHistory.pop(); // Remove current element. It is not required now. loadPath(enterText.val());
var backPath = config.basePath; }
if(privateConfig.browserHistory.length > 0){ }).appendTo(enterButton.clone(false).appendTo(enterPathDiv));
backPath = privateConfig.browserHistory.pop();
}
loadPath(backPath); // Back button.
}).appendTo(enterButton.clone(true).appendTo(enterPathDiv)); // When user click on it, 2 last elements of the history pop from the list, and reload second of them.
var enterBack = $('<div></div>').addClass('ui-corner-all ui-icon ui-icon-circle-arrow-w').click(function(){
// Level Up Button privateConfig.browserHistory.pop(); // Remove current element. It is not required now.
// When user click on it, last element of the history will be taken, and '..' will be applied to the end of the array. var backPath = config.basePath;
var enterUp = $('<div></div>').addClass('ui-corner-all ui-icon ui-icon-arrowreturnthick-1-n').click(function(){ if(privateConfig.browserHistory.length > 0){
backPath = privateConfig.browserHistory[privateConfig.browserHistory.length - 1]; backPath = privateConfig.browserHistory.pop();
if(backPath != config.basePath){ }
loadPath(backPath + config.separatorPath + '..'); loadPath(backPath);
} }).appendTo(enterButton.clone(true).appendTo(enterPathDiv));
}).appendTo(enterButton.clone(true).appendTo(enterPathDiv));
// Level Up Button
// Second div is on the left // When user click on it, last element of the history will be taken, and '..' will be applied to the end of the array.
// It contains images and texts for pre-defined paths var enterUp = $('<div></div>').addClass('ui-corner-all ui-icon ui-icon-arrowreturnthick-1-n').click(function(){
// User just click on them and it will open pre-defined path backPath = privateConfig.browserHistory[privateConfig.browserHistory.length - 1];
var knownPathDiv = $('<div></div>').addClass('ui-widget-content').css({'text-align':'center', 'overflow': 'auto', 'float': 'left', 'width': '100px'}); if(backPath != config.basePath){
if(config.useKnownPaths){ loadPath(backPath + config.separatorPath + '..');
knownPathDiv.appendTo(browserDlg); }
$.each(config.knownPaths, function(index, path) { }).appendTo(enterButton.clone(true).appendTo(enterPathDiv));
var knownDiv = $('<div></div>').css({'margin':'10px'}).hover(
function() { $(this).addClass('ui-state-hover'); }, // Second div is on the left
function() { $(this).removeClass('ui-state-hover'); } // It contains images and texts for pre-defined paths
).click(function() { // User just click on them and it will open pre-defined path
loadPath(path.path); var knownPathDiv = $('<div></div>').addClass('ui-widget-content').css({'text-align':'center', 'overflow': 'auto', 'float': 'left', 'width': '100px'});
}).appendTo(knownPathDiv); if(config.useKnownPaths){
knownPathDiv.appendTo(browserDlg);
$('<img />').attr({ src: systemImageUrl() + config.separatorPath + path.image }).css({ width: '32px', margin: '5px 10px 5px 5px' }).appendTo(knownDiv); $.each(config.knownPaths, function(index, path) {
$('<br/>').appendTo(knownDiv); var knownDiv = $('<div></div>').css({'margin':'10px'}).hover(
$('<span></span>').text(path.text).appendTo(knownDiv); function() { $(this).addClass('ui-state-hover'); },
}); function() { $(this).removeClass('ui-state-hover'); }
} ).click(function() {
loadPath(path.path);
// Third div is everywhere :) }).appendTo(knownPathDiv);
// It show files and folders in the current path
// User can click on path to select or deselect it $('<img />').attr({ src: systemImageUrl() + config.separatorPath + path.image }).css({ width: '32px', margin: '5px 10px 5px 5px' }).appendTo(knownDiv);
// Doubleclick on path will open it $('<br/>').appendTo(knownDiv);
// Also doubleclick on file will select this file and close dialog $('<span></span>').text(path.text).appendTo(knownDiv);
var browserPathDiv = $('<div></div>').addClass('ui-widget-content').css({'float': 'right', 'overflow': 'auto'}).appendTo(browserDlg); });
}
// Now everything is done
// When user will be ready - he just click on the area you select for this plugin and dialog will appear // Third div is everywhere :)
$(this).click(function() { // It show files and folders in the current path
privateConfig.browserHistory = []; // User can click on path to select or deselect it
var startpath = removeBackPath(config.onLoad()); // Doubleclick on path will open it
// Also doubleclick on file will select this file and close dialog
startpath = startpath.split(config.separatorPath); var browserPathDiv = $('<div></div>').addClass('ui-widget-content').css({'float': 'right', 'overflow': 'auto'}).appendTo(browserDlg);
startpath.pop();
startpath = startpath.join(config.separatorPath); // Now everything is done
// When user will be ready - he just click on the area you select for this plugin and dialog will appear
if(!checkBasePath(startpath)){ $(this).click(function() {
startpath = config.basePath; privateConfig.browserHistory = [];
} var startpath = removeBackPath(config.onLoad());
loadPath(startpath);
browserDlg.dialog('open'); startpath = startpath.split(config.separatorPath);
recalculateSize(); startpath.pop();
}); startpath = startpath.join(config.separatorPath);
// Function check if specified path is a child path of a 'config.basePath' if(!checkBasePath(startpath)){
// If it is not - user should see message, that path invalid, or path should be changed to valid. startpath = config.basePath;
function checkBasePath(path){ }
if(config.basePath == '') loadPath(startpath);
return true; browserDlg.dialog('open');
var confPath = config.basePath.split(config.separatorPath); recalculateSize();
var curPath = path.split(config.separatorPath); });
if(confPath.length > curPath.length)
return false; // Function check if specified path is a child path of a 'config.basePath'
var result = true; // If it is not - user should see message, that path invalid, or path should be changed to valid.
$.each(confPath, function(index, partConfPath) { function checkBasePath(path){
if(partConfPath != curPath[index]){ if(config.basePath == '')
result = false; return true;
} var confPath = config.basePath.split(config.separatorPath);
}); var curPath = path.split(config.separatorPath);
return result; if(confPath.length > curPath.length)
} return false;
var result = true;
// Function remove '..' parts of the path $.each(confPath, function(index, partConfPath) {
// Process depend on config.separatorPath option if(partConfPath != curPath[index]){
// On the server side you need to check / or \ separators result = false;
function removeBackPath(path){ }
var confPath = config.basePath.split(config.separatorPath); });
var curPath = path.split(config.separatorPath); return result;
var newcurPath = []; }
$.each(curPath, function(index, partCurPath) {
if(partCurPath == ".."){ // Function remove '..' parts of the path
newcurPath.pop(); // Process depend on config.separatorPath option
}else{ // On the server side you need to check / or \ separators
newcurPath.push(partCurPath); function removeBackPath(path){
} var confPath = config.basePath.split(config.separatorPath);
}); var curPath = path.split(config.separatorPath);
return newcurPath.join(config.separatorPath); var newcurPath = [];
} $.each(curPath, function(index, partCurPath) {
if(partCurPath == ".."){
// This function will be called when user click 'Open' newcurPath.pop();
// It check if any path is selected, and call config.onSelect function with path list }else{
function doneOk(){ newcurPath.push(partCurPath);
var newCurPath = []; }
$.each(privateConfig.selectedItems, function(index, item) { });
newCurPath.push($.data(item, 'path')); return newcurPath.join(config.separatorPath);
}); }
if(newCurPath.length == 0) {
newCurPath.push(privateConfig.browserHistory.pop()); // This function will be called when user click 'Open'
} // It check if any path is selected, and call config.onSelect function with path list
function doneOk(){
if(config.multiselect) var newCurPath = [];
config.onSelect(newCurPath); $.each(privateConfig.selectedItems, function(index, item) {
else { newCurPath.push($.data(item, 'path'));
if(newCurPath.length == 1) { });
config.onSelect(newCurPath[0]); if(newCurPath.length == 0) {
} else if(newCurPath.length > 1){ newCurPath.push(privateConfig.browserHistory.pop());
alert('Plugin work incorrectly. If error repeat, please add issue into http://code.google.com/p/jq-serverbrowse/issues/list with steps to reproduce.'); }
return;
} if(config.multiselect)
} config.onSelect(newCurPath);
browserDlg.dialog("close"); else {
} if(newCurPath.length == 1) {
config.onSelect(newCurPath[0]);
// Function recalculate and set new width and height for left and right div elements } else if(newCurPath.length > 1){
// height have '-2' because of the borders alert('Plugin work incorrectly. If error repeat, please add issue into http://code.google.com/p/jq-serverbrowse/issues/list with steps to reproduce.');
// width have '-4' because of a border an 2 pixels space between divs return;
function recalculateSize(event, ui){ }
knownPathDiv.css({'height' : browserDlg.height() - enterPathDiv.outerHeight(true) - 2}); }
browserPathDiv.css({'height' : browserDlg.height() - enterPathDiv.outerHeight(true) - 2, browserDlg.dialog("close");
'width' : browserDlg.width() - knownPathDiv.outerWidth(true) - 4}); }
}
// Function recalculate and set new width and height for left and right div elements
// Function adds new element into browserPathDiv element depends on file parameters // height have '-2' because of the borders
// If file.isError is set, error message will be displayed instead of clickable area // width have '-4' because of a border an 2 pixels space between divs
// Clickable div contain image from extension and text from file parameter function recalculateSize(event, ui){
function addElement(file){ knownPathDiv.css({'height' : browserDlg.height() - enterPathDiv.outerHeight(true) - 2});
var itemDiv = $('<div></div>').css({ margin: '2px' }).appendTo(browserPathDiv); browserPathDiv.css({'height' : browserDlg.height() - enterPathDiv.outerHeight(true) - 2,
if(file.isError) 'width' : browserDlg.width() - knownPathDiv.outerWidth(true) - 4});
{ }
itemDiv.addClass('ui-state-error ui-corner-all').css({padding: '0pt 0.7em'});
var p = $('<p></p>').appendTo(itemDiv); // Function adds new element into browserPathDiv element depends on file parameters
$('<span></span>').addClass('ui-icon ui-icon-alert').css({'float': 'left', 'margin-right': '0.3em'}).appendTo(p); // If file.isError is set, error message will be displayed instead of clickable area
$('<span></span>').text(file.name).appendTo(p); // Clickable div contain image from extension and text from file parameter
}else function addElement(file){
{ var itemDiv = $('<div></div>').css({ margin: '2px' }).appendTo(browserPathDiv);
var fullPath = file.path + config.separatorPath + file.name; if(file.isError)
itemDiv.hover( {
function() { $(this).addClass('ui-state-hover'); }, itemDiv.addClass('ui-state-error ui-corner-all').css({padding: '0pt 0.7em'});
function() { $(this).removeClass('ui-state-hover'); } var p = $('<p></p>').appendTo(itemDiv);
); $('<span></span>').addClass('ui-icon ui-icon-alert').css({'float': 'left', 'margin-right': '0.3em'}).appendTo(p);
var itemImage = $('<img />').css({ width: '16px', margin: '0 5px 0 0' }).appendTo(itemDiv); $('<span></span>').text(file.name).appendTo(p);
var itemText = $('<span></span>').text(file.name).appendTo(itemDiv); }else
if (file.isFolder) {
itemImage.attr({ src: systemImageUrl() + 'folder.png' }); var fullPath = file.path + config.separatorPath + file.name;
else { itemDiv.hover(
ext = file.name.split('.').pop(); function() { $(this).addClass('ui-state-hover'); },
var res = ''; function() { $(this).removeClass('ui-state-hover'); }
if (ext == '' || ext == file.name || (config.knownExt.length > 0 && $.inArray(ext, config.knownExt) < 0)) );
itemImage.attr({ src: systemImageUrl() + 'unknown.png' }); var itemImage = $('<img />').css({ width: '16px', margin: '0 5px 0 0' }).appendTo(itemDiv);
else var itemText = $('<span></span>').text(file.name).appendTo(itemDiv);
itemImage.attr({ src: config.imageUrl + ext + '.png' }); if (file.isFolder)
} itemImage.attr({ src: systemImageUrl() + 'folder.png' });
$.data(itemDiv, 'path', fullPath); else {
itemDiv.unbind('click').bind('click', function(e) { ext = file.name.split('.').pop();
if(!$(this).hasClass('ui-state-active')) { var res = '';
if(!config.multiselect && privateConfig.selectedItems.length > 0) { if (ext == '' || ext == file.name || (config.knownExt.length > 0 && $.inArray(ext, config.knownExt) < 0))
$(privateConfig.selectedItems[0]).click(); itemImage.attr({ src: systemImageUrl() + 'unknown.png' });
} else
privateConfig.selectedItems.push(itemDiv); itemImage.attr({ src: config.imageUrl + ext + '.png' });
}else{ }
var newCurPath = []; $.data(itemDiv, 'path', fullPath);
$.each(privateConfig.selectedItems, function(index, item) { itemDiv.unbind('click').bind('click', function(e) {
if($.data(item, 'path') != fullPath) if(!$(this).hasClass('ui-state-active')) {
newCurPath.push(item); if(!config.multiselect && privateConfig.selectedItems.length > 0) {
}); $(privateConfig.selectedItems[0]).click();
privateConfig.selectedItems = newCurPath; }
} privateConfig.selectedItems.push(itemDiv);
$(this).toggleClass('ui-state-active'); }else{
}); var newCurPath = [];
$.each(privateConfig.selectedItems, function(index, item) {
itemDiv.unbind('dblclick').bind('dblclick', function(e) { if($.data(item, 'path') != fullPath)
if (file.isFolder){ newCurPath.push(item);
loadPath(fullPath); });
} else { privateConfig.selectedItems = newCurPath;
privateConfig.selectedItems = [itemDiv]; }
doneOk(); $(this).toggleClass('ui-state-active');
} });
});
} itemDiv.unbind('dblclick').bind('dblclick', function(e) {
} if (file.isFolder){
loadPath(fullPath);
// Main plugin function } else {
// When user enter path manually, select it from pre-defined path, or doubleclick in browser this function will call privateConfig.selectedItems = [itemDiv];
// It send a request on the server to retrieve child directories and files of the specified path doneOk();
// If path is not under 'config.basePath', alert will be shown and nothing will be opened }
function loadPath(path) { });
privateConfig.selectedItems = []; }
}
// First we need to remove all '..' parts of the path
path = removeBackPath(path); // Main plugin function
// When user enter path manually, select it from pre-defined path, or doubleclick in browser this function will call
// Then we need to check, if path based on 'config.basePath' // It send a request on the server to retrieve child directories and files of the specified path
if(!checkBasePath(path)) { // If path is not under 'config.basePath', alert will be shown and nothing will be opened
alert('Path should be based from ' + config.basePath); function loadPath(path) {
return; privateConfig.selectedItems = [];
}
// First we need to remove all '..' parts of the path
// Then we can put this path into history path = removeBackPath(path);
privateConfig.browserHistory.push(path);
// Then we need to check, if path based on 'config.basePath'
// Show it to user if(!checkBasePath(path)) {
enterText.val(path); alert('Path should be based from ' + config.basePath);
return;
// And load }
$.ajax({
url: config.handlerUrl, // Then we can put this path into history
type: config.requestMethod, privateConfig.browserHistory.push(path);
data: {
action: 'browse', // Show it to user
path: path, enterText.val(path);
time: new Date().getTime()
}, // And load
beforeSend: function() { $.ajax({
browserPathDiv.empty().css({ 'text-align': 'center' }); url: config.handlerUrl,
$('<img />').attr({ src: systemImageUrl() + 'loading.gif' }).css({ width: '32px' }).appendTo(browserPathDiv); type: config.requestMethod,
}, data: {
success: function(files) { action: 'browse',
browserPathDiv.empty().css({ 'text-align': 'left' }); path: path,
if(path != config.basePath && config.showUpInList){ time: new Date().getTime()
addElement({name: '..', isFolder: true, isError: false, path: path}); },
} beforeSend: function() {
$.each(files, function(index, file) { browserPathDiv.empty().css({ 'text-align': 'center' });
addElement($.extend(file, {path: path})); $('<img />').attr({ src: systemImageUrl() + 'loading.gif' }).css({ width: '32px' }).appendTo(browserPathDiv);
}); },
}, success: function(files) {
dataType: 'json' browserPathDiv.empty().css({ 'text-align': 'left' });
}); if(path != config.basePath && config.showUpInList){
} addElement({name: '..', isFolder: true, isError: false, path: path});
}); }
return this; $.each(files, function(index, file) {
}; addElement($.extend(file, {path: path}));
})(jQuery); });
},
dataType: 'json'
});
}
});
return this;
};
})(jQuery);

View file

@ -1,2 +1,2 @@
[main] [main]
liquidsoap_tar_url = http://dl.dropbox.com/u/256410/airtime/liquidsoap-1.0.1-full.tar.gz liquidsoap_tar_url = http://dl.dropbox.com/u/256410/airtime/savonet.tar.gz

View file

@ -23,7 +23,7 @@ env.host_string
env.vm_download_url = "http://host.sourcefabric.org/vms/VirtualBox" env.vm_download_url = "http://host.sourcefabric.org/vms/VirtualBox"
#fab -f fab_setup.py ubuntu_lucid_64 airtime_182_tar airtime_190_tar #fab -f fab_setup.py ubuntu_lucid_64 airtime_182_tar airtime_190_tar
def do_sudo(command): def do_sudo(command):
result = sudo(command) result = sudo(command)
@ -33,7 +33,7 @@ def do_sudo(command):
sys.exit(1) sys.exit(1)
else: else:
return result return result
def do_run(command): def do_run(command):
result = run(command) result = run(command)
if result.return_code != 0: if result.return_code != 0:
@ -42,7 +42,7 @@ def do_run(command):
sys.exit(1) sys.exit(1)
else: else:
return result return result
def do_local(command, capture=True): def do_local(command, capture=True):
result = local(command, capture) result = local(command, capture)
if result.return_code != 0: if result.return_code != 0:
@ -55,11 +55,11 @@ def do_local(command, capture=True):
def shutdown(): def shutdown():
do_sudo("poweroff") do_sudo("poweroff")
time.sleep(30) time.sleep(30)
def download_if_needed(vdi_dir, xml_dir, vm_name, vm_vdi_file, vm_xml_file): def download_if_needed(vdi_dir, xml_dir, vm_name, vm_vdi_file, vm_xml_file):
if not os.path.exists(vdi_dir): if not os.path.exists(vdi_dir):
os.makedirs(vdi_dir) os.makedirs(vdi_dir)
if os.path.exists(os.path.join(vdi_dir, vm_vdi_file)): if os.path.exists(os.path.join(vdi_dir, vm_vdi_file)):
print "File %s already exists. No need to re-download" % os.path.join(vdi_dir, vm_vdi_file) print "File %s already exists. No need to re-download" % os.path.join(vdi_dir, vm_vdi_file)
else: else:
@ -67,24 +67,24 @@ def download_if_needed(vdi_dir, xml_dir, vm_name, vm_vdi_file, vm_xml_file):
tmpPath = do_local("mktemp", capture=True) tmpPath = do_local("mktemp", capture=True)
do_local("wget %s/%s/%s -O %s"%(env.vm_download_url, vm_name, vm_vdi_file, tmpPath)) do_local("wget %s/%s/%s -O %s"%(env.vm_download_url, vm_name, vm_vdi_file, tmpPath))
os.rename(tmpPath, os.path.join(vdi_dir, vm_vdi_file)) os.rename(tmpPath, os.path.join(vdi_dir, vm_vdi_file))
if os.path.exists(os.path.join(xml_dir, vm_xml_file)): if os.path.exists(os.path.join(xml_dir, vm_xml_file)):
print "File %s already exists. No need to re-download" % os.path.join(xml_dir, vm_xml_file) print "File %s already exists. No need to re-download" % os.path.join(xml_dir, vm_xml_file)
else: else:
do_local("wget %s/%s/%s -O %s"%(env.vm_download_url, vm_name, vm_xml_file, os.path.join(xml_dir, vm_xml_file))) do_local("wget %s/%s/%s -O %s"%(env.vm_download_url, vm_name, vm_xml_file, os.path.join(xml_dir, vm_xml_file)))
def create_fresh_os(vm_name, debian=False): def create_fresh_os(vm_name, debian=False):
vm_vdi_file = '%s.vdi'%vm_name vm_vdi_file = '%s.vdi'%vm_name
vm_xml_file = '%s.xml'%vm_name vm_xml_file = '%s.xml'%vm_name
vdi_dir = os.path.expanduser('~/tmp/vms/%s'%vm_name) vdi_dir = os.path.expanduser('~/tmp/vms/%s'%vm_name)
vdi_snapshot_dir = os.path.expanduser('~/tmp/vms/%s/Snapshots'%vm_name) vdi_snapshot_dir = os.path.expanduser('~/tmp/vms/%s/Snapshots'%vm_name)
xml_dir = os.path.expanduser('~/.VirtualBox') xml_dir = os.path.expanduser('~/.VirtualBox')
vm_xml_path = os.path.join(xml_dir, vm_xml_file) vm_xml_path = os.path.join(xml_dir, vm_xml_file)
download_if_needed(vdi_dir, xml_dir, vm_name, vm_vdi_file, vm_xml_file) download_if_needed(vdi_dir, xml_dir, vm_name, vm_vdi_file, vm_xml_file)
if not os.path.exists("%s/vm_registered"%vdi_dir): if not os.path.exists("%s/vm_registered"%vdi_dir):
do_local("VBoxManage registervm %s"%os.path.join(xml_dir, vm_xml_file), capture=True) do_local("VBoxManage registervm %s"%os.path.join(xml_dir, vm_xml_file), capture=True)
@ -98,7 +98,7 @@ def create_fresh_os(vm_name, debian=False):
do_local('VBoxManage modifyvm "%s" --bridgeadapter1 eth0'%vm_name) do_local('VBoxManage modifyvm "%s" --bridgeadapter1 eth0'%vm_name)
do_local('VBoxManage startvm %s'%vm_name) do_local('VBoxManage startvm %s'%vm_name)
print "Please wait while attempting to acquire IP address" print "Please wait while attempting to acquire IP address"
time.sleep(15) time.sleep(15)
try_again = True try_again = True
@ -107,16 +107,16 @@ def create_fresh_os(vm_name, debian=False):
triple = ret.partition(':') triple = ret.partition(':')
ip_addr = triple[2].strip(' \r\n') ip_addr = triple[2].strip(' \r\n')
print "Address found %s"%ip_addr print "Address found %s"%ip_addr
try_again = (len(ip_addr) == 0) try_again = (len(ip_addr) == 0)
time.sleep(1) time.sleep(1)
env.hosts.append(ip_addr) env.hosts.append(ip_addr)
env.host_string = ip_addr env.host_string = ip_addr
if debian: if debian:
append('/etc/apt/sources.list', "deb http://www.debian-multimedia.org squeeze main non-free", use_sudo=True) append('/etc/apt/sources.list', "deb http://www.debian-multimedia.org squeeze main non-free", use_sudo=True)
def ubuntu_lucid_32(fresh_os=True): def ubuntu_lucid_32(fresh_os=True):
if (fresh_os): if (fresh_os):
create_fresh_os('Ubuntu_10.04_32') create_fresh_os('Ubuntu_10.04_32')
@ -124,7 +124,7 @@ def ubuntu_lucid_32(fresh_os=True):
def ubuntu_lucid_64(fresh_os=True): def ubuntu_lucid_64(fresh_os=True):
if (fresh_os): if (fresh_os):
create_fresh_os('Ubuntu_10.04_64') create_fresh_os('Ubuntu_10.04_64')
def ubuntu_maverick_32(fresh_os=True): def ubuntu_maverick_32(fresh_os=True):
if (fresh_os): if (fresh_os):
create_fresh_os('Ubuntu_10.10_32') create_fresh_os('Ubuntu_10.10_32')
@ -136,44 +136,44 @@ def ubuntu_maverick_64(fresh_os=True):
def ubuntu_natty_32(fresh_os=True): def ubuntu_natty_32(fresh_os=True):
if (fresh_os): if (fresh_os):
create_fresh_os('Ubuntu_11.04_32') create_fresh_os('Ubuntu_11.04_32')
def ubuntu_natty_64(fresh_os=True): def ubuntu_natty_64(fresh_os=True):
if (fresh_os): if (fresh_os):
create_fresh_os('Ubuntu_11.04_64') create_fresh_os('Ubuntu_11.04_64')
def ubuntu_oneiric_32(fresh_os=True): def ubuntu_oneiric_32(fresh_os=True):
if (fresh_os): if (fresh_os):
create_fresh_os('Ubuntu_11.10_32') create_fresh_os('Ubuntu_11.10_32')
def ubuntu_oneiric_64(fresh_os=True): def ubuntu_oneiric_64(fresh_os=True):
if (fresh_os): if (fresh_os):
create_fresh_os('Ubuntu_11.10_64') create_fresh_os('Ubuntu_11.10_64')
def ubuntu_precise_64(fresh_os=True): def ubuntu_precise_64(fresh_os=True):
if (fresh_os): if (fresh_os):
create_fresh_os('Ubuntu_12.04_64') create_fresh_os('Ubuntu_12.04_64')
def ubuntu_precise_32(fresh_os=True): def ubuntu_precise_32(fresh_os=True):
if (fresh_os): if (fresh_os):
create_fresh_os('Ubuntu_12.04_32') create_fresh_os('Ubuntu_12.04_32')
def debian_squeeze_32(fresh_os=True): def debian_squeeze_32(fresh_os=True):
if (fresh_os): if (fresh_os):
create_fresh_os('Debian_Squeeze_32', debian=True) create_fresh_os('Debian_Squeeze_32', debian=True)
def debian_squeeze_64(fresh_os=True): def debian_squeeze_64(fresh_os=True):
if (fresh_os): if (fresh_os):
create_fresh_os('Debian_Squeeze_64', debian=True) create_fresh_os('Debian_Squeeze_64', debian=True)
def compile_liquidsoap(filename="liquidsoap"): def compile_liquidsoap(filename="liquidsoap"):
config = ConfigParser() config = ConfigParser()
config.readfp(open('fab_liquidsoap_compile.cfg')) config.readfp(open('fab_liquidsoap_compile.cfg'))
url = config.get('main', 'liquidsoap_tar_url') url = config.get('main', 'liquidsoap_tar_url')
print "Will get liquidsoap from " + url print "Will get liquidsoap from " + url
do_sudo('apt-get update') do_sudo('apt-get update')
do_sudo('apt-get upgrade -y --force-yes') do_sudo('apt-get upgrade -y --force-yes')
do_sudo('apt-get install -y --force-yes ocaml-findlib libao-ocaml-dev libportaudio-ocaml-dev ' + \ do_sudo('apt-get install -y --force-yes ocaml-findlib libao-ocaml-dev libportaudio-ocaml-dev ' + \
@ -181,22 +181,32 @@ def compile_liquidsoap(filename="liquidsoap"):
'libspeex-dev libspeexdsp-dev speex libladspa-ocaml-dev festival festival-dev ' + \ 'libspeex-dev libspeexdsp-dev speex libladspa-ocaml-dev festival festival-dev ' + \
'libsamplerate-dev libxmlplaylist-ocaml-dev libxmlrpc-light-ocaml-dev libflac-dev ' + \ 'libsamplerate-dev libxmlplaylist-ocaml-dev libxmlrpc-light-ocaml-dev libflac-dev ' + \
'libxml-dom-perl libxml-dom-xpath-perl patch autoconf libmp3lame-dev ' + \ 'libxml-dom-perl libxml-dom-xpath-perl patch autoconf libmp3lame-dev ' + \
'libcamomile-ocaml-dev libcamlimages-ocaml-dev libtool libpulse-dev libjack-dev camlidl') 'libcamomile-ocaml-dev libcamlimages-ocaml-dev libtool libpulse-dev libjack-dev camlidl libfaad-dev')
root = '/home/martin/src' root = '/home/martin/src'
do_run('mkdir -p %s' % root) do_run('mkdir -p %s' % root)
tmpPath = do_local("mktemp", capture=True) tmpPath = do_local("mktemp", capture=True)
do_run('wget %s -O %s' % (url, tmpPath)) do_run('wget %s -O %s' % (url, tmpPath))
do_run('mv %s %s/liquidsoap.tar.gz' % (tmpPath, root)) do_run('mv %s %s/liquidsoap.tar.gz' % (tmpPath, root))
do_run('cd %s && tar xzf liquidsoap.tar.gz' % root) do_run('cd %s && tar xzf liquidsoap.tar.gz' % root)
do_run('cd %s/liquidsoap-1.0.1-full && cp PACKAGES.minimal PACKAGES' % root) #do_run('cd %s/liquidsoap-1.0.1-full && cp PACKAGES.minimal PACKAGES' % root)
sed('%s/liquidsoap-1.0.1-full/PACKAGES' % root, '#ocaml-portaudio', 'ocaml-portaudio') #sed('%s/liquidsoap-1.0.1-full/PACKAGES' % root, '#ocaml-portaudio', 'ocaml-portaudio')
sed('%s/liquidsoap-1.0.1-full/PACKAGES' % root, '#ocaml-alsa', 'ocaml-alsa') #sed('%s/liquidsoap-1.0.1-full/PACKAGES' % root, '#ocaml-alsa', 'ocaml-alsa')
sed('%s/liquidsoap-1.0.1-full/PACKAGES' % root, '#ocaml-pulseaudio', 'ocaml-pulseaudio') #sed('%s/liquidsoap-1.0.1-full/PACKAGES' % root, '#ocaml-pulseaudio', 'ocaml-pulseaudio')
sed('%s/liquidsoap-1.0.1-full/PACKAGES' % root, '#ocaml-faad', 'ocaml-faad') #sed('%s/liquidsoap-1.0.1-full/PACKAGES' % root, '#ocaml-faad', 'ocaml-faad')
do_run('cd %s/liquidsoap-1.0.1-full && ./bootstrap' % root) #do_run('cd %s/liquidsoap-1.0.1-full && ./bootstrap' % root)
do_run('cd %s/liquidsoap-1.0.1-full && ./configure' % root) #do_run('cd %s/liquidsoap-1.0.1-full && ./configure' % root)
do_run('cd %s/liquidsoap-1.0.1-full && make' % root) #do_run('cd %s/liquidsoap-1.0.1-full && make' % root)
get('%s/liquidsoap-1.0.1-full/liquidsoap-1.0.1/src/liquidsoap' % root, filename) #get('%s/liquidsoap-1.0.1-full/liquidsoap-1.0.1/src/liquidsoap' % root, filename)
do_run('cd %s/savonet && cp PACKAGES.minimal PACKAGES' % root)
sed('%s/savonet/PACKAGES' % root, '#ocaml-portaudio', 'ocaml-portaudio')
sed('%s/savonet/PACKAGES' % root, '#ocaml-alsa', 'ocaml-alsa')
sed('%s/savonet/PACKAGES' % root, '#ocaml-pulseaudio', 'ocaml-pulseaudio')
sed('%s/savonet/PACKAGES' % root, '#ocaml-faad', 'ocaml-faad')
do_run('cd %s/savonet && ./bootstrap' % root)
do_run('cd %s/savonet && ./configure' % root)
do_run('cd %s/savonet && make' % root)
get('%s/savonet/liquidsoap/src/liquidsoap' % root, filename)