CC-3395: Play preview for playlists and timelines for shows should show a list under the pop-up player which will play the entire playlist.

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

Conflicts:
	airtime_mvc/application/controllers/LibraryController.php
	airtime_mvc/public/js/airtime/library/library.js
This commit is contained in:
Daniel 2012-03-12 10:23:50 -04:00
commit d713f830cd
61 changed files with 5112 additions and 200 deletions

View File

@ -26,6 +26,7 @@ $ccAcl->add(new Zend_Acl_Resource('library'))
->add(new Zend_Acl_Resource('recorder')) ->add(new Zend_Acl_Resource('recorder'))
->add(new Zend_Acl_Resource('showbuilder')) ->add(new Zend_Acl_Resource('showbuilder'))
->add(new Zend_Acl_Resource('auth')) ->add(new Zend_Acl_Resource('auth'))
->add(new Zend_Acl_Resource('playouthistory'))
->add(new Zend_Acl_Resource('usersettings')); ->add(new Zend_Acl_Resource('usersettings'));
/** Creating permissions */ /** Creating permissions */
@ -44,6 +45,7 @@ $ccAcl->allow('G', 'index')
->allow('H', 'search') ->allow('H', 'search')
->allow('H', 'playlist') ->allow('H', 'playlist')
->allow('H', 'showbuilder') ->allow('H', 'showbuilder')
->allow('A', 'playouthistory')
->allow('A', 'user') ->allow('A', 'user')
->allow('A', 'systemstatus') ->allow('A', 'systemstatus')
->allow('A', 'preference'); ->allow('A', 'preference');

View File

@ -11,9 +11,9 @@ $pages = array(
array( array(
'label' => 'Now Playing', 'label' => 'Now Playing',
'module' => 'default', 'module' => 'default',
'controller' => 'Nowplaying', 'controller' => 'Showbuilder',
'action' => 'index', 'action' => 'index',
'resource' => 'nowplaying' 'resource' => 'showbuilder'
), ),
array( array(
'label' => 'Add Media', 'label' => 'Add Media',
@ -29,13 +29,6 @@ $pages = array(
'action' => 'index', 'action' => 'index',
'resource' => 'library' 'resource' => 'library'
), ),
array(
'label' => 'Airtimeline',
'module' => 'default',
'controller' => 'Showbuilder',
'action' => 'index',
'resource' => 'showbuilder'
),
array( array(
'label' => 'Calendar', 'label' => 'Calendar',
'module' => 'default', 'module' => 'default',
@ -85,7 +78,14 @@ $pages = array(
'controller' => 'systemstatus', 'controller' => 'systemstatus',
'action' => 'index', 'action' => 'index',
'resource' => 'systemstatus' 'resource' => 'systemstatus'
) ),
array(
'label' => 'Playout History',
'module' => 'default',
'controller' => 'playouthistory',
'action' => 'index',
'resource' => 'playouthistory'
)
) )
), ),
array( array(

View File

@ -29,9 +29,15 @@ class LibraryController extends Zend_Controller_Action
public function indexAction() { public function indexAction() {
global $CC_CONFIG;
$this->_helper->layout->setLayout('library'); $this->_helper->layout->setLayout('library');
$request = $this->getRequest();
$baseUrl = $request->getBaseUrl();
$this->view->headScript()->appendFile($this->view->baseUrl('/js/airtime/library/events/library_playlistbuilder.js'),'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/main_library.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->_helper->actionStack('library', 'library'); $this->_helper->actionStack('library', 'library');
$this->_helper->actionStack('index', 'playlist'); $this->_helper->actionStack('index', 'playlist');
@ -56,9 +62,10 @@ class LibraryController extends Zend_Controller_Action
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.TableTools.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.TableTools.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/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/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($baseUrl.'/js/airtime/library/main_library.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/airtime/library/main_library.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']);
$this->view->headLink()->appendStylesheet($baseUrl.'/css/datatables/css/ColVis.css?'.$CC_CONFIG['airtime_version']); $this->view->headLink()->appendStylesheet($baseUrl.'/css/datatables/css/ColVis.css?'.$CC_CONFIG['airtime_version']);

View File

@ -68,7 +68,7 @@ class LoginController extends Zend_Controller_Action
$tempSess = new Zend_Session_Namespace("referrer"); $tempSess = new Zend_Session_Namespace("referrer");
$tempSess->referrer = 'login'; $tempSess->referrer = 'login';
$this->_redirect('Nowplaying'); $this->_redirect('Showbuilder');
} }
else else
{ {
@ -95,7 +95,7 @@ class LoginController extends Zend_Controller_Action
public function logoutAction() public function logoutAction()
{ {
Zend_Auth::getInstance()->clearIdentity(); Zend_Auth::getInstance()->clearIdentity();
$this->_redirect('login/index'); $this->_redirect('showbuilder/index');
} }
} }

View File

@ -0,0 +1,87 @@
<?php
class PlayoutHistoryController extends Zend_Controller_Action
{
public function init()
{
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext
->addActionContext('playout-history-feed', 'json')
->initContext();
}
public function indexAction()
{
global $CC_CONFIG;
$this->_helper->layout->setLayout('playouthistory');
$request = $this->getRequest();
$baseUrl = $request->getBaseUrl();
//default time is the last 24 hours.
$now = time();
$from = $request->getParam("from", $now - (24*60*60));
$to = $request->getParam("to", $now);
$start = DateTime::createFromFormat("U", $from, new DateTimeZone("UTC"));
$start->setTimezone(new DateTimeZone(date_default_timezone_get()));
$end = DateTime::createFromFormat("U", $to, new DateTimeZone("UTC"));
$end->setTimezone(new DateTimeZone(date_default_timezone_get()));
$form = new Application_Form_DateRange();
$form->populate(array(
'his_date_start' => $start->format("Y-m-d"),
'his_time_start' => $start->format("H:i"),
'his_date_end' => $end->format("Y-m-d"),
'his_time_end' => $end->format("H:i")
));
$this->view->date_form = $form;
$this->view->headScript()->appendFile($baseUrl.'/js/contextmenu/jquery.contextMenu.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/js/jquery.dataTables.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.pluginAPI.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.fnSetFilteringDelay.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/TableTools/js/ZeroClipboard.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/TableTools/js/TableTools.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$offset = date("Z") * -1;
$this->view->headScript()->appendScript("var serverTimezoneOffset = {$offset}; //in seconds");
$this->view->headScript()->appendFile($baseUrl.'/js/timepicker/jquery.ui.timepicker.js','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/playouthistory/historytable.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headLink()->appendStylesheet($baseUrl.'/js/datatables/plugin/TableTools/css/TableTools.css?'.$CC_CONFIG['airtime_version']);
//$this->view->headLink()->appendStylesheet($baseUrl.'/js/datatables/plugin/TableTools/css/TableTools_JUI.css?'.$CC_CONFIG['airtime_version']);
$this->view->headLink()->appendStylesheet($baseUrl.'/css/jquery.ui.timepicker.css');
}
public function playoutHistoryFeedAction()
{
$request = $this->getRequest();
$current_time = time();
$params = $request->getParams();
$starts_epoch = $request->getParam("start", $current_time - (60*60*24));
$ends_epoch = $request->getParam("end", $current_time);
$startsDT = DateTime::createFromFormat("U", $starts_epoch, new DateTimeZone("UTC"));
$endsDT = DateTime::createFromFormat("U", $ends_epoch, new DateTimeZone("UTC"));
Logging::log("history starts {$startsDT->format("Y-m-d H:i:s")}");
Logging::log("history ends {$endsDT->format("Y-m-d H:i:s")}");
$history = new Application_Model_PlayoutHistory($startsDT, $endsDT, $params);
$r = $history->getItems();
$this->view->sEcho = $r["sEcho"];
$this->view->iTotalDisplayRecords = $r["iTotalDisplayRecords"];
$this->view->iTotalRecords = $r["iTotalRecords"];
$this->view->history = $r["history"];
}
}

View File

@ -10,6 +10,7 @@ class ShowbuilderController extends Zend_Controller_Action
->addActionContext('schedule-add', 'json') ->addActionContext('schedule-add', 'json')
->addActionContext('schedule-remove', 'json') ->addActionContext('schedule-remove', 'json')
->addActionContext('builder-dialog', 'json') ->addActionContext('builder-dialog', 'json')
->addActionContext('check-builder-feed', 'json')
->addActionContext('builder-feed', 'json') ->addActionContext('builder-feed', 'json')
->initContext(); ->initContext();
} }
@ -17,10 +18,80 @@ class ShowbuilderController extends Zend_Controller_Action
public function indexAction() { public function indexAction() {
$this->_helper->layout->setLayout('builder'); $this->_helper->layout->setLayout('builder');
$this->_helper->viewRenderer->setResponseSegment('dialog');
$this->view->headScript()->appendFile($this->view->baseUrl('/js/airtime/library/events/library_showbuilder.js'),'text/javascript');
$this->_helper->actionStack('library', 'library'); global $CC_CONFIG;
$request = $this->getRequest();
$baseUrl = $request->getBaseUrl();
$this->view->headScript()->appendFile($this->view->baseUrl('/js/airtime/library/events/library_showbuilder.js?'.$CC_CONFIG['airtime_version']),'text/javascript');
$refer_sses = new Zend_Session_Namespace('referrer');
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
if ($request->isPost()) {
$form = new Application_Form_RegisterAirtime();
$values = $request->getPost();
if ($values["Publicise"] != 1 && $form->isValid($values)) {
Application_Model_Preference::SetSupportFeedback($values["SupportFeedback"]);
if (isset($values["Privacy"])) {
Application_Model_Preference::SetPrivacyPolicyCheck($values["Privacy"]);
}
// unset session
Zend_Session::namespaceUnset('referrer');
}
else if ($values["Publicise"] == '1' && $form->isValid($values)) {
Application_Model_Preference::SetHeadTitle($values["stnName"], $this->view);
Application_Model_Preference::SetPhone($values["Phone"]);
Application_Model_Preference::SetEmail($values["Email"]);
Application_Model_Preference::SetStationWebSite($values["StationWebSite"]);
Application_Model_Preference::SetPublicise($values["Publicise"]);
$form->Logo->receive();
$imagePath = $form->Logo->getFileName();
Application_Model_Preference::SetStationCountry($values["Country"]);
Application_Model_Preference::SetStationCity($values["City"]);
Application_Model_Preference::SetStationDescription($values["Description"]);
Application_Model_Preference::SetStationLogo($imagePath);
Application_Model_Preference::SetSupportFeedback($values["SupportFeedback"]);
if (isset($values["Privacy"])){
Application_Model_Preference::SetPrivacyPolicyCheck($values["Privacy"]);
}
// unset session
Zend_Session::namespaceUnset('referrer');
}
else {
$logo = Application_Model_Preference::GetStationLogo();
if ($logo) {
$this->view->logoImg = $logo;
}
$this->view->dialog = $form;
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/nowplaying/register.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
}
}
else {
//popup if previous page was login
if ($refer_sses->referrer == 'login' && Application_Model_Nowplaying::ShouldShowPopUp()
&& !Application_Model_Preference::GetSupportFeedback() && $user->isAdmin()){
$form = new Application_Form_RegisterAirtime();
$logo = Application_Model_Preference::GetStationLogo();
if ($logo) {
$this->view->logoImg = $logo;
}
$this->view->dialog = $form;
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/nowplaying/register.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
}
}
$this->_helper->actionStack('library', 'library');
$this->_helper->actionStack('builder', 'showbuilder'); $this->_helper->actionStack('builder', 'showbuilder');
} }
@ -33,7 +104,7 @@ class ShowbuilderController extends Zend_Controller_Action
$now = time(); $now = time();
$from = $request->getParam("from", $now); $from = $request->getParam("from", $now);
$to = $request->getParam("to", $now+(24*60*60)); $to = $request->getParam("to", $now + (24*60*60));
$start = DateTime::createFromFormat("U", $from, new DateTimeZone("UTC")); $start = DateTime::createFromFormat("U", $from, new DateTimeZone("UTC"));
$start->setTimezone(new DateTimeZone(date_default_timezone_get())); $start->setTimezone(new DateTimeZone(date_default_timezone_get()));
@ -52,12 +123,12 @@ class ShowbuilderController extends Zend_Controller_Action
$offset = date("Z") * -1; $offset = date("Z") * -1;
$this->view->headScript()->appendScript("var serverTimezoneOffset = {$offset}; //in seconds"); $this->view->headScript()->appendScript("var serverTimezoneOffset = {$offset}; //in seconds");
$this->view->headScript()->appendFile($baseUrl.'/js/timepicker/jquery.ui.timepicker.js','text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/timepicker/jquery.ui.timepicker.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/showbuilder/builder.js','text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/airtime/showbuilder/builder.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/showbuilder/main_builder.js','text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/airtime/showbuilder/main_builder.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headLink()->appendStylesheet($baseUrl.'/css/jquery.ui.timepicker.css'); $this->view->headLink()->appendStylesheet($baseUrl.'/css/jquery.ui.timepicker.css?'.$CC_CONFIG['airtime_version']);
$this->view->headLink()->appendStylesheet($baseUrl.'/css/showbuilder.css'); $this->view->headLink()->appendStylesheet($baseUrl.'/css/showbuilder.css?'.$CC_CONFIG['airtime_version']);
} }
public function builderDialogAction() { public function builderDialogAction() {
@ -88,6 +159,37 @@ class ShowbuilderController extends Zend_Controller_Action
$this->view->dialog = $this->view->render('showbuilder/builderDialog.phtml'); $this->view->dialog = $this->view->render('showbuilder/builderDialog.phtml');
} }
public function checkBuilderFeedAction() {
$request = $this->getRequest();
$current_time = time();
$starts_epoch = $request->getParam("start", $current_time);
//default ends is 24 hours after starts.
$ends_epoch = $request->getParam("end", $current_time + (60*60*24));
$show_filter = intval($request->getParam("showFilter", 0));
$my_shows = intval($request->getParam("myShows", 0));
$timestamp = intval($request->getParam("timestamp", -1));
$startsDT = DateTime::createFromFormat("U", $starts_epoch, new DateTimeZone("UTC"));
$endsDT = DateTime::createFromFormat("U", $ends_epoch, new DateTimeZone("UTC"));
Logging::log("showbuilder starts {$startsDT->format("Y-m-d H:i:s")}");
Logging::log("showbuilder ends {$endsDT->format("Y-m-d H:i:s")}");
$opts = array("myShows" => $my_shows, "showFilter" => $show_filter);
$showBuilder = new Application_Model_ShowBuilder($startsDT, $endsDT, $opts);
//only send the schedule back if updates have been made.
// -1 default will always call the schedule to be sent back if no timestamp is defined.
if ($showBuilder->hasBeenUpdatedSince($timestamp)) {
$this->view->update = true;
}
else {
$this->view->update = false;
}
}
public function builderFeedAction() { public function builderFeedAction() {
$request = $this->getRequest(); $request = $this->getRequest();
@ -98,6 +200,7 @@ class ShowbuilderController extends Zend_Controller_Action
$ends_epoch = $request->getParam("end", $current_time + (60*60*24)); $ends_epoch = $request->getParam("end", $current_time + (60*60*24));
$show_filter = intval($request->getParam("showFilter", 0)); $show_filter = intval($request->getParam("showFilter", 0));
$my_shows = intval($request->getParam("myShows", 0)); $my_shows = intval($request->getParam("myShows", 0));
$timestamp = intval($request->getParam("timestamp", -1));
$startsDT = DateTime::createFromFormat("U", $starts_epoch, new DateTimeZone("UTC")); $startsDT = DateTime::createFromFormat("U", $starts_epoch, new DateTimeZone("UTC"));
$endsDT = DateTime::createFromFormat("U", $ends_epoch, new DateTimeZone("UTC")); $endsDT = DateTime::createFromFormat("U", $ends_epoch, new DateTimeZone("UTC"));
@ -109,6 +212,7 @@ class ShowbuilderController extends Zend_Controller_Action
$showBuilder = new Application_Model_ShowBuilder($startsDT, $endsDT, $opts); $showBuilder = new Application_Model_ShowBuilder($startsDT, $endsDT, $opts);
$this->view->schedule = $showBuilder->GetItems(); $this->view->schedule = $showBuilder->GetItems();
$this->view->timestamp = $current_time;
} }
public function scheduleAddAction() { public function scheduleAddAction() {

View File

@ -0,0 +1,68 @@
<?php
class Application_Form_DateRange extends Zend_Form_SubForm
{
public function init()
{
$this->setDecorators(array(
array('ViewScript', array('viewScript' => 'form/daterange.phtml'))
));
// Add start date element
$startDate = new Zend_Form_Element_Text('his_date_start');
$startDate->class = 'input_text';
$startDate->setRequired(true)
->setLabel('Date Start:')
->setValue(date("Y-m-d"))
->setFilters(array('StringTrim'))
->setValidators(array(
'NotEmpty',
array('date', false, array('YYYY-MM-DD'))))
->setDecorators(array('ViewHelper'));
$startDate->setAttrib('alt', 'date');
$this->addElement($startDate);
// Add start time element
$startTime = new Zend_Form_Element_Text('his_time_start');
$startTime->class = 'input_text';
$startTime->setRequired(true)
->setValue('00:00')
->setFilters(array('StringTrim'))
->setValidators(array(
'NotEmpty',
array('date', false, array('HH:mm')),
array('regex', false, array('/^[0-9:]+$/', 'messages' => 'Invalid character entered'))))
->setDecorators(array('ViewHelper'));
$startTime->setAttrib('alt', 'time');
$this->addElement($startTime);
// Add end date element
$endDate = new Zend_Form_Element_Text('his_date_end');
$endDate->class = 'input_text';
$endDate->setRequired(true)
->setLabel('Date End:')
->setValue(date("Y-m-d"))
->setFilters(array('StringTrim'))
->setValidators(array(
'NotEmpty',
array('date', false, array('YYYY-MM-DD'))))
->setDecorators(array('ViewHelper'));
$endDate->setAttrib('alt', 'date');
$this->addElement($endDate);
// Add end time element
$endTime = new Zend_Form_Element_Text('his_time_end');
$endTime->class = 'input_text';
$endTime->setRequired(true)
->setValue('01:00')
->setFilters(array('StringTrim'))
->setValidators(array(
'NotEmpty',
array('date', false, array('HH:mm')),
array('regex', false, array('/^[0-9:]+$/', 'messages' => 'Invalid character entered'))))
->setDecorators(array('ViewHelper'));
$endTime->setAttrib('alt', 'time');
$this->addElement($endTime);
}
}

View File

@ -11,6 +11,12 @@ class Application_Form_ShowBuilder extends Zend_Form_SubForm
array('ViewScript', array('viewScript' => 'form/showbuilder.phtml')) array('ViewScript', array('viewScript' => 'form/showbuilder.phtml'))
)); ));
//set value to -1 originally to ensure we grab the schedule on first call.
$timestamp = new Zend_Form_Element_Hidden('sb_timestamp');
$timestamp->setValue(-1)
->setDecorators(array('ViewHelper'));
$this->addElement($timestamp);
// Add start date element // Add start date element
$startDate = new Zend_Form_Element_Text('sb_date_start'); $startDate = new Zend_Form_Element_Text('sb_date_start');
$startDate->class = 'input_text'; $startDate->class = 'input_text';

View File

@ -23,5 +23,8 @@
<div id="library_content" class="tabs ui-widget ui-widget-content block-shadow alpha-block padded" style="display:none"><?php echo $this->layout()->library ?></div> <div id="library_content" class="tabs ui-widget ui-widget-content block-shadow alpha-block padded" style="display:none"><?php echo $this->layout()->library ?></div>
<div id="show_builder" class="ui-widget ui-widget-content block-shadow omega-block padded"><?php echo $this->layout()->builder ?></div> <div id="show_builder" class="ui-widget ui-widget-content block-shadow omega-block padded"><?php echo $this->layout()->builder ?></div>
</div> </div>
<?php echo $this->layout()->dialog ?>
</body> </body>
</html> </html>

View File

@ -23,7 +23,7 @@
<div class="wrapper"> <div class="wrapper">
<!--Set to z-index 254 to make it lower than the top-panel and the ZFDebug info bar, but higher than the side-playlist--> <!--Set to z-index 254 to make it lower than the top-panel and the ZFDebug info bar, but higher than the side-playlist-->
<div id="library_content" class="ui-widget ui-widget-content block-shadow alpha-block padded" style="z-index:254"><?php echo $this->layout()->library ?></div> <div id="library_content" class="ui-widget ui-widget-content block-shadow alpha-block padded" style="z-index:254"><?php echo $this->layout()->library ?></div>
<div id="side_playlist" class="ui-widget ui-widget-content block-shadow omega-block"><?php echo $this->layout()->spl ?></div> <div id="side_playlist" class="ui-widget ui-widget-content block-shadow omega-block padded"><?php echo $this->layout()->spl ?></div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -0,0 +1,27 @@
<?php echo $this->doctype() ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php echo $this->headTitle() ?>
<?php echo $this->headScript() ?>
<?php echo $this->headLink() ?>
<?php echo isset($this->google_analytics)?$this->google_analytics:"" ?>
</head>
<body>
<div id="Panel">
<div class="logo"></div>
<?php echo $this->versionNotify() ?>
<?php echo $this->partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?>
<?php $partial = array('menu.phtml', 'default');
$this->navigation()->menu()->setPartial($partial); ?>
<?php echo $this->navigation()->menu() ?>
</div>
<div class="wrapper">
<div id="history_content" class="ui-widget ui-widget-content block-shadow alpha-block padded"><?php echo $this->layout()->content ?></div>
</div>
</body>
</html>

View File

@ -0,0 +1,109 @@
<?php
class Application_Model_Datatables {
/*
* query used to return data for a paginated/searchable datatable.
*/
public static function findEntries($con, $displayColumns, $fromTable, $data, $dataProp = "aaData")
{
$where = array();
if ($data["sSearch"] !== "") {
$searchTerms = explode(" ", $data["sSearch"]);
}
$selectorCount = "SELECT COUNT(*) ";
$selectorRows = "SELECT ".join(",", $displayColumns)." ";
$sql = $selectorCount." FROM ".$fromTable;
$sqlTotalRows = $sql;
if (isset($searchTerms)) {
$searchCols = array();
for ($i = 0; $i < $data["iColumns"]; $i++) {
if ($data["bSearchable_".$i] == "true") {
$searchCols[] = $data["mDataProp_{$i}"];
}
}
$outerCond = array();
foreach ($searchTerms as $term) {
$innerCond = array();
foreach ($searchCols as $col) {
$escapedTerm = pg_escape_string($term);
$innerCond[] = "{$col}::text ILIKE '%{$escapedTerm}%'";
}
$outerCond[] = "(".join(" OR ", $innerCond).")";
}
$where[] = "(".join(" AND ", $outerCond).")";
}
// End Where clause
// Order By clause
$orderby = array();
for ($i = 0; $i < $data["iSortingCols"]; $i++){
$num = $data["iSortCol_".$i];
$orderby[] = $data["mDataProp_{$num}"]." ".$data["sSortDir_".$i];
}
$orderby[] = "id";
$orderby = join("," , $orderby);
// End Order By clause
$displayLength = intval($data["iDisplayLength"]);
if (count($where) > 0) {
$where = join(" AND ", $where);
$sql = $selectorCount." FROM ".$fromTable." WHERE ".$where;
$sqlTotalDisplayRows = $sql;
$sql = $selectorRows." FROM ".$fromTable." WHERE ".$where." ORDER BY ".$orderby;
//limit the results returned.
if ($displayLength !== -1) {
$sql .= " OFFSET ".$data["iDisplayStart"]." LIMIT ".$displayLength;
}
}
else {
$sql = $selectorRows." FROM ".$fromTable." ORDER BY ".$orderby;
//limit the results returned.
if ($displayLength !== -1) {
$sql .= " OFFSET ".$data["iDisplayStart"]." LIMIT ".$displayLength;
}
}
try {
$r = $con->query($sqlTotalRows);
Logging::log($sqlTotalRows);
$totalRows = $r->fetchColumn(0);
if (isset($sqlTotalDisplayRows)) {
$r = $con->query($sqlTotalDisplayRows);
Logging::log($sqlTotalDisplayRows);
$totalDisplayRows = $r->fetchColumn(0);
}
else {
$totalDisplayRows = $totalRows;
}
$r = $con->query($sql);
$r->setFetchMode(PDO::FETCH_ASSOC);
$results = $r->fetchAll();
}
catch (Exception $e) {
Logging::log($e->getMessage());
}
//display sql executed in airtime log for testing
Logging::log($sql);
return array(
"sEcho" => intval($data["sEcho"]),
"iTotalDisplayRecords" => intval($totalDisplayRows),
"iTotalRecords" => intval($totalRows),
$dataProp => $results
);
}
}

View File

@ -0,0 +1,82 @@
<?php
require_once 'formatters/LengthFormatter.php';
class Application_Model_PlayoutHistory {
private $con;
private $timezone;
//in UTC timezone
private $startDT;
//in UTC timezone
private $endDT;
private $epoch_now;
private $opts;
private $mDataPropMap = array(
"artist" => "file.artist_name",
"title" => "file.track_title",
"played" => "playout.played",
"length" => "file.length",
"composer" => "file.composer",
"copyright" => "file.copyright",
);
public function __construct($p_startDT, $p_endDT, $p_opts) {
$this->con = Propel::getConnection(CcSchedulePeer::DATABASE_NAME);
$this->startDT = $p_startDT;
$this->endDT = $p_endDT;
$this->timezone = date_default_timezone_get();
$this->epoch_now = time();
$this->opts = $p_opts;
}
/*
* map front end mDataProp labels to proper column names for searching etc.
*/
private function translateColumns() {
for ($i = 0; $i < $this->opts["iColumns"]; $i++){
$this->opts["mDataProp_{$i}"] = $this->mDataPropMap[$this->opts["mDataProp_{$i}"]];
}
}
public function getItems() {
$this->translateColumns();
$select = array(
"file.track_title as title",
"file.artist_name as artist",
"playout.played",
"playout.file_id",
"file.composer",
"file.copyright",
"file.length"
);
$start = $this->startDT->format("Y-m-d H:i:s");
$end = $this->endDT->format("Y-m-d H:i:s");
$historyTable = "(
select count(schedule.file_id) as played, schedule.file_id as file_id
from cc_schedule as schedule
where schedule.starts >= '{$start}' and schedule.starts < '{$end}'
group by schedule.file_id
)
AS playout left join cc_files as file on (file.id = playout.file_id)";
$results = Application_Model_Datatables::findEntries($this->con, $select, $historyTable, $this->opts, "history");
foreach ($results["history"] as &$row) {
$formatter = new LengthFormatter($row['length']);
$row['length'] = $formatter->format();
}
return $results;
}
}

View File

@ -162,7 +162,7 @@ class Application_Model_Show {
->find($con); ->find($con);
foreach ($instances as $instance) { foreach ($instances as $instance) {
$instance->updateScheduleStatus(); $instance->updateScheduleStatus($con);
} }
$con->commit(); $con->commit();
@ -1448,7 +1448,8 @@ class Application_Model_Show {
} }
$sql = "SELECT starts, ends, record, rebroadcast, instance_id, show_id, name, $sql = "SELECT starts, ends, record, rebroadcast, instance_id, show_id, name,
color, background_color, file_id, cc_show_instances.id AS instance_id color, background_color, file_id, cc_show_instances.id AS instance_id,
last_scheduled
FROM cc_show_instances FROM cc_show_instances
LEFT JOIN cc_show ON cc_show.id = cc_show_instances.show_id LEFT JOIN cc_show ON cc_show.id = cc_show_instances.show_id
WHERE cc_show_instances.modified_instance = FALSE"; WHERE cc_show_instances.modified_instance = FALSE";
@ -1479,6 +1480,9 @@ class Application_Model_Show {
$sql = $sql." AND ({$exclude})"; $sql = $sql." AND ({$exclude})";
} }
//Logging::log("getShows");
//Logging::log($sql);
return $CC_DBC->GetAll($sql); return $CC_DBC->GetAll($sql);
} }

View File

@ -6,13 +6,19 @@ require_once 'formatters/TimeFilledFormatter.php';
class Application_Model_ShowBuilder { class Application_Model_ShowBuilder {
private $timezone; private $timezone;
//in UTC timezone
private $startDT; private $startDT;
//in UTC timezone
private $endDT; private $endDT;
private $user; private $user;
private $opts; private $opts;
private $contentDT; private $contentDT;
private $epoch_now; private $epoch_now;
private $hasCurrent;
private $defaultRowArray = array( private $defaultRowArray = array(
"header" => false, "header" => false,
@ -47,6 +53,8 @@ class Application_Model_ShowBuilder {
$this->user = Application_Model_User::GetCurrentUser(); $this->user = Application_Model_User::GetCurrentUser();
$this->opts = $p_opts; $this->opts = $p_opts;
$this->epoch_now = time(); $this->epoch_now = time();
$this->hasCurrent = false;
} }
//check to see if this row should be editable. //check to see if this row should be editable.
@ -59,12 +67,12 @@ class Application_Model_ShowBuilder {
$showStartDT = new DateTime($p_item["si_starts"], new DateTimeZone("UTC")); $showStartDT = new DateTime($p_item["si_starts"], new DateTimeZone("UTC"));
$schedStartDT = new DateTime($p_item["sched_starts"], new DateTimeZone("UTC")); $schedStartDT = new DateTime($p_item["sched_starts"], new DateTimeZone("UTC"));
$showStartEpoch = intval($showStartDT->format('U')); $showStartEpoch = intval($showStartDT->format('U'));
$schedStartEpoch = intval($schedStartDT->format('U')); $schedStartEpoch = intval($schedStartDT->format('U'));
//can only schedule the show if item hasn't started and you are allowed. //can only schedule the show if item hasn't started and you are allowed.
if ($this->epoch_now < max($showStartEpoch, $schedStartEpoch) if ($this->epoch_now < max($showStartEpoch, $schedStartEpoch)
&& $this->user->canSchedule($p_item["show_id"]) == true) { && $this->user->canSchedule($p_item["show_id"]) == true) {
$row["allowed"] = true; $row["allowed"] = true;
} }
@ -89,11 +97,13 @@ class Application_Model_ShowBuilder {
} }
private function isCurrent($p_epochItemStart, $p_epochItemEnd, &$row) { private function isCurrent($p_epochItemStart, $p_epochItemEnd, &$row) {
if ($this->epoch_now >= $p_epochItemStart && $this->epoch_now < $p_epochItemEnd) { if ($this->epoch_now >= $p_epochItemStart && $this->epoch_now < $p_epochItemEnd) {
$row["current"] = true; $row["current"] = true;
//how many seconds the view should wait to redraw itself. //how many seconds the view should wait to redraw itself.
$row["refresh"] = $p_epochItemEnd - $this->epoch_now; $row["refresh"] = $p_epochItemEnd - $this->epoch_now;
$this->hasCurrent = true;
} }
} }
@ -111,6 +121,7 @@ class Application_Model_ShowBuilder {
$row["header"] = true; $row["header"] = true;
$row["starts"] = $showStartDT->format("Y-m-d H:i"); $row["starts"] = $showStartDT->format("Y-m-d H:i");
$row["timeUntil"] = intval($showStartDT->format("U")) - $this->epoch_now;
$row["ends"] = $showEndDT->format("Y-m-d H:i"); $row["ends"] = $showEndDT->format("Y-m-d H:i");
$row["duration"] = $showEndDT->format("U") - $showStartDT->format("U"); $row["duration"] = $showEndDT->format("U") - $showStartDT->format("U");
$row["title"] = $p_item["show_name"]; $row["title"] = $p_item["show_name"];
@ -194,6 +205,39 @@ class Application_Model_ShowBuilder {
return $row; return $row;
} }
/*
* @param int $timestamp Unix timestamp in seconds.
*
* @return boolean whether the schedule in the show builder's range has been updated.
*
*/
public function hasBeenUpdatedSince($timestamp) {
$outdated = false;
Logging::log("checking if show builder has been updated since {$timestamp}");
$shows = Application_Model_Show::getShows($this->startDT, $this->endDT);
foreach ($shows as $show) {
if (isset($show["last_scheduled"])) {
$dt = new DateTime($show["last_scheduled"], new DateTimeZone("UTC"));
//check if any of the shows have a more recent timestamp.
if ($timestamp < intval($dt->format("U"))) {
$outdated = true;
break;
}
}
}
if (count($shows) == 0) {
$outdated = true;
}
return $outdated;
}
public function GetItems() { public function GetItems() {
$current_id = -1; $current_id = -1;
@ -229,7 +273,7 @@ class Application_Model_ShowBuilder {
//pass in the previous row as it's the last row for the previous show. //pass in the previous row as it's the last row for the previous show.
$display_items[] = $this->makeFooterRow($scheduled_items[$i-1]); $display_items[] = $this->makeFooterRow($scheduled_items[$i-1]);
} }
$display_items[] = $this->makeHeaderRow($item); $display_items[] = $this->makeHeaderRow($item);
$current_id = $item["si_id"]; $current_id = $item["si_id"];
@ -247,6 +291,10 @@ class Application_Model_ShowBuilder {
if (count($scheduled_items) > 0) { if (count($scheduled_items) > 0) {
$display_items[] = $this->makeFooterRow($scheduled_items[count($scheduled_items)-1]); $display_items[] = $this->makeFooterRow($scheduled_items[count($scheduled_items)-1]);
} }
if (!$this->hasCurrent) {
}
return $display_items; return $display_items;
} }

View File

@ -395,7 +395,7 @@ class Application_Model_StoredFile {
} }
private function constructGetFileUrl($p_serverName, $p_serverPort){ private function constructGetFileUrl($p_serverName, $p_serverPort){
Logging::log("getting media! - 2"); Logging::log("getting media! - 2");
return "http://$p_serverName:$p_serverPort/api/get-media/file/".$this->getGunId().".".$this->getFileExtension(); return "http://$p_serverName:$p_serverPort/api/get-media/file/".$this->getGunId().".".$this->getFileExtension();
} }
@ -660,7 +660,7 @@ Logging::log("getting media! - 2");
if($type == "au"){//&& isset( $audioResults )) { if($type == "au"){//&& isset( $audioResults )) {
$row['audioFile'] = $row['gunid'].".".pathinfo($row['filepath'], PATHINFO_EXTENSION); $row['audioFile'] = $row['gunid'].".".pathinfo($row['filepath'], PATHINFO_EXTENSION);
$row['image'] = '<div class="big_play"><img src="/css/images/icon_audioclip.png"></div>'; $row['image'] = '<img src="/css/images/icon_audioclip.png">';
} }
else { else {
$row['image'] = '<img src="/css/images/icon_playlist.png">'; $row['image'] = '<img src="/css/images/icon_playlist.png">';
@ -669,22 +669,22 @@ Logging::log("getting media! - 2");
return $results; return $results;
} }
public static function searchFiles($displayColumns, $fromTable, $data) public static function searchFiles($displayColumns, $fromTable, $data)
{ {
$con = Propel::getConnection(CcFilesPeer::DATABASE_NAME); $con = Propel::getConnection(CcFilesPeer::DATABASE_NAME);
$where = array(); $where = array();
if ($data["sSearch"] !== "") { if ($data["sSearch"] !== "") {
$searchTerms = explode(" ", $data["sSearch"]); $searchTerms = explode(" ", $data["sSearch"]);
} }
$selectorCount = "SELECT COUNT(*) "; $selectorCount = "SELECT COUNT(*) ";
$selectorRows = "SELECT ".join(",", $displayColumns)." "; $selectorRows = "SELECT ".join(",", $displayColumns)." ";
$sql = $selectorCount." FROM ".$fromTable; $sql = $selectorCount." FROM ".$fromTable;
$sqlTotalRows = $sql; $sqlTotalRows = $sql;
if (isset($searchTerms)) { if (isset($searchTerms)) {
$searchCols = array(); $searchCols = array();
for ($i = 0; $i < $data["iColumns"]; $i++) { for ($i = 0; $i < $data["iColumns"]; $i++) {
@ -692,12 +692,12 @@ Logging::log("getting media! - 2");
$searchCols[] = $data["mDataProp_{$i}"]; $searchCols[] = $data["mDataProp_{$i}"];
} }
} }
$outerCond = array(); $outerCond = array();
foreach ($searchTerms as $term) { foreach ($searchTerms as $term) {
$innerCond = array(); $innerCond = array();
foreach ($searchCols as $col) { foreach ($searchCols as $col) {
$escapedTerm = pg_escape_string($term); $escapedTerm = pg_escape_string($term);
$innerCond[] = "{$col}::text ILIKE '%{$escapedTerm}%'"; $innerCond[] = "{$col}::text ILIKE '%{$escapedTerm}%'";
@ -707,7 +707,7 @@ Logging::log("getting media! - 2");
$where[] = "(".join(" AND ", $outerCond).")"; $where[] = "(".join(" AND ", $outerCond).")";
} }
// End Where clause // End Where clause
// Order By clause // Order By clause
$orderby = array(); $orderby = array();
for ($i = 0; $i < $data["iSortingCols"]; $i++){ for ($i = 0; $i < $data["iSortingCols"]; $i++){
@ -717,22 +717,22 @@ Logging::log("getting media! - 2");
$orderby[] = "id"; $orderby[] = "id";
$orderby = join("," , $orderby); $orderby = join("," , $orderby);
// End Order By clause // End Order By clause
if (count($where) > 0) { if (count($where) > 0) {
$where = join(" AND ", $where); $where = join(" AND ", $where);
$sql = $selectorCount." FROM ".$fromTable." WHERE ".$where; $sql = $selectorCount." FROM ".$fromTable." WHERE ".$where;
$sqlTotalDisplayRows = $sql; $sqlTotalDisplayRows = $sql;
$sql = $selectorRows." FROM ".$fromTable." WHERE ".$where." ORDER BY ".$orderby." OFFSET ".$data["iDisplayStart"]." LIMIT ".$data["iDisplayLength"]; $sql = $selectorRows." FROM ".$fromTable." WHERE ".$where." ORDER BY ".$orderby." OFFSET ".$data["iDisplayStart"]." LIMIT ".$data["iDisplayLength"];
} }
else { else {
$sql = $selectorRows." FROM ".$fromTable." ORDER BY ".$orderby." OFFSET ".$data["iDisplayStart"]." LIMIT ".$data["iDisplayLength"]; $sql = $selectorRows." FROM ".$fromTable." ORDER BY ".$orderby." OFFSET ".$data["iDisplayStart"]." LIMIT ".$data["iDisplayLength"];
} }
try { try {
$r = $con->query($sqlTotalRows); $r = $con->query($sqlTotalRows);
$totalRows = $r->fetchColumn(0); $totalRows = $r->fetchColumn(0);
if (isset($sqlTotalDisplayRows)) { if (isset($sqlTotalDisplayRows)) {
$r = $con->query($sqlTotalDisplayRows); $r = $con->query($sqlTotalDisplayRows);
$totalDisplayRows = $r->fetchColumn(0); $totalDisplayRows = $r->fetchColumn(0);
@ -740,7 +740,7 @@ Logging::log("getting media! - 2");
else { else {
$totalDisplayRows = $totalRows; $totalDisplayRows = $totalRows;
} }
$r = $con->query($sql); $r = $con->query($sql);
$r->setFetchMode(PDO::FETCH_ASSOC); $r->setFetchMode(PDO::FETCH_ASSOC);
$results = $r->fetchAll(); $results = $r->fetchAll();
@ -748,10 +748,10 @@ Logging::log("getting media! - 2");
catch (Exception $e) { catch (Exception $e) {
Logging::log($e->getMessage()); Logging::log($e->getMessage());
} }
//display sql executed in airtime log for testing //display sql executed in airtime log for testing
Logging::log($sql); Logging::log($sql);
return array("sEcho" => intval($data["sEcho"]), "iTotalDisplayRecords" => $totalDisplayRows, "iTotalRecords" => $totalRows, "aaData" => $results); return array("sEcho" => intval($data["sEcho"]), "iTotalDisplayRecords" => $totalDisplayRows, "iTotalRecords" => $totalRows, "aaData" => $results);
} }
@ -764,15 +764,15 @@ Logging::log("getting media! - 2");
header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false); header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache"); header("Pragma: no-cache");
// Settings // Settings
$cleanupTargetDir = false; // Remove old files $cleanupTargetDir = false; // Remove old files
$maxFileAge = 60 * 60; // Temp file age in seconds $maxFileAge = 60 * 60; // Temp file age in seconds
// 5 minutes execution time // 5 minutes execution time
@set_time_limit(5 * 60); @set_time_limit(5 * 60);
// usleep(5000); // usleep(5000);
// Get parameters // Get parameters
$chunk = isset($_REQUEST["chunk"]) ? $_REQUEST["chunk"] : 0; $chunk = isset($_REQUEST["chunk"]) ? $_REQUEST["chunk"] : 0;
$chunks = isset($_REQUEST["chunks"]) ? $_REQUEST["chunks"] : 0; $chunks = isset($_REQUEST["chunks"]) ? $_REQUEST["chunks"] : 0;
@ -781,29 +781,29 @@ Logging::log("getting media! - 2");
// Clean the fileName for security reasons // Clean the fileName for security reasons
//this needs fixing for songs not in ascii. //this needs fixing for songs not in ascii.
//$fileName = preg_replace('/[^\w\._]+/', '', $fileName); //$fileName = preg_replace('/[^\w\._]+/', '', $fileName);
// Create target dir // Create target dir
if (!file_exists($p_targetDir)) if (!file_exists($p_targetDir))
@mkdir($p_targetDir); @mkdir($p_targetDir);
// Remove old temp files // Remove old temp files
if (is_dir($p_targetDir) && ($dir = opendir($p_targetDir))) { if (is_dir($p_targetDir) && ($dir = opendir($p_targetDir))) {
while (($file = readdir($dir)) !== false) { while (($file = readdir($dir)) !== false) {
$filePath = $p_targetDir . DIRECTORY_SEPARATOR . $file; $filePath = $p_targetDir . DIRECTORY_SEPARATOR . $file;
// Remove temp files if they are older than the max age // Remove temp files if they are older than the max age
if (preg_match('/\.tmp$/', $file) && (filemtime($filePath) < time() - $maxFileAge)) if (preg_match('/\.tmp$/', $file) && (filemtime($filePath) < time() - $maxFileAge))
@unlink($filePath); @unlink($filePath);
} }
closedir($dir); closedir($dir);
} else } else
die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}'); die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
// Look for the content type header // Look for the content type header
if (isset($_SERVER["HTTP_CONTENT_TYPE"])) if (isset($_SERVER["HTTP_CONTENT_TYPE"]))
$contentType = $_SERVER["HTTP_CONTENT_TYPE"]; $contentType = $_SERVER["HTTP_CONTENT_TYPE"];
if (isset($_SERVER["CONTENT_TYPE"])) if (isset($_SERVER["CONTENT_TYPE"]))
$contentType = $_SERVER["CONTENT_TYPE"]; $contentType = $_SERVER["CONTENT_TYPE"];
@ -819,13 +819,13 @@ Logging::log("getting media! - 2");
if ($out) { if ($out) {
// Read binary input stream and append it to temp file // Read binary input stream and append it to temp file
$in = fopen($_FILES['file']['tmp_name'], "rb"); $in = fopen($_FILES['file']['tmp_name'], "rb");
if ($in) { if ($in) {
while ($buff = fread($in, 4096)) while ($buff = fread($in, 4096))
fwrite($out, $buff); fwrite($out, $buff);
} else } else
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}'); die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
fclose($out); fclose($out);
unlink($_FILES['file']['tmp_name']); unlink($_FILES['file']['tmp_name']);
} else } else
@ -838,18 +838,18 @@ Logging::log("getting media! - 2");
if ($out) { if ($out) {
// Read binary input stream and append it to temp file // Read binary input stream and append it to temp file
$in = fopen("php://input", "rb"); $in = fopen("php://input", "rb");
if ($in) { if ($in) {
while ($buff = fread($in, 4096)) while ($buff = fread($in, 4096))
fwrite($out, $buff); fwrite($out, $buff);
} else } else
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}'); die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
fclose($out); fclose($out);
} else } else
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}'); die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
} }
return $tempFilePath; return $tempFilePath;
} }
@ -899,7 +899,7 @@ Logging::log("getting media! - 2");
Logging::log("copyFileToStor: moving file $audio_file to $audio_stor"); Logging::log("copyFileToStor: moving file $audio_file to $audio_stor");
//Martin K.: changed to rename: Much less load + quicker since this is an atomic operation //Martin K.: changed to rename: Much less load + quicker since this is an atomic operation
$r = @rename($audio_file, $audio_stor); $r = @rename($audio_file, $audio_stor);
if ($r === false) { if ($r === false) {
#something went wrong likely there wasn't enough space in the audio_stor to move the file too. #something went wrong likely there wasn't enough space in the audio_stor to move the file too.
#warn the user that the file wasn't uploaded and they should check if there is enough disk space. #warn the user that the file wasn't uploaded and they should check if there is enough disk space.

View File

@ -19,6 +19,7 @@ class TimeFilledFormatter {
{ {
$formatted = ""; $formatted = "";
$sign = ($this->_seconds < 0) ? "-" : "+"; $sign = ($this->_seconds < 0) ? "-" : "+";
$perfect = true;
$time = Application_Model_Playlist::secondsToPlaylistTime(abs($this->_seconds)); $time = Application_Model_Playlist::secondsToPlaylistTime(abs($this->_seconds));
Logging::log("time is: ".$time); Logging::log("time is: ".$time);
@ -29,16 +30,24 @@ class TimeFilledFormatter {
if (intval($info[0]) > 0) { if (intval($info[0]) > 0) {
$info[0] = ltrim($info[0], "0"); $info[0] = ltrim($info[0], "0");
$formatted .= " {$info[0]}h"; $formatted .= " {$info[0]}h";
$perfect = false;
} }
if (intval($info[1]) > 0) { if (intval($info[1]) > 0) {
$info[1] = ltrim($info[1], "0"); $info[1] = ltrim($info[1], "0");
$formatted .= " {$info[1]}m"; $formatted .= " {$info[1]}m";
$perfect = false;
} }
if (intval($info[2]) > 0) { if (intval($info[2]) > 0) {
$sec = round($info[2], 0); $sec = round($info[2], 0);
$formatted .= " {$sec}s"; $formatted .= " {$sec}s";
$perfect = false;
}
//0 over/under lap of content.
if ($perfect === true) {
$formatted = "+ 0s";
} }
return $formatted; return $formatted;

View File

@ -0,0 +1,7 @@
<div class="his-timerange">
<?php echo $this->element->getElement('his_date_start') ?>
<?php echo $this->element->getElement('his_time_start') ?>
<?php echo $this->element->getElement('his_date_end') ?>
<?php echo $this->element->getElement('his_time_end') ?>
<input type="button" id="his_submit" class="ui-button ui-state-default" value="GO"></input>
</div>

View File

@ -1,4 +1,5 @@
<div class="sb-timerange"> <div class="sb-timerange">
<?php echo $this->element->getElement('sb_timestamp') ?>
<?php echo $this->element->getElement('sb_date_start') ?> <?php echo $this->element->getElement('sb_date_start') ?>
<?php echo $this->element->getElement('sb_time_start') ?> <?php echo $this->element->getElement('sb_time_start') ?>
<?php echo $this->element->getElement('sb_date_end') ?> <?php echo $this->element->getElement('sb_date_end') ?>

View File

@ -0,0 +1,2 @@
<?php echo $this->date_form; ?>
<table id="history_table" cellpadding="0" cellspacing="0" class="datatable"></table>

View File

@ -0,0 +1 @@
<?php echo $this->dialog ?>

View File

@ -1,7 +1,7 @@
#library_content { #library_content {
float: left; float: left;
width: 50%; width: 50%;
min-height: 475px; overflow: hidden;
} }
#library_display { #library_display {
@ -9,10 +9,6 @@
table-layout:fixed; table-layout:fixed;
} }
#library_display th {
text-align: left;
}
#library_content #library_display { #library_content #library_display {
width:100%; width:100%;
} }
@ -80,7 +76,8 @@
text-align: center; text-align: center;
} }
.library_sr, td.library_track,
.library_bitrate { td.library_sr,
text-align: right; td.library_bitrate {
} text-align: right;
}

View File

@ -1,9 +1,7 @@
#side_playlist { #side_playlist {
width: 40%; width: 40%;
min-height: 475px;
padding: 8px;
padding-bottom: 0px;
font-size: 16px; font-size: 16px;
overflow: auto;
} }
#side_playlist, #side_playlist,

View File

@ -2,6 +2,7 @@
#show_builder { #show_builder {
width:95%; width:95%;
overflow: auto;
} }
#show_builder_table th { #show_builder_table th {
@ -47,10 +48,22 @@ tr.cursor-selected-row .marker {
.ui-dialog .wrapper { .ui-dialog .wrapper {
margin: 0; margin: 0;
padding: 10px 0 0 0; padding: 10px 0 0 0;
overflow: hidden;
}
.ui-dialog #library_content {
margin: 0 10px 10px 0;
overflow: auto;
min-height: 0;
} }
.ui-dialog #show_builder { .ui-dialog #show_builder {
width:45%; margin: 0 0 10px 0;
overflow: auto;
}
.ui-dialog .padded {
padding: 5px 10px 5px 8px;
} }
.ui-dialog .ui-buttonset { .ui-dialog .ui-buttonset {

View File

@ -9,7 +9,7 @@ body {
padding: 0; padding: 0;
} }
html, body { html, body {
height: 100%; height: 100%;
} }
#login-page { #login-page {
@ -366,7 +366,7 @@ select {
.wrapper { .wrapper {
margin: 0 20px 0 20px; margin: 0 20px 0 20px;
padding:20px 0 0 0; padding:10px 0 0 0;
} }
.alpha-block { .alpha-block {
@ -510,6 +510,11 @@ dl.inline-list dd {
border-width: 1px 1px 1px 1px; border-width: 1px 1px 1px 1px;
width:100%; width:100%;
} }
.datatable th {
text-align: left;
}
.datatable tr td, .datatable tr th { .datatable tr td, .datatable tr th {
border-color: #b1b1b1; border-color: #b1b1b1;
border-style: solid; border-style: solid;
@ -554,6 +559,14 @@ dl.inline-list dd {
border-width: 0px 1px 0 1px; border-width: 0px 1px 0 1px;
} }
.dataTables_scrolling {
overflow: auto;
}
.dataTables_scrolling table{
border-width: 0px 1px 0 1px;
}
.DataTables_sort_wrapper .ui-icon { .DataTables_sort_wrapper .ui-icon {
display: block; display: block;
float: left; float: left;
@ -577,7 +590,7 @@ dl.inline-list dd {
line-height:22px; line-height:22px;
} }
.dataTables_filter { .dataTables_filter {
margin:8px 0 0 8px; margin:0 0 0 8px;
} }
.dataTables_filter .auto-search { .dataTables_filter .auto-search {
width:55%; width:55%;
@ -611,6 +624,7 @@ dl.inline-list dd {
.dataTables_paginate { .dataTables_paginate {
float: right; float: right;
padding: 8px 0 8px 8px; padding: 8px 0 8px 8px;
clear: left;
} }
.dataTables_paginate .ui-button { .dataTables_paginate .ui-button {
font-size:12px; font-size:12px;
@ -623,7 +637,7 @@ dl.inline-list dd {
width: 55%; width: 55%;
border: 1px solid #5B5B5B; border: 1px solid #5B5B5B;
margin-left: -8px; margin-left: -8px;
padding: 4px 3px 4px 25px; padding: 5px 3px 4px 25px;
} }
.dataTables_length select { .dataTables_length select {
background-color: #DDDDDD; background-color: #DDDDDD;
@ -662,7 +676,6 @@ button.ColVis_Button.ColVis_ShowAll {
.library_length { .library_length {
text-align: right; text-align: right;
padding-right: 1em !important;
} }
/*----END Data Table----*/ /*----END Data Table----*/

View File

@ -1,4 +1,4 @@
var AIRTIME = (function(AIRTIME){ var AIRTIME = (function(AIRTIME) {
var mod, var mod,
libraryInit; libraryInit;
@ -42,14 +42,17 @@
}; };
libraryInit = function() { libraryInit = function() {
var oTable; var oTable,
libContentDiv = $("#library_content");
tableHeight = libContentDiv.height() - 140;
oTable = $('#library_display').dataTable( { oTable = $('#library_display').dataTable( {
//put hidden columns at the top to insure they can never be visible on the table through column reordering.
"aoColumns": [ "aoColumns": [
/* Checkbox */ {"sTitle": "<input type='checkbox' name='pl_cb_all'>", "mDataProp": "checkbox", "bSortable": false, "bSearchable": false, "sWidth": "25px", "sClass": "library_checkbox"},
/* Type */ {"sTitle": "", "mDataProp": "image", "bSearchable": false, "sWidth": "25px", "sClass": "library_type", "iDataSort": 2},
/* ftype */ {"sTitle": "", "mDataProp": "ftype", "bSearchable": false, "bVisible": false}, /* ftype */ {"sTitle": "", "mDataProp": "ftype", "bSearchable": false, "bVisible": false},
/* Checkbox */ {"sTitle": "<input type='checkbox' name='pl_cb_all'>", "mDataProp": "checkbox", "bSortable": false, "bSearchable": false, "sWidth": "25px", "sClass": "library_checkbox"},
/* Type */ {"sTitle": "", "mDataProp": "image", "bSearchable": false, "sWidth": "25px", "sClass": "library_type", "iDataSort": 0},
/* Title */ {"sTitle": "Title", "mDataProp": "track_title", "sClass": "library_title"}, /* Title */ {"sTitle": "Title", "mDataProp": "track_title", "sClass": "library_title"},
/* Creator */ {"sTitle": "Creator", "mDataProp": "artist_name", "sClass": "library_creator"}, /* Creator */ {"sTitle": "Creator", "mDataProp": "artist_name", "sClass": "library_creator"},
/* Album */ {"sTitle": "Album", "mDataProp": "album_title", "sClass": "library_album"}, /* Album */ {"sTitle": "Album", "mDataProp": "album_title", "sClass": "library_album"},
@ -58,7 +61,7 @@
/* Length */ {"sTitle": "Length", "mDataProp": "length", "sClass": "library_length", "sWidth": "80px"}, /* Length */ {"sTitle": "Length", "mDataProp": "length", "sClass": "library_length", "sWidth": "80px"},
/* Upload Time */ {"sTitle": "Uploaded", "mDataProp": "utime", "sClass": "library_upload_time"}, /* Upload Time */ {"sTitle": "Uploaded", "mDataProp": "utime", "sClass": "library_upload_time"},
/* Last Modified */ {"sTitle": "Last Modified", "mDataProp": "mtime", "bVisible": false, "sClass": "library_modified_time"}, /* Last Modified */ {"sTitle": "Last Modified", "mDataProp": "mtime", "bVisible": false, "sClass": "library_modified_time"},
/* Track Number */ {"sTitle": "Track", "mDataProp": "track_number", "bSearchable": false, "bVisible": false, "sClass": "library_track"}, /* Track Number */ {"sTitle": "Track", "mDataProp": "track_number", "bSearchable": false, "bVisible": false, "sClass": "library_track", "sWidth": "65px"},
/* Mood */ {"sTitle": "Mood", "mDataProp": "mood", "bSearchable": false, "bVisible": false, "sClass": "library_mood"}, /* Mood */ {"sTitle": "Mood", "mDataProp": "mood", "bSearchable": false, "bVisible": false, "sClass": "library_mood"},
/* BPM */ {"sTitle": "BPM", "mDataProp": "bpm", "bSearchable": false, "bVisible": false, "sClass": "library_bpm"}, /* BPM */ {"sTitle": "BPM", "mDataProp": "bpm", "bSearchable": false, "bVisible": false, "sClass": "library_bpm"},
/* Composer */ {"sTitle": "Composer", "mDataProp": "composer", "bSearchable": false, "bVisible": false, "sClass": "library_composer"}, /* Composer */ {"sTitle": "Composer", "mDataProp": "composer", "bSearchable": false, "bVisible": false, "sClass": "library_composer"},
@ -232,9 +235,9 @@
"oLanguage": { "oLanguage": {
"sSearch": "" "sSearch": ""
}, },
// R = ColReorder, C = ColVis, T = TableTools // R = ColReorder, C = ColVis, T = TableTools
"sDom": 'Rl<"#library_display_type">fr<"H"T<"library_toolbar"C>>t<"F"ip>', "sDom": 'Rl<"#library_display_type">fr<"H"T<"library_toolbar"C>><"dataTables_scrolling"t><"F"ip>',
"oTableTools": { "oTableTools": {
"sRowSelect": "multi", "sRowSelect": "multi",
@ -290,6 +293,8 @@
}); });
oTable.fnSetFilteringDelay(350); oTable.fnSetFilteringDelay(350);
libContentDiv.find(".dataTables_scrolling").css("max-height", tableHeight);
AIRTIME.library.events.setupLibraryToolbar(oTable); AIRTIME.library.events.setupLibraryToolbar(oTable);
@ -469,9 +474,9 @@
return AIRTIME; return AIRTIME;
}(AIRTIME || {})); }(AIRTIME || {}));
function addToolBarButtonsLibrary(aButtons) { function addToolBarButtonsLibrary(aButtons) {
var i, var i,
length = aButtons.length, length = aButtons.length,
libToolBar = $(".library_toolbar"), libToolBar = $(".library_toolbar"),
@ -511,9 +516,9 @@
}(i)); }(i));
} }
} }
function checkImportStatus(){ function checkImportStatus(){
$.getJSON('/Preference/is-import-in-progress', function(data){ $.getJSON('/Preference/is-import-in-progress', function(data){
var div = $('#import_status'); var div = $('#import_status');
if (data == true){ if (data == true){
@ -523,9 +528,9 @@
div.hide(); div.hide();
} }
}); });
} }
function addProgressIcon(id) { function addProgressIcon(id) {
var tr = $("#au_"+id), var tr = $("#au_"+id),
span; span;
@ -539,9 +544,9 @@
tr.find("td.library_title") tr.find("td.library_title")
.append('<span class="small-icon progress"></span>'); .append('<span class="small-icon progress"></span>');
} }
} }
function checkSCUploadStatus(){ function checkSCUploadStatus(){
var url = '/Library/get-upload-to-soundcloud-status'; var url = '/Library/get-upload-to-soundcloud-status';
@ -563,9 +568,9 @@
} }
}); });
}); });
} }
function addQtipToSCIcons(){ function addQtipToSCIcons(){
$(".progress, .soundcloud, .sc-error").live('mouseover', function(){ $(".progress, .soundcloud, .sc-error").live('mouseover', function(){
var id = $(this).parent().parent().data("aData").id; var id = $(this).parent().parent().data("aData").id;
@ -644,8 +649,7 @@
}); });
} }
}); });
}
}
var audio_preview_window = null; var audio_preview_window = null;
@ -662,4 +666,3 @@ function open_audio_preview(fileID, index) {
return false; return false;
} }

View File

@ -1 +1,16 @@
$(document).ready(AIRTIME.library.libraryInit); $(document).ready(function() {
var viewport = AIRTIME.utilities.findViewportDimensions(),
lib = $("#library_content"),
pl = $("#side_playlist"),
widgetHeight = viewport.height - 185,
width = Math.floor(viewport.width - 110);
lib.height(widgetHeight)
.width(Math.floor(width * 0.55));
pl.height(widgetHeight)
.width(Math.floor(width * 0.45));
AIRTIME.library.libraryInit();
});

View File

@ -0,0 +1,133 @@
var AIRTIME = (function(AIRTIME) {
var mod;
if (AIRTIME.history === undefined) {
AIRTIME.history = {};
}
mod = AIRTIME.history;
mod.historyTable = function() {
var oTable,
historyContentDiv = $("#history_content"),
historyTableDiv = historyContentDiv.find("#history_table"),
tableHeight = historyContentDiv.height() - 140,
fnServerData;
fnServerData = function ( sSource, aoData, fnCallback ) {
if (fnServerData.hasOwnProperty("start")) {
aoData.push( { name: "start", value: fnServerData.start} );
}
if (fnServerData.hasOwnProperty("end")) {
aoData.push( { name: "end", value: fnServerData.end} );
}
aoData.push( { name: "format", value: "json"} );
$.ajax( {
"dataType": 'json',
"type": "GET",
"url": sSource,
"data": aoData,
"success": fnCallback
} );
};
oTable = historyTableDiv.dataTable( {
"aoColumns": [
{"sTitle": "Title", "mDataProp": "title", "sClass": "his_title"}, /* Title */
{"sTitle": "Artist", "mDataProp": "artist", "sClass": "his_artist"}, /* Creator */
{"sTitle": "Played", "mDataProp": "played", "sClass": "his_artist"}, /* times played */
{"sTitle": "Length", "mDataProp": "length", "sClass": "his_length library_length"}, /* Length */
{"sTitle": "Composer", "mDataProp": "composer", "sClass": "his_composer"}, /* Composer */
{"sTitle": "Copyright", "mDataProp": "copyright", "sClass": "his_copyright"} /* Copyright */
],
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": "/Playouthistory/playout-history-feed",
"sAjaxDataProp": "history",
"fnServerData": fnServerData,
"oLanguage": {
"sSearch": ""
},
"aLengthMenu": [[50, 100, 500, -1], [50, 100, 500, "All"]],
"iDisplayLength": 50,
"sPaginationType": "full_numbers",
"bJQueryUI": true,
"bAutoWidth": true,
"sDom": 'lfr<"H"T><"dataTables_scrolling"t><"F"ip>',
"oTableTools": {
"sSwfPath": "/js/datatables/plugin/TableTools/swf/copy_cvs_xls_pdf.swf"
}
});
oTable.fnSetFilteringDelay(350);
return oTable;
};
return AIRTIME;
}(AIRTIME || {}));
$(document).ready(function(){
var viewport = AIRTIME.utilities.findViewportDimensions(),
history_content = $("#history_content"),
widgetHeight = viewport.height - 185,
screenWidth = Math.floor(viewport.width - 110),
oBaseDatePickerSettings,
oBaseTimePickerSettings,
oTable,
dateStartId = "#his_date_start",
timeStartId = "#his_time_start",
dateEndId = "#his_date_end",
timeEndId = "#his_time_end";
history_content
.height(widgetHeight)
.width(screenWidth);
oBaseDatePickerSettings = {
dateFormat: 'yy-mm-dd',
onSelect: function(sDate, oDatePicker) {
$(this).datepicker( "setDate", sDate );
}
};
oBaseTimePickerSettings = {
showPeriodLabels: false,
showCloseButton: true,
showLeadingZero: false,
defaultTime: '0:00'
};
oTable = AIRTIME.history.historyTable();
history_content.find(dateStartId).datepicker(oBaseDatePickerSettings);
history_content.find(timeStartId).timepicker(oBaseTimePickerSettings);
history_content.find(dateEndId).datepicker(oBaseDatePickerSettings);
history_content.find(timeEndId).timepicker(oBaseTimePickerSettings);
history_content.find("#his_submit").click(function(ev){
var fn,
oRange;
oRange = AIRTIME.utilities.fnGetScheduleRange(dateStartId, timeStartId, dateEndId, timeEndId);
fn = oTable.fnSettings().fnServerData;
fn.start = oRange.start;
fn.end = oRange.end;
oTable.fnDraw();
});
});

View File

@ -100,15 +100,32 @@ function buildScheduleDialog (json) {
var dialog = $(json.dialog), var dialog = $(json.dialog),
viewport = findViewportDimensions(), viewport = findViewportDimensions(),
height = viewport.height * 0.96, height = Math.floor(viewport.height * 0.96),
width = viewport.width * 0.96, width = Math.floor(viewport.width * 0.96),
fnServer = AIRTIME.showbuilder.fnServerData; fnServer = AIRTIME.showbuilder.fnServerData,
//subtract padding in pixels
widgetWidth = width - 50,
libWidth = Math.floor(widgetWidth * 0.5),
builderWidth = Math.floor(widgetWidth * 0.5),
libLength,
libType,
libFilter;
dialog.find("#library_content")
.height(height - 110)
.width(libWidth);
dialog.find("#show_builder")
.height(height - 110)
.width(builderWidth);
dialog.dialog({ dialog.dialog({
autoOpen: false, autoOpen: false,
title: json.title, title: json.title,
width: width, width: width,
height: height, height: height,
resizable: false,
draggable: false,
modal: true, modal: true,
close: closeDialog, close: closeDialog,
buttons: {"Ok": function() { buttons: {"Ok": function() {
@ -116,7 +133,7 @@ function buildScheduleDialog (json) {
$("#schedule_calendar").fullCalendar( 'refetchEvents' ); $("#schedule_calendar").fullCalendar( 'refetchEvents' );
}} }}
}); });
//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.
fnServer.start = json.start; fnServer.start = json.start;
fnServer.end = json.end; fnServer.end = json.end;
@ -124,7 +141,17 @@ function buildScheduleDialog (json) {
AIRTIME.library.libraryInit(); AIRTIME.library.libraryInit();
AIRTIME.showbuilder.builderDataTable(); AIRTIME.showbuilder.builderDataTable();
dialog.find(".dataTables_scrolling")
.css("max-height", height - 110 - 155);
dialog.dialog('open'); dialog.dialog('open');
//calculate dynamically width for the library search input.
libLength = dialog.find("#library_display_length");
libType = dialog.find("#library_display_type");
libFilter = dialog.find("#library_display_filter");
libFilter.find("input").width(libFilter.width() - libType.width() - libLength.width() - 80);
} }
function buildContentDialog (json){ function buildContentDialog (json){

View File

@ -14,6 +14,34 @@ var AIRTIME = (function(AIRTIME){
} }
} }
mod.timeout = undefined;
mod.resetTimestamp = function() {
var timestamp = $("#sb_timestamp");
//reset timestamp value since input values could have changed.
timestamp.val(-1);
};
mod.setTimestamp = function(timestamp) {
$("#sb_timestamp").val(timestamp);
};
mod.getTimestamp = function() {
var timestamp = $("#sb_timestamp"),
val;
//if the timestamp field is on the page return it, or give the default of -1
//to ensure a page refresh.
if (timestamp.length === 1) {
val = timestamp.val();
}
else {
val = -1;
}
return val;
};
mod.fnAdd = function(aMediaIds, aSchedIds) { mod.fnAdd = function(aMediaIds, aSchedIds) {
var oLibTT = TableTools.fnGetInstance('library_display'); var oLibTT = TableTools.fnGetInstance('library_display');
@ -47,6 +75,8 @@ var AIRTIME = (function(AIRTIME){
}; };
fnServerData = function ( sSource, aoData, fnCallback ) { fnServerData = function ( sSource, aoData, fnCallback ) {
aoData.push( { name: "timestamp", value: AIRTIME.showbuilder.getTimestamp()} );
aoData.push( { name: "format", value: "json"} ); aoData.push( { name: "format", value: "json"} );
if (fnServerData.hasOwnProperty("start")) { if (fnServerData.hasOwnProperty("start")) {
@ -65,7 +95,10 @@ var AIRTIME = (function(AIRTIME){
"type": "GET", "type": "GET",
"url": sSource, "url": sSource,
"data": aoData, "data": aoData,
"success": fnCallback "success": function(json) {
AIRTIME.showbuilder.setTimestamp(json.timestamp);
fnCallback(json);
}
} ); } );
}; };
@ -74,7 +107,8 @@ var AIRTIME = (function(AIRTIME){
mod.builderDataTable = function() { mod.builderDataTable = function() {
var tableDiv = $('#show_builder_table'), var tableDiv = $('#show_builder_table'),
oTable, oTable,
fnRemoveSelectedItems; fnRemoveSelectedItems,
tableHeight;
fnRemoveSelectedItems = function() { fnRemoveSelectedItems = function() {
var oTT = TableTools.fnGetInstance('show_builder_table'), var oTT = TableTools.fnGetInstance('show_builder_table'),
@ -269,7 +303,11 @@ var AIRTIME = (function(AIRTIME){
markerDiv, markerDiv,
td, td,
$lib = $("#library_content"), $lib = $("#library_content"),
tr; tr,
oTable = $('#show_builder_table').dataTable(),
aData;
clearTimeout(AIRTIME.showbuilder.timeout);
//only create the cursor arrows if the library is on the page. //only create the cursor arrows if the library is on the page.
if ($lib.length > 0 && $lib.filter(":visible").length > 0) { if ($lib.length > 0 && $lib.filter(":visible").length > 0) {
@ -297,21 +335,37 @@ var AIRTIME = (function(AIRTIME){
//if the now playing song is visible set a timeout to redraw the table at the start of the next song. //if the now playing song is visible set a timeout to redraw the table at the start of the next song.
tr = tableDiv.find("tr.sb-now-playing"); tr = tableDiv.find("tr.sb-now-playing");
if (tr.length > 0) { if (tr.length > 0) {
var oTable = $('#show_builder_table').dataTable(), aData = tr.data("aData");
aData = tr.data("aData");
setTimeout(function(){ setTimeout(function(){
AIRTIME.showbuilder.resetTimestamp();
oTable.fnDraw(); oTable.fnDraw();
}, aData.refresh * 1000); //need refresh in milliseconds }, aData.refresh * 1000); //need refresh in milliseconds
} }
//current song is not set, set a timeout to refresh when the first item on the timeline starts.
else {
tr = tableDiv.find("tbody tr.sb-allowed.sb-header:first");
if (tr.length > 0) {
aData = tr.data("aData");
AIRTIME.showbuilder.timeout = setTimeout(function(){
AIRTIME.showbuilder.resetTimestamp();
oTable.fnDraw();
}, aData.timeUntil * 1000); //need refresh in milliseconds
}
}
}, },
"fnHeaderCallback": function(nHead) { "fnHeaderCallback": function(nHead) {
$(nHead).find("input[type=checkbox]").attr("checked", false); $(nHead).find("input[type=checkbox]").attr("checked", false);
}, },
//remove any selected nodes before the draw. //remove any selected nodes before the draw.
"fnPreDrawCallback": function( oSettings ) { "fnPreDrawCallback": function( oSettings ) {
var oTT = TableTools.fnGetInstance('show_builder_table'); var oTT;
oTT = TableTools.fnGetInstance('show_builder_table');
oTT.fnSelectNone(); oTT.fnSelectNone();
}, },
@ -371,7 +425,7 @@ var AIRTIME = (function(AIRTIME){
}, },
// R = ColReorderResize, C = ColVis, T = TableTools // R = ColReorderResize, C = ColVis, T = TableTools
"sDom": 'Rr<"H"CT>t<"F">', "sDom": 'Rr<"H"CT>t',
"sAjaxDataProp": "schedule", "sAjaxDataProp": "schedule",
"sAjaxSource": "/showbuilder/builder-feed" "sAjaxSource": "/showbuilder/builder-feed"

View File

@ -1,8 +1,24 @@
$(document).ready(function(){ $(document).ready(function(){
var oBaseDatePickerSettings, var viewport = AIRTIME.utilities.findViewportDimensions(),
lib = $("#library_content"),
builder = $("#show_builder"),
widgetHeight = viewport.height - 185,
screenWidth = Math.floor(viewport.width - 110),
oBaseDatePickerSettings,
oBaseTimePickerSettings, oBaseTimePickerSettings,
oRange; oRange,
dateStartId = "#sb_date_start",
timeStartId = "#sb_time_start",
dateEndId = "#sb_date_end",
timeEndId = "#sb_time_end";
//set the heights of the main widgets.
lib.height(widgetHeight);
//builder takes all the screen on first load
builder.height(widgetHeight)
.width(screenWidth);
oBaseDatePickerSettings = { oBaseDatePickerSettings = {
dateFormat: 'yy-mm-dd', dateFormat: 'yy-mm-dd',
@ -18,78 +34,10 @@ $(document).ready(function(){
defaultTime: '0:00' defaultTime: '0:00'
}; };
/* builder.find(dateStartId).datepicker(oBaseDatePickerSettings);
* Get the schedule range start in unix timestamp form (in seconds). builder.find(timeStartId).timepicker(oBaseTimePickerSettings);
* defaults to NOW if nothing is selected. builder.find(dateEndId).datepicker(oBaseDatePickerSettings);
* builder.find(timeEndId).timepicker(oBaseTimePickerSettings);
* @param String sDatePickerId
*
* @param String sTimePickerId
*
* @return Number iTime
*/
function fnGetTimestamp(sDatePickerId, sTimePickerId) {
var date,
time,
iTime,
iServerOffset,
iClientOffset;
if ($(sDatePickerId).val() === "") {
return 0;
}
date = $(sDatePickerId).val();
time = $(sTimePickerId).val();
date = date.split("-");
time = time.split(":");
//0 based month in js.
oDate = new Date(date[0], date[1]-1, date[2], time[0], time[1]);
iTime = oDate.getTime(); //value is in millisec.
iTime = Math.round(iTime / 1000);
iServerOffset = serverTimezoneOffset;
iClientOffset = oDate.getTimezoneOffset() * -60;//function returns minutes
//adjust for the fact the the Date object is in client time.
iTime = iTime + iClientOffset + iServerOffset;
return iTime;
}
/*
* Returns an object containing a unix timestamp in seconds for the start/end range
*
* @return Object {"start", "end", "range"}
*/
function fnGetScheduleRange() {
var iStart,
iEnd,
iRange,
DEFAULT_RANGE = 60*60*24;
iStart = fnGetTimestamp("#sb_date_start", "#sb_time_start");
iEnd = fnGetTimestamp("#sb_date_end", "#sb_time_end");
iRange = iEnd - iStart;
if (iRange === 0 || iEnd < iStart) {
iEnd = iStart + DEFAULT_RANGE;
iRange = DEFAULT_RANGE;
}
return {
start: iStart,
end: iEnd,
range: iRange
};
}
$("#sb_date_start").datepicker(oBaseDatePickerSettings);
$("#sb_time_start").timepicker(oBaseTimePickerSettings);
$("#sb_date_end").datepicker(oBaseDatePickerSettings);
$("#sb_time_end").timepicker(oBaseTimePickerSettings);
$("#sb_submit").click(function(ev){ $("#sb_submit").click(function(ev){
var fn, var fn,
@ -97,7 +45,10 @@ $(document).ready(function(){
op, op,
oTable = $('#show_builder_table').dataTable(); oTable = $('#show_builder_table').dataTable();
oRange = fnGetScheduleRange(); //reset timestamp value since input values could have changed.
AIRTIME.showbuilder.resetTimestamp();
oRange = AIRTIME.utilities.fnGetScheduleRange(dateStartId, timeStartId, dateEndId, timeEndId);
fn = oTable.fnSettings().fnServerData; fn = oTable.fnSettings().fnServerData;
fn.start = oRange.start; fn.start = oRange.start;
@ -120,40 +71,70 @@ $(document).ready(function(){
var $button = $(this), var $button = $(this),
$lib = $("#library_content"), $lib = $("#library_content"),
$builder = $("#show_builder"), $builder = $("#show_builder"),
oTable = $("#show_builder_table").dataTable(); schedTable = $("#show_builder_table").dataTable();
if ($button.hasClass("sb-edit")) { if ($button.hasClass("sb-edit")) {
//reset timestamp to redraw the cursors.
AIRTIME.showbuilder.resetTimestamp();
$lib.show(); $lib.show();
$lib.width("45%"); $lib.width(Math.floor(screenWidth * 0.5));
$builder.width("50%"); $builder.width(Math.floor(screenWidth * 0.5));
$button.removeClass("sb-edit"); $button.removeClass("sb-edit");
$button.addClass("sb-finish-edit"); $button.addClass("sb-finish-edit");
$button.val("Close Library"); $button.val("Close Library");
} }
else if($button.hasClass("sb-finish-edit")) { else if ($button.hasClass("sb-finish-edit")) {
$lib.hide(); $lib.hide();
$builder.width("95%"); $builder.width(screenWidth);
$button.removeClass("sb-finish-edit"); $button.removeClass("sb-finish-edit");
$button.addClass("sb-edit"); $button.addClass("sb-edit");
$button.val("Add Files"); $button.val("Add Files");
} }
oTable.fnDraw(); schedTable.fnDraw();
}); });
oRange = fnGetScheduleRange(); oRange = AIRTIME.utilities.fnGetScheduleRange(dateStartId, timeStartId, dateEndId, timeEndId);
AIRTIME.showbuilder.fnServerData.start = oRange.start; AIRTIME.showbuilder.fnServerData.start = oRange.start;
AIRTIME.showbuilder.fnServerData.end = oRange.end; AIRTIME.showbuilder.fnServerData.end = oRange.end;
AIRTIME.library.libraryInit();
AIRTIME.showbuilder.builderDataTable(); AIRTIME.showbuilder.builderDataTable();
//check if the timeline viewed needs updating.
setInterval(function(){ setInterval(function(){
var oTable = $('#show_builder_table').dataTable(); var data = {},
oTable.fnDraw(); oTable = $('#show_builder_table').dataTable(),
}, 20 * 1000); //need refresh in milliseconds fn = oTable.fnSettings().fnServerData,
start = fn.start,
end = fn.end;
data["format"] = "json";
data["start"] = start;
data["end"] = end;
data["timestamp"] = AIRTIME.showbuilder.getTimestamp();
if (fn.hasOwnProperty("ops")) {
data["myShows"] = fn.ops.myShows;
data["showFilter"] = fn.ops.showFilter;
}
$.ajax( {
"dataType": "json",
"type": "GET",
"url": "/showbuilder/check-builder-feed",
"data": data,
"success": function(json) {
if (json.update === true) {
oTable.fnDraw();
}
}
} );
}, 5 * 1000); //need refresh in milliseconds
}); });

View File

@ -0,0 +1,113 @@
var AIRTIME = (function(AIRTIME){
var mod;
if (AIRTIME.utilities === undefined) {
AIRTIME.utilities = {};
}
mod = AIRTIME.utilities;
mod.findViewportDimensions = function() {
var viewportwidth,
viewportheight;
// the more standards compliant browsers (mozilla/netscape/opera/IE7) use
// window.innerWidth and window.innerHeight
if (typeof window.innerWidth != 'undefined') {
viewportwidth = window.innerWidth, viewportheight = window.innerHeight;
}
// IE6 in standards compliant mode (i.e. with a valid doctype as the first
// line in the document)
else if (typeof document.documentElement != 'undefined'
&& typeof document.documentElement.clientWidth != 'undefined'
&& document.documentElement.clientWidth != 0) {
viewportwidth = document.documentElement.clientWidth;
viewportheight = document.documentElement.clientHeight;
}
// older versions of IE
else {
viewportwidth = document.getElementsByTagName('body')[0].clientWidth;
viewportheight = document.getElementsByTagName('body')[0].clientHeight;
}
return {
width: viewportwidth,
height: viewportheight
};
};
/*
* Get the schedule range start in unix timestamp form (in seconds).
* defaults to NOW if nothing is selected.
*
* @param String sDatePickerId
*
* @param String sTimePickerId
*
* @return Number iTime
*/
mod.fnGetTimestamp = function(sDateId, sTimeId) {
var date,
time,
iTime,
iServerOffset,
iClientOffset,
temp;
temp = $(sDateId).val();
if ( temp === "") {
return 0;
}
else {
date = temp;
}
time = $(sTimeId).val();
date = date.split("-");
time = time.split(":");
//0 based month in js.
oDate = new Date(date[0], date[1]-1, date[2], time[0], time[1]);
iTime = oDate.getTime(); //value is in millisec.
iTime = Math.round(iTime / 1000);
iServerOffset = serverTimezoneOffset;
iClientOffset = oDate.getTimezoneOffset() * -60;//function returns minutes
//adjust for the fact the the Date object is in client time.
iTime = iTime + iClientOffset + iServerOffset;
return iTime;
};
/*
* Returns an object containing a unix timestamp in seconds for the start/end range
*
* @return Object {"start", "end", "range"}
*/
mod.fnGetScheduleRange = function(dateStart, timeStart, dateEnd, timeEnd) {
var iStart,
iEnd,
iRange,
DEFAULT_RANGE = 60*60*24;
iStart = AIRTIME.utilities.fnGetTimestamp(dateStart, timeStart);
iEnd = AIRTIME.utilities.fnGetTimestamp(dateEnd, timeEnd);
iRange = iEnd - iStart;
if (iRange === 0 || iEnd < iStart) {
iEnd = iStart + DEFAULT_RANGE;
iRange = DEFAULT_RANGE;
}
return {
start: iStart,
end: iEnd,
range: iRange
};
};
return AIRTIME;
}(AIRTIME || {}));

View File

@ -0,0 +1,221 @@
/* Compile using: mxmlc --target-player=10.0.0 ZeroClipboard.as */
package {
import flash.display.Stage;
import flash.display.Sprite;
import flash.display.LoaderInfo;
import flash.display.StageScaleMode;
import flash.events.*;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.external.ExternalInterface;
import flash.system.Security;
import flash.utils.*;
import flash.system.System;
import flash.net.FileReference;
import flash.net.FileFilter;
public class ZeroClipboard extends Sprite {
private var domId:String = '';
private var button:Sprite;
private var clipText:String = 'blank';
private var fileName:String = '';
private var action:String = 'copy';
private var incBom:Boolean = true;
private var charSet:String = 'utf8';
public function ZeroClipboard() {
// constructor, setup event listeners and external interfaces
stage.scaleMode = StageScaleMode.EXACT_FIT;
flash.system.Security.allowDomain("*");
// import flashvars
var flashvars:Object = LoaderInfo( this.root.loaderInfo ).parameters;
domId = flashvars.id;
// invisible button covers entire stage
button = new Sprite();
button.buttonMode = true;
button.useHandCursor = true;
button.graphics.beginFill(0x00FF00);
button.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
button.alpha = 0.0;
addChild(button);
button.addEventListener(MouseEvent.CLICK, clickHandler);
button.addEventListener(MouseEvent.MOUSE_OVER, function(event:Event):void {
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'mouseOver', null );
} );
button.addEventListener(MouseEvent.MOUSE_OUT, function(event:Event):void {
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'mouseOut', null );
} );
button.addEventListener(MouseEvent.MOUSE_DOWN, function(event:Event):void {
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'mouseDown', null );
} );
button.addEventListener(MouseEvent.MOUSE_UP, function(event:Event):void {
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'mouseUp', null );
} );
// External functions - readd whenever the stage is made active for IE
addCallbacks();
stage.addEventListener(Event.ACTIVATE, addCallbacks);
// signal to the browser that we are ready
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'load', null );
}
public function addCallbacks ():void {
ExternalInterface.addCallback("setHandCursor", setHandCursor);
ExternalInterface.addCallback("clearText", clearText);
ExternalInterface.addCallback("setText", setText);
ExternalInterface.addCallback("appendText", appendText);
ExternalInterface.addCallback("setFileName", setFileName);
ExternalInterface.addCallback("setAction", setAction);
ExternalInterface.addCallback("setCharSet", setCharSet);
ExternalInterface.addCallback("setBomInc", setBomInc);
}
public function setCharSet(newCharSet:String):void {
if ( newCharSet == 'UTF16LE' ) {
charSet = newCharSet;
} else {
charSet = 'UTF8';
}
}
public function setBomInc(newBomInc:Boolean):void {
incBom = newBomInc;
}
public function clearText():void {
clipText = '';
}
public function appendText(newText:String):void {
clipText += newText;
}
public function setText(newText:String):void {
clipText = newText;
}
public function setFileName(newFileName:String):void {
fileName = newFileName;
}
public function setAction(newAction:String):void {
action = newAction;
}
public function setHandCursor(enabled:Boolean):void {
// control whether the hand cursor is shown on rollover (true)
// or the default arrow cursor (false)
button.useHandCursor = enabled;
}
private function clickHandler(event:Event):void {
var fileRef:FileReference = new FileReference();
fileRef.addEventListener(Event.COMPLETE, saveComplete);
if ( action == "save" ) {
/* Save as a file */
if ( charSet == 'UTF16LE' ) {
fileRef.save( strToUTF16LE(clipText), fileName );
} else {
fileRef.save( strToUTF8(clipText), fileName );
}
} else if ( action == "pdf" ) {
fileRef.save( "This instance of ZeroClipboard is not configured for PDF export. "+
"Please use the PDF export version.", fileName+".txt" );
} else {
/* Copy the text to the clipboard. Note charset and BOM have no effect here */
System.setClipboard( clipText );
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'complete', clipText );
}
}
private function saveComplete(event:Event):void {
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'complete', clipText );
}
private function getProp( prop:String, opts:Array ):String
{
var i:int, iLen:int;
for ( i=0, iLen=opts.length ; i<iLen ; i++ )
{
if ( opts[i].indexOf( prop+":" ) != -1 )
{
return opts[i].replace( prop+":", "" );
}
}
return "";
}
/*
* Function: strToUTF8
* Purpose: Convert a string to the output utf-8
* Returns: ByteArray
* Inputs: String
*/
private function strToUTF8( str:String ):ByteArray {
var utf8:ByteArray = new ByteArray();
/* BOM first */
if ( incBom ) {
utf8.writeByte( 0xEF );
utf8.writeByte( 0xBB );
utf8.writeByte( 0xBF );
}
utf8.writeUTFBytes( str );
return utf8;
}
/*
* Function: strToUTF16LE
* Purpose: Convert a string to the output utf-16
* Returns: ByteArray
* Inputs: String
* Notes: The fact that this function is needed is a little annoying. Basically, strings in
* AS3 are UTF-16 (with surrogate pairs and everything), but characters which take up less
* than 8 bytes appear to be stored as only 8 bytes. This function effective adds the
* padding required, and the BOM
*/
private function strToUTF16LE( str:String ):ByteArray {
var utf16:ByteArray = new ByteArray();
var iChar:uint;
var i:uint=0, iLen:uint = str.length;
/* BOM first */
if ( incBom ) {
utf16.writeByte( 0xFF );
utf16.writeByte( 0xFE );
}
while ( i < iLen ) {
iChar = str.charCodeAt(i);
if ( iChar < 0xFF ) {
/* one byte char */
utf16.writeByte( iChar );
utf16.writeByte( 0 );
} else {
/* two byte char */
utf16.writeByte( iChar & 0x00FF );
utf16.writeByte( iChar >> 8 );
}
i++;
}
return utf16;
}
}
}

View File

@ -0,0 +1,310 @@
/* Compile using: mxmlc --target-player=10.0.0 -static-link-runtime-shared-libraries=true -library-path+=lib ZeroClipboardPdf.as */
package {
import flash.display.Stage;
import flash.display.Sprite;
import flash.display.LoaderInfo;
import flash.display.StageScaleMode;
import flash.events.*;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.external.ExternalInterface;
import flash.system.Security;
import flash.utils.*;
import flash.system.System;
import flash.net.FileReference;
import flash.net.FileFilter;
/* PDF imports */
import org.alivepdf.pdf.PDF;
import org.alivepdf.data.Grid;
import org.alivepdf.data.GridColumn;
import org.alivepdf.layout.Orientation;
import org.alivepdf.layout.Size;
import org.alivepdf.layout.Unit;
import org.alivepdf.display.Display;
import org.alivepdf.saving.Method;
import org.alivepdf.fonts.FontFamily;
import org.alivepdf.fonts.Style;
import org.alivepdf.fonts.CoreFont;
import org.alivepdf.colors.RGBColor;
public class ZeroClipboard extends Sprite {
private var domId:String = '';
private var button:Sprite;
private var clipText:String = 'blank';
private var fileName:String = '';
private var action:String = 'copy';
private var incBom:Boolean = true;
private var charSet:String = 'utf8';
public function ZeroClipboard() {
// constructor, setup event listeners and external interfaces
stage.scaleMode = StageScaleMode.EXACT_FIT;
flash.system.Security.allowDomain("*");
// import flashvars
var flashvars:Object = LoaderInfo( this.root.loaderInfo ).parameters;
domId = flashvars.id;
// invisible button covers entire stage
button = new Sprite();
button.buttonMode = true;
button.useHandCursor = true;
button.graphics.beginFill(0x00FF00);
button.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
button.alpha = 0.0;
addChild(button);
button.addEventListener(MouseEvent.CLICK, function(event:Event):void {
clickHandler(event);
} );
button.addEventListener(MouseEvent.MOUSE_OVER, function(event:Event):void {
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'mouseOver', null );
} );
button.addEventListener(MouseEvent.MOUSE_OUT, function(event:Event):void {
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'mouseOut', null );
} );
button.addEventListener(MouseEvent.MOUSE_DOWN, function(event:Event):void {
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'mouseDown', null );
} );
button.addEventListener(MouseEvent.MOUSE_UP, function(event:Event):void {
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'mouseUp', null );
} );
// External functions - readd whenever the stage is made active for IE
addCallbacks();
stage.addEventListener(Event.ACTIVATE, addCallbacks);
// signal to the browser that we are ready
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'load', null );
}
public function addCallbacks ():void {
ExternalInterface.addCallback("setHandCursor", setHandCursor);
ExternalInterface.addCallback("clearText", clearText);
ExternalInterface.addCallback("setText", setText);
ExternalInterface.addCallback("appendText", appendText);
ExternalInterface.addCallback("setFileName", setFileName);
ExternalInterface.addCallback("setAction", setAction);
ExternalInterface.addCallback("setCharSet", setCharSet);
ExternalInterface.addCallback("setBomInc", setBomInc);
}
public function setCharSet(newCharSet:String):void {
if ( newCharSet == 'UTF16LE' ) {
charSet = newCharSet;
} else {
charSet = 'UTF8';
}
}
public function setBomInc(newBomInc:Boolean):void {
incBom = newBomInc;
}
public function clearText():void {
clipText = '';
}
public function appendText(newText:String):void {
clipText += newText;
}
public function setText(newText:String):void {
clipText = newText;
}
public function setFileName(newFileName:String):void {
fileName = newFileName;
}
public function setAction(newAction:String):void {
action = newAction;
}
public function setHandCursor(enabled:Boolean):void {
// control whether the hand cursor is shown on rollover (true)
// or the default arrow cursor (false)
button.useHandCursor = enabled;
}
private function clickHandler(event:Event):void {
var fileRef:FileReference = new FileReference();
fileRef.addEventListener(Event.COMPLETE, saveComplete);
if ( action == "save" ) {
/* Save as a file */
if ( charSet == 'UTF16LE' ) {
fileRef.save( strToUTF16LE(clipText), fileName );
} else {
fileRef.save( strToUTF8(clipText), fileName );
}
} else if ( action == "pdf" ) {
/* Save as a PDF */
var pdf:PDF = configPdf();
fileRef.save( pdf.save( Method.LOCAL ), fileName );
} else {
/* Copy the text to the clipboard. Note charset and BOM have no effect here */
System.setClipboard( clipText );
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'complete', clipText );
}
}
private function saveComplete(event:Event):void {
ExternalInterface.call( 'ZeroClipboard.dispatch', domId, 'complete', clipText );
}
private function getProp( prop:String, opts:Array ):String
{
var i:int, iLen:int;
for ( i=0, iLen=opts.length ; i<iLen ; i++ )
{
if ( opts[i].indexOf( prop+":" ) != -1 )
{
return opts[i].replace( prop+":", "" );
}
}
return "";
}
private function configPdf():PDF
{
var
pdf:PDF,
i:int, iLen:int,
splitText:Array = clipText.split("--/TableToolsOpts--\n"),
opts:Array = splitText[0].split("\n"),
dataIn:Array = splitText[1].split("\n"),
aColRatio:Array = getProp( 'colWidth', opts ).split('\t'),
title:String = getProp( 'title', opts ),
message:String = getProp( 'message', opts ),
orientation:String = getProp( 'orientation', opts ),
size:String = getProp( 'size', opts ),
iPageWidth:int = 0,
dataOut:Array = [],
columns:Array = [],
headers:Array,
y:int = 0;
/* Create the PDF */
pdf = new PDF( Orientation[orientation.toUpperCase()], Unit.MM, Size[size.toUpperCase()] );
pdf.setDisplayMode( Display.FULL_WIDTH );
pdf.addPage();
iPageWidth = pdf.getCurrentPage().w-20;
pdf.textStyle( new RGBColor(0), 1 );
/* Add the title / message if there is one */
pdf.setFont( new CoreFont(FontFamily.HELVETICA), 14 );
if ( title != "" )
{
pdf.writeText(11, title+"\n");
}
pdf.setFont( new CoreFont(FontFamily.HELVETICA), 11 );
if ( message != "" )
{
pdf.writeText(11, message+"\n");
}
/* Data setup. Split up the headers, and then construct the columns */
for ( i=0, iLen=dataIn.length ; i<iLen ; i++ )
{
if ( dataIn[i] != "" )
{
dataOut.push( dataIn[i].split("\t") );
}
}
headers = dataOut.shift();
for ( i=0, iLen=headers.length ; i<iLen ; i++ )
{
columns.push( new GridColumn( " \n"+headers[i]+"\n ", i.toString(), aColRatio[i]*iPageWidth, 'C' ) );
}
var grid:Grid = new Grid(
dataOut, /* 1. data */
iPageWidth, /* 2. width */
100, /* 3. height */
new RGBColor (0xE0E0E0), /* 4. headerColor */
new RGBColor (0xFFFFFF), /* 5. backgroundColor */
true, /* 6. alternateRowColor */
new RGBColor ( 0x0 ), /* 7. borderColor */
.1, /* 8. border alpha */
null, /* 9. joins */
columns /* 10. columns */
);
pdf.addGrid( grid, 0, y );
return pdf;
}
/*
* Function: strToUTF8
* Purpose: Convert a string to the output utf-8
* Returns: ByteArray
* Inputs: String
*/
private function strToUTF8( str:String ):ByteArray {
var utf8:ByteArray = new ByteArray();
/* BOM first */
if ( incBom ) {
utf8.writeByte( 0xEF );
utf8.writeByte( 0xBB );
utf8.writeByte( 0xBF );
}
utf8.writeUTFBytes( str );
return utf8;
}
/*
* Function: strToUTF16LE
* Purpose: Convert a string to the output utf-16
* Returns: ByteArray
* Inputs: String
* Notes: The fact that this function is needed is a little annoying. Basically, strings in
* AS3 are UTF-16 (with surrogate pairs and everything), but characters which take up less
* than 8 bytes appear to be stored as only 8 bytes. This function effective adds the
* padding required, and the BOM
*/
private function strToUTF16LE( str:String ):ByteArray {
var utf16:ByteArray = new ByteArray();
var iChar:uint;
var i:uint=0, iLen:uint = str.length;
/* BOM first */
if ( incBom ) {
utf16.writeByte( 0xFF );
utf16.writeByte( 0xFE );
}
while ( i < iLen ) {
iChar = str.charCodeAt(i);
if ( iChar < 0xFF ) {
/* one byte char */
utf16.writeByte( iChar );
utf16.writeByte( 0 );
} else {
/* two byte char */
utf16.writeByte( iChar & 0x00FF );
utf16.writeByte( iChar >> 8 );
}
i++;
}
return utf16;
}
}
}

View File

@ -0,0 +1,264 @@
/*
* File: TableTools.css
* Description: Styles for TableTools 2
* Author: Allan Jardine (www.sprymedia.co.uk)
* Language: Javascript
* License: LGPL / 3 point BSD
* Project: DataTables
*
* Copyright 2010 Allan Jardine, all rights reserved.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* CSS name space:
* DTTT DataTables TableTools
*
* Colour dictionary:
* Button border #d0d0d0
* Button border hover #999999
* Hover background #f0f0f0
* Action blue #4b66d9
*
* Style sheet provides:
* CONTAINER TableTools container element and styles applying to all components
* BUTTON_STYLES Action specific button styles
* SELECTING Row selection styles
* COLLECTIONS Drop down list (collection) styles
* PRINTING Print display styles
* MISC Minor misc styles
*/
/*
* CONTAINER
* TableTools container element and styles applying to all components
*/
div.DTTT_container {
position: relative;
float: right;
margin-bottom: 1em;
}
button.DTTT_button {
position: relative;
float: left;
height: 30px;
margin-right: 3px;
padding: 3px 5px;
border: 1px solid #d0d0d0;
background-color: #fff;
cursor: pointer;
*cursor: hand;
}
button.DTTT_button::-moz-focus-inner {
border: none !important;
padding: 0;
}
/*
* BUTTON_STYLES
* Action specific button styles
*/
button.DTTT_button_csv {
padding-right: 30px;
background: #6E6E6E url(../images/csv.png) no-repeat center right !important;
}
button.DTTT_button_csv_hover {
padding-right: 30px;
background: #868686 url(../images/csv_hover.png) no-repeat center right !important;
}
button.DTTT_button_xls {
padding-right: 30px;
background: #6E6E6E url(../images/xls.png) no-repeat center right !important;
}
button.DTTT_button_xls_hover {
padding-right: 30px;
border: 1px solid #999;
background: #868686 url(../images/xls_hover.png) no-repeat center right !important;
}
button.DTTT_button_copy {
padding-right: 30px;
background: #6E6E6E url(../images/copy.png) no-repeat center right !important;
}
button.DTTT_button_copy_hover {
padding-right: 30px;
border: 1px solid #999;
background: #868686 url(../images/copy_hover.png) no-repeat center right !important;
}
button.DTTT_button_pdf {
padding-right: 30px;
background: #6E6E6E url(../images/pdf.png) no-repeat center right !important;
}
button.DTTT_button_pdf_hover {
padding-right: 30px;
border: 1px solid #999;
background: #868686 url(../images/pdf_hover.png) no-repeat center right !important;
}
button.DTTT_button_print {
padding-right: 30px;
background: #6E6E6E url(../images/print.png) no-repeat center right !important;
}
button.DTTT_button_print_hover {
padding-right: 30px;
border: 1px solid #999;
background: #868686 url(../images/print_hover.png) no-repeat center right !important;
}
button.DTTT_button_text {
}
button.DTTT_button_text_hover {
border: 1px solid #999;
background-color: #f0f0f0;
}
button.DTTT_button_collection {
padding-right: 17px;
background: url(../images/collection.png) no-repeat center right;
}
button.DTTT_button_collection_hover {
padding-right: 17px;
border: 1px solid #999;
background: #f0f0f0 url(../images/collection_hover.png) no-repeat center right;
}
/*
* SELECTING
* Row selection styles
*/
table.DTTT_selectable tbody tr {
cursor: pointer;
*cursor: hand;
}
tr.DTTT_selected.odd {
background-color: #9FAFD1;
}
tr.DTTT_selected.odd td.sorting_1 {
background-color: #9FAFD1;
}
tr.DTTT_selected.odd td.sorting_2 {
background-color: #9FAFD1;
}
tr.DTTT_selected.odd td.sorting_3 {
background-color: #9FAFD1;
}
tr.DTTT_selected.even {
background-color: #B0BED9;
}
tr.DTTT_selected.even td.sorting_1 {
background-color: #B0BED9;
}
tr.DTTT_selected.even td.sorting_2 {
background-color: #B0BED9;
}
tr.DTTT_selected.even td.sorting_3 {
background-color: #B0BED9;
}
/*
* COLLECTIONS
* Drop down list (collection) styles
*/
div.DTTT_collection {
width: 150px;
padding: 3px;
border: 1px solid #ccc;
background-color: #f3f3f3;
overflow: hidden;
z-index: 2002;
}
div.DTTT_collection_background {
background: transparent url(../images/background.png) repeat top left;
z-index: 2001;
}
div.DTTT_collection button.DTTT_button {
float: none;
width: 100%;
margin-bottom: 2px;
background-color: white;
}
/*
* PRINTING
* Print display styles
*/
.DTTT_print_info {
position: absolute;
top: 50%;
left: 50%;
width: 400px;
height: 150px;
margin-left: -200px;
margin-top: -75px;
text-align: center;
background-color: #3f3f3f;
color: white;
padding: 10px 30px;
opacity: 0.9;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
}
.DTTT_print_info h6 {
font-weight: normal;
font-size: 28px;
line-height: 28px;
margin: 1em;
}
.DTTT_print_info p {
font-size: 14px;
line-height: 20px;
}
/*
* MISC
* Minor misc styles
*/
.DTTT_disabled {
color: #999;
}

View File

@ -0,0 +1,183 @@
/*
* File: TableTools.css
* Description: Styles for TableTools 2 with JUI theming
* Author: Allan Jardine (www.sprymedia.co.uk)
* Language: Javascript
* License: LGPL / 3 point BSD
* Project: DataTables
*
* Copyright 2010 Allan Jardine, all rights reserved.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Notes:
* Generally speaking, please refer to the TableTools.css file - this file contains basic
* modifications to that 'master' stylesheet for ThemeRoller.
*
* CSS name space:
* DTTT DataTables TableTools
*
* Colour dictionary:
* Button border #d0d0d0
* Button border hover #999999
* Hover background #f0f0f0
* Action blue #4b66d9
*
* Style sheet provides:
* CONTAINER TableTools container element and styles applying to all components
* SELECTING Row selection styles
* COLLECTIONS Drop down list (collection) styles
* PRINTING Print display styles
* MISC Minor misc styles
*/
/*
* CONTAINER
* TableTools container element and styles applying to all components
*/
div.DTTT_container {
position: relative;
float: left;
}
button.DTTT_button {
position: relative;
float: left;
height: 24px;
margin-right: 3px;
padding: 3px 10px;
border: 1px solid #d0d0d0;
background-color: #fff;
cursor: pointer;
*cursor: hand;
}
button.DTTT_button::-moz-focus-inner {
border: none !important;
padding: 0;
}
/*
* SELECTING
* Row selection styles
*/
table.DTTT_selectable tbody tr {
cursor: pointer;
*cursor: hand;
}
tr.DTTT_selected.odd {
background-color: #9FAFD1;
}
tr.DTTT_selected.odd td.sorting_1 {
background-color: #9FAFD1;
}
tr.DTTT_selected.odd td.sorting_2 {
background-color: #9FAFD1;
}
tr.DTTT_selected.odd td.sorting_3 {
background-color: #9FAFD1;
}
tr.DTTT_selected.even {
background-color: #B0BED9;
}
tr.DTTT_selected.even td.sorting_1 {
background-color: #B0BED9;
}
tr.DTTT_selected.even td.sorting_2 {
background-color: #B0BED9;
}
tr.DTTT_selected.even td.sorting_3 {
background-color: #B0BED9;
}
/*
* COLLECTIONS
* Drop down list (collection) styles
*/
div.DTTT_collection {
width: 150px;
background-color: #f3f3f3;
overflow: hidden;
z-index: 2002;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
}
div.DTTT_collection_background {
background: url(../images/background.png) repeat top left;
z-index: 2001;
}
div.DTTT_collection button.DTTT_button {
float: none;
width: 100%;
margin-bottom: -0.1em;
}
/*
* PRINTING
* Print display styles
*/
.DTTT_print_info {
position: absolute;
top: 50%;
left: 50%;
width: 400px;
height: 150px;
margin-left: -200px;
margin-top: -75px;
text-align: center;
background-color: #3f3f3f;
color: white;
padding: 10px 30px;
opacity: 0.9;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
}
.DTTT_print_info h6 {
font-weight: normal;
font-size: 28px;
line-height: 28px;
margin: 1em;
}
.DTTT_print_info p {
font-size: 14px;
line-height: 20px;
}
/*
* MISC
* Minor misc styles
*/
.DTTT_disabled {
color: #999;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,81 @@
// Simple Set Clipboard System
// Author: Joseph Huckaby
var ZeroClipboard={version:"1.0.4-TableTools2",clients:{},moviePath:"",nextId:1,$:function(a){"string"==typeof a&&(a=document.getElementById(a));if(!a.addClass)a.hide=function(){this.style.display="none"},a.show=function(){this.style.display=""},a.addClass=function(a){this.removeClass(a);this.className+=" "+a},a.removeClass=function(a){this.className=this.className.replace(RegExp("\\s*"+a+"\\s*")," ").replace(/^\s+/,"").replace(/\s+$/,"")},a.hasClass=function(a){return!!this.className.match(RegExp("\\s*"+
a+"\\s*"))};return a},setMoviePath:function(a){this.moviePath=a},dispatch:function(a,b,c){(a=this.clients[a])&&a.receiveEvent(b,c)},register:function(a,b){this.clients[a]=b},getDOMObjectPosition:function(a){var b={left:0,top:0,width:a.width?a.width:a.offsetWidth,height:a.height?a.height:a.offsetHeight};if(""!=a.style.width)b.width=a.style.width.replace("px","");if(""!=a.style.height)b.height=a.style.height.replace("px","");for(;a;)b.left+=a.offsetLeft,b.top+=a.offsetTop,a=a.offsetParent;return b},
Client:function(a){this.handlers={};this.id=ZeroClipboard.nextId++;this.movieId="ZeroClipboardMovie_"+this.id;ZeroClipboard.register(this.id,this);a&&this.glue(a)}};
ZeroClipboard.Client.prototype={id:0,ready:!1,movie:null,clipText:"",fileName:"",action:"copy",handCursorEnabled:!0,cssEffects:!0,handlers:null,sized:!1,glue:function(a,b){this.domElement=ZeroClipboard.$(a);var c=99;this.domElement.style.zIndex&&(c=parseInt(this.domElement.style.zIndex)+1);var d=ZeroClipboard.getDOMObjectPosition(this.domElement);this.div=document.createElement("div");var e=this.div.style;e.position="absolute";e.left=this.domElement.offsetLeft+"px";e.top=this.domElement.offsetTop+
"px";e.width=d.width+"px";e.height=d.height+"px";e.zIndex=c;if("undefined"!=typeof b&&""!=b)this.div.title=b;if(0!=d.width&&0!=d.height)this.sized=!0;this.domElement.parentNode.appendChild(this.div);this.div.innerHTML=this.getHTML(d.width,d.height)},positionElement:function(){var a=ZeroClipboard.getDOMObjectPosition(this.domElement),b=this.div.style;b.position="absolute";b.left=this.domElement.offsetLeft+"px";b.top=this.domElement.offsetTop+"px";b.width=a.width+"px";b.height=a.height+"px";if(0!=a.width&&
0!=a.height)this.sized=!0,b=this.div.childNodes[0],b.width=a.width,b.height=a.height},getHTML:function(a,b){var c="",d="id="+this.id+"&width="+a+"&height="+b;if(navigator.userAgent.match(/MSIE/))var e=location.href.match(/^https/i)?"https://":"http://",c=c+('<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="'+e+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0" width="'+a+'" height="'+b+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+
ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+d+'"/><param name="wmode" value="transparent"/></object>');else c+='<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+a+'" height="'+b+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+
d+'" wmode="transparent" />';return c},hide:function(){if(this.div)this.div.style.left="-2000px"},show:function(){this.reposition()},destroy:function(){if(this.domElement&&this.div){this.hide();this.div.innerHTML="";var a=document.getElementsByTagName("body")[0];try{a.removeChild(this.div)}catch(b){}this.div=this.domElement=null}},reposition:function(a){if(a)(this.domElement=ZeroClipboard.$(a))||this.hide();if(this.domElement&&this.div){var a=ZeroClipboard.getDOMObjectPosition(this.domElement),b=
this.div.style;b.left=""+a.left+"px";b.top=""+a.top+"px"}},clearText:function(){this.clipText="";this.ready&&this.movie.clearText()},appendText:function(a){this.clipText+=a;this.ready&&this.movie.appendText(a)},setText:function(a){this.clipText=a;this.ready&&this.movie.setText(a)},setCharSet:function(a){this.charSet=a;this.ready&&this.movie.setCharSet(a)},setBomInc:function(a){this.incBom=a;this.ready&&this.movie.setBomInc(a)},setFileName:function(a){this.fileName=a;this.ready&&this.movie.setFileName(a)},
setAction:function(a){this.action=a;this.ready&&this.movie.setAction(a)},addEventListener:function(a,b){a=a.toString().toLowerCase().replace(/^on/,"");this.handlers[a]||(this.handlers[a]=[]);this.handlers[a].push(b)},setHandCursor:function(a){this.handCursorEnabled=a;this.ready&&this.movie.setHandCursor(a)},setCSSEffects:function(a){this.cssEffects=!!a},receiveEvent:function(a,b){a=a.toString().toLowerCase().replace(/^on/,"");switch(a){case "load":this.movie=document.getElementById(this.movieId);
if(!this.movie){var c=this;setTimeout(function(){c.receiveEvent("load",null)},1);return}if(!this.ready&&navigator.userAgent.match(/Firefox/)&&navigator.userAgent.match(/Windows/)){c=this;setTimeout(function(){c.receiveEvent("load",null)},100);this.ready=!0;return}this.ready=!0;this.movie.clearText();this.movie.appendText(this.clipText);this.movie.setFileName(this.fileName);this.movie.setAction(this.action);this.movie.setCharSet(this.charSet);this.movie.setBomInc(this.incBom);this.movie.setHandCursor(this.handCursorEnabled);
break;case "mouseover":this.domElement&&this.cssEffects&&this.recoverActive&&this.domElement.addClass("active");break;case "mouseout":if(this.domElement&&this.cssEffects&&(this.recoverActive=!1,this.domElement.hasClass("active")))this.domElement.removeClass("active"),this.recoverActive=!0;break;case "mousedown":this.domElement&&this.cssEffects&&this.domElement.addClass("active");break;case "mouseup":if(this.domElement&&this.cssEffects)this.domElement.removeClass("active"),this.recoverActive=!1}if(this.handlers[a])for(var d=
0,e=this.handlers[a].length;d<e;d++){var f=this.handlers[a][d];if("function"==typeof f)f(this,b);else if("object"==typeof f&&2==f.length)f[0][f[1]](this,b);else if("string"==typeof f)window[f](this,b)}}};
/*
* File: TableTools.min.js
* Version: 2.0.2
* Author: Allan Jardine (www.sprymedia.co.uk)
*
* Copyright 2009-2011 Allan Jardine, all rights reserved.
*
* This source file is free software, under either the GPL v2 license or a
* BSD (3 point) style license, as supplied with this software.
*
* This source file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
*/
var TableTools;
(function(e,n,h){TableTools=function(a,b){(!this.CLASS||"TableTools"!=this.CLASS)&&alert("Warning: TableTools must be initialised with the keyword 'new'");this.s={that:this,dt:null,print:{saveStart:-1,saveLength:-1,saveScroll:-1,funcEnd:function(){}},buttonCounter:0,select:{type:"",selected:[],preRowSelect:null,postSelected:null,postDeselected:null,all:!1,selectedClass:""},custom:{},swfPath:"",buttonSet:[],master:!1};this.dom={container:null,table:null,print:{hidden:[],message:null},collection:{collection:null,
background:null}};this.fnSettings=function(){return this.s};"undefined"==typeof b&&(b={});this.s.dt=a.fnSettings();this._fnConstruct(b);return this};TableTools.prototype={fnGetSelected:function(){return this._fnGetMasterSettings().select.selected},fnGetSelectedData:function(){for(var a=this._fnGetMasterSettings().select.selected,b=[],c=0,d=a.length;c<d;c++)b.push(this.s.dt.oInstance.fnGetData(a[c]));return b},fnIsSelected:function(a){for(var b=this.fnGetSelected(),c=0,d=b.length;c<d;c++)if(a==b[c])return!0;
return!1},fnSelectAll:function(){this._fnGetMasterSettings().that._fnRowSelectAll()},fnSelectNone:function(){this._fnGetMasterSettings().that._fnRowDeselectAll()},fnSelect:function(a){this.fnIsSelected(a)||("single"==this.s.select.type?this._fnRowSelectSingle(a):"multi"==this.s.select.type&&this._fnRowSelectMulti(a))},fnDeselect:function(a){this.fnIsSelected(a)&&("single"==this.s.select.type?this._fnRowSelectSingle(a):"multi"==this.s.select.type&&this._fnRowSelectMulti(a))},fnGetTitle:function(a){var b=
"";if("undefined"!=typeof a.sTitle&&""!==a.sTitle)b=a.sTitle;else if(a=h.getElementsByTagName("title"),0<a.length)b=a[0].innerHTML;return 4>"\u00a1".toString().length?b.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g,""):b.replace(/[^a-zA-Z0-9_\.,\-_ !\(\)]/g,"")},fnCalcColRatios:function(a){var b=this.s.dt.aoColumns,a=this._fnColumnTargets(a.mColumns),c=[],d=0,e=0,f,g;for(f=0,g=a.length;f<g;f++)if(a[f])d=b[f].nTh.offsetWidth,e+=d,c.push(d);for(f=0,g=c.length;f<g;f++)c[f]/=e;return c.join("\t")},
fnGetTableData:function(a){if(this.s.dt)return this._fnGetDataTablesData(a)},fnSetText:function(a,b){this._fnFlashSetText(a,b)},fnResizeButtons:function(){for(var a in ZeroClipboard.clients)if(a){var b=ZeroClipboard.clients[a];"undefined"!=typeof b.domElement&&b.domElement.parentNode==this.dom.container&&b.positionElement()}},fnResizeRequired:function(){for(var a in ZeroClipboard.clients)if(a){var b=ZeroClipboard.clients[a];if("undefined"!=typeof b.domElement&&b.domElement.parentNode==this.dom.container&&
!1===b.sized)return!0}return!1},_fnConstruct:function(a){var b=this;this._fnCustomiseSettings(a);this.dom.container=h.createElement("div");this.dom.container.className=!this.s.dt.bJUI?"DTTT_container":"DTTT_container ui-buttonset ui-buttonset-multi";"none"!=this.s.select.type&&this._fnRowSelectConfig();this._fnButtonDefinations(this.s.buttonSet,this.dom.container);this.s.dt.aoDestroyCallback.push({sName:"TableTools",fn:function(){b.dom.container.innerHTML=""}})},_fnCustomiseSettings:function(a){if("undefined"==
typeof this.s.dt._TableToolsInit)this.s.master=!0,this.s.dt._TableToolsInit=!0;this.dom.table=this.s.dt.nTable;this.s.custom=e.extend({},TableTools.DEFAULTS,a);this.s.swfPath=this.s.custom.sSwfPath;if("undefined"!=typeof ZeroClipboard)ZeroClipboard.moviePath=this.s.swfPath;this.s.select.type=this.s.custom.sRowSelect;this.s.select.preRowSelect=this.s.custom.fnPreRowSelect;this.s.select.postSelected=this.s.custom.fnRowSelected;this.s.select.postDeselected=this.s.custom.fnRowDeselected;this.s.select.selectedClass=
this.s.custom.sSelectedClass;this.s.buttonSet=this.s.custom.aButtons},_fnButtonDefinations:function(a,b){for(var c,d=0,j=a.length;d<j;d++){if("string"==typeof a[d]){if("undefined"==typeof TableTools.BUTTONS[a[d]]){alert("TableTools: Warning - unknown button type: "+a[d]);continue}c=e.extend({},TableTools.BUTTONS[a[d]],!0)}else{if("undefined"==typeof TableTools.BUTTONS[a[d].sExtends]){alert("TableTools: Warning - unknown button type: "+a[d].sExtends);continue}c=e.extend({},TableTools.BUTTONS[a[d].sExtends],
!0);c=e.extend(c,a[d],!0)}this.s.dt.bJUI&&(c.sButtonClass+=" ui-button ui-state-default",c.sButtonClassHover+=" ui-state-hover");b.appendChild(this._fnCreateButton(c))}},_fnCreateButton:function(a){var b="div"==a.sAction?this._fnDivBase(a):this._fnButtonBase(a);"print"==a.sAction?this._fnPrintConfig(b,a):a.sAction.match(/flash/)?this._fnFlashConfig(b,a):"text"==a.sAction?this._fnTextConfig(b,a):"div"==a.sAction?this._fnTextConfig(b,a):"collection"==a.sAction&&(this._fnTextConfig(b,a),this._fnCollectionConfig(b,
a));return b},_fnButtonBase:function(a){var b=h.createElement("button"),c=h.createElement("span"),d=this._fnGetMasterSettings();b.className="DTTT_button "+a.sButtonClass;b.setAttribute("id","ToolTables_"+this.s.dt.sInstance+"_"+d.buttonCounter);b.appendChild(c);c.innerHTML=a.sButtonText;d.buttonCounter++;return b},_fnDivBase:function(a){var b=h.createElement("div"),c=this._fnGetMasterSettings();b.className=a.sButtonClass;b.setAttribute("id","ToolTables_"+this.s.dt.sInstance+"_"+c.buttonCounter);b.innerHTML=
a.sButtonText;null!==a.nContent&&b.appendChild(a.nContent);c.buttonCounter++;return b},_fnGetMasterSettings:function(){if(this.s.master)return this.s;for(var a=TableTools._aInstances,b=0,c=a.length;b<c;b++)if(this.dom.table==a[b].s.dt.nTable)return a[b].s},_fnCollectionConfig:function(a,b){var c=h.createElement("div");c.style.display="none";c.className=!this.s.dt.bJUI?"DTTT_collection":"DTTT_collection ui-buttonset ui-buttonset-multi";b._collection=c;this._fnButtonDefinations(b.aButtons,c)},_fnCollectionShow:function(a,
b){var c=this,d=e(a).offset(),j=b._collection,f=d.left,d=d.top+e(a).outerHeight(),g=e(n).height(),l=e(h).height(),m=e(n).width(),o=e(h).width();j.style.position="absolute";j.style.left=f+"px";j.style.top=d+"px";j.style.display="block";e(j).css("opacity",0);var k=h.createElement("div");k.style.position="absolute";k.style.left="0px";k.style.top="0px";k.style.height=(g>l?g:l)+"px";k.style.width=(m>o?m:o)+"px";k.className="DTTT_collection_background";e(k).css("opacity",0);h.body.appendChild(k);h.body.appendChild(j);
g=e(j).outerWidth();m=e(j).outerHeight();if(f+g>o)j.style.left=o-g+"px";if(d+m>l)j.style.top=d-m-e(a).outerHeight()+"px";this.dom.collection.collection=j;this.dom.collection.background=k;setTimeout(function(){e(j).animate({opacity:1},500);e(k).animate({opacity:0.25},500)},10);e(k).click(function(){c._fnCollectionHide.call(c,null,null)})},_fnCollectionHide:function(a,b){if(!(null!==b&&"collection"==b.sExtends)&&null!==this.dom.collection.collection)e(this.dom.collection.collection).animate({opacity:0},
500,function(){this.style.display="none"}),e(this.dom.collection.background).animate({opacity:0},500,function(){this.parentNode.removeChild(this)}),this.dom.collection.collection=null,this.dom.collection.background=null},_fnRowSelectConfig:function(){if(this.s.master){var a=this;e(a.s.dt.nTable).addClass("DTTT_selectable");e("tr",a.s.dt.nTBody).live("click",function(b){if(this.parentNode==a.s.dt.nTBody){var c=a.s.dt.oInstance.fnGetNodes();-1===e.inArray(this,c)||null!==a.s.select.preRowSelect&&!a.s.select.preRowSelect.call(a,
b)||("single"==a.s.select.type?a._fnRowSelectSingle.call(a,this):a._fnRowSelectMulti.call(a,this))}});a.s.dt.aoDrawCallback.push({fn:function(){a.s.select.all&&a.s.dt.oFeatures.bServerSide&&a.fnSelectAll()},sName:"TableTools_select"})}},_fnRowSelectSingle:function(a){this.s.master&&!e("td",a).hasClass(this.s.dt.oClasses.sRowEmpty)&&(e(a).hasClass(this.s.select.selectedClass)?this._fnRowDeselect(a):(0!==this.s.select.selected.length&&this._fnRowDeselectAll(),this.s.select.selected.push(a),e(a).addClass(this.s.select.selectedClass),
null!==this.s.select.postSelected&&this.s.select.postSelected.call(this,a)),TableTools._fnEventDispatch(this,"select",a))},_fnRowSelectMulti:function(a){this.s.master&&!e("td",a).hasClass(this.s.dt.oClasses.sRowEmpty)&&(e(a).hasClass(this.s.select.selectedClass)?this._fnRowDeselect(a):(this.s.select.selected.push(a),e(a).addClass(this.s.select.selectedClass),null!==this.s.select.postSelected&&this.s.select.postSelected.call(this,a)),TableTools._fnEventDispatch(this,"select",a))},_fnRowSelectAll:function(){if(this.s.master){for(var a,
b=0,c=this.s.dt.aiDisplayMaster.length;b<c;b++)a=this.s.dt.aoData[this.s.dt.aiDisplayMaster[b]].nTr,e(a).hasClass(this.s.select.selectedClass)||(this.s.select.selected.push(a),e(a).addClass(this.s.select.selectedClass));null!==this.s.select.postSelected&&this.s.select.postSelected.call(this,null);this.s.select.all=!0;TableTools._fnEventDispatch(this,"select",null)}},_fnRowDeselectAll:function(){if(this.s.master){for(var a=this.s.select.selected.length-1;0<=a;a--)this._fnRowDeselect(a,!1);null!==this.s.select.postDeselected&&
this.s.select.postDeselected.call(this,null);this.s.select.all=!1;TableTools._fnEventDispatch(this,"select",null)}},_fnRowDeselect:function(a,b){"undefined"!=typeof a.nodeName&&(a=e.inArray(a,this.s.select.selected));var c=this.s.select.selected[a];e(c).removeClass(this.s.select.selectedClass);this.s.select.selected.splice(a,1);("undefined"==typeof b||b)&&null!==this.s.select.postDeselected&&this.s.select.postDeselected.call(this,c);this.s.select.all=!1},_fnTextConfig:function(a,b){var c=this;null!==
b.fnInit&&b.fnInit.call(this,a,b);if(""!==b.sToolTip)a.title=b.sToolTip;e(a).hover(function(){e(a).addClass(b.sButtonClassHover);null!==b.fnMouseover&&b.fnMouseover.call(this,a,b,null)},function(){e(a).removeClass(b.sButtonClassHover);null!==b.fnMouseout&&b.fnMouseout.call(this,a,b,null)});null!==b.fnSelect&&TableTools._fnEventListen(this,"select",function(d){b.fnSelect.call(c,a,b,d)});e(a).click(function(d){d.preventDefault();null!==b.fnClick&&b.fnClick.call(c,a,b,null);null!==b.fnComplete&&b.fnComplete.call(c,
a,b,null,null);c._fnCollectionHide(a,b)})},_fnFlashConfig:function(a,b){var c=this,d=new ZeroClipboard.Client;null!==b.fnInit&&b.fnInit.call(this,a,b);d.setHandCursor(!0);"flash_save"==b.sAction?(d.setAction("save"),d.setCharSet("utf16le"==b.sCharSet?"UTF16LE":"UTF8"),d.setBomInc(b.bBomInc),d.setFileName(b.sFileName.replace("*",this.fnGetTitle(b)))):"flash_pdf"==b.sAction?(d.setAction("pdf"),d.setFileName(b.sFileName.replace("*",this.fnGetTitle(b)))):d.setAction("copy");d.addEventListener("mouseOver",
function(){e(a).addClass(b.sButtonClassHover);null!==b.fnMouseover&&b.fnMouseover.call(c,a,b,d)});d.addEventListener("mouseOut",function(){e(a).removeClass(b.sButtonClassHover);null!==b.fnMouseout&&b.fnMouseout.call(c,a,b,d)});d.addEventListener("mouseDown",function(){null!==b.fnClick&&b.fnClick.call(c,a,b,d)});d.addEventListener("complete",function(e,f){null!==b.fnComplete&&b.fnComplete.call(c,a,b,d,f);c._fnCollectionHide(a,b)});this._fnFlashGlue(d,a,b.sToolTip)},_fnFlashGlue:function(a,b,c){var d=
this,e=b.getAttribute("id");if(h.getElementById(e)){if(a.glue(b,c),a.domElement.parentNode!=a.div.parentNode&&"undefined"==typeof d.__bZCWarning)d.s.dt.oApi._fnLog(this.s.dt,0,"It looks like you are using the version of ZeroClipboard which came with TableTools 1. Please update to use the version that came with TableTools 2."),d.__bZCWarning=!0}else setTimeout(function(){d._fnFlashGlue(a,b,c)},100)},_fnFlashSetText:function(a,b){var c=this._fnChunkData(b,8192);a.clearText();for(var d=0,e=c.length;d<
e;d++)a.appendText(c[d])},_fnColumnTargets:function(a){var b=[],c=this.s.dt;if("object"==typeof a){for(i=0,iLen=c.aoColumns.length;i<iLen;i++)b.push(!1);for(i=0,iLen=a.length;i<iLen;i++)b[a[i]]=!0}else if("visible"==a)for(i=0,iLen=c.aoColumns.length;i<iLen;i++)b.push(c.aoColumns[i].bVisible?!0:!1);else if("hidden"==a)for(i=0,iLen=c.aoColumns.length;i<iLen;i++)b.push(c.aoColumns[i].bVisible?!1:!0);else if("sortable"==a)for(i=0,iLen=c.aoColumns.length;i<iLen;i++)b.push(c.aoColumns[i].bSortable?!0:!1);
else for(i=0,iLen=c.aoColumns.length;i<iLen;i++)b.push(!0);return b},_fnNewline:function(a){return"auto"==a.sNewLine?navigator.userAgent.match(/Windows/)?"\r\n":"\n":a.sNewLine},_fnGetDataTablesData:function(a){var b,c,d,j,f="",g="",h=this.s.dt,m=RegExp(a.sFieldBoundary,"g"),o=this._fnColumnTargets(a.mColumns),k=this._fnNewline(a),n="undefined"!=typeof a.bSelectedOnly?a.bSelectedOnly:!1;if(a.bHeader){for(b=0,c=h.aoColumns.length;b<c;b++)o[b]&&(g=h.aoColumns[b].sTitle.replace(/\n/g," ").replace(/<.*?>/g,
"").replace(/^\s+|\s+$/g,""),g=this._fnHtmlDecode(g),f+=this._fnBoundData(g,a.sFieldBoundary,m)+a.sFieldSeperator);f=f.slice(0,-1*a.sFieldSeperator.length);f+=k}for(d=0,j=h.aiDisplay.length;d<j;d++)if("none"==this.s.select.type||n&&e(h.aoData[h.aiDisplay[d]].nTr).hasClass(this.s.select.selectedClass)||n&&0==this.s.select.selected.length){for(b=0,c=h.aoColumns.length;b<c;b++)o[b]&&(g=h.oApi._fnGetCellData(h,h.aiDisplay[d],b,"display"),a.fnCellRender?g=a.fnCellRender(g,b)+"":"string"==typeof g?(g=g.replace(/\n/g,
" "),g=g.replace(/<img.*?\s+alt\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+)).*?>/gi,"$1$2$3"),g=g.replace(/<.*?>/g,"")):g+="",g=g.replace(/^\s+/,"").replace(/\s+$/,""),g=this._fnHtmlDecode(g),f+=this._fnBoundData(g,a.sFieldBoundary,m)+a.sFieldSeperator);f=f.slice(0,-1*a.sFieldSeperator.length);f+=k}f.slice(0,-1);if(a.bFooter){for(b=0,c=h.aoColumns.length;b<c;b++)o[b]&&null!==h.aoColumns[b].nTf&&(g=h.aoColumns[b].nTf.innerHTML.replace(/\n/g," ").replace(/<.*?>/g,""),g=this._fnHtmlDecode(g),f+=this._fnBoundData(g,
a.sFieldBoundary,m)+a.sFieldSeperator);f=f.slice(0,-1*a.sFieldSeperator.length)}return _sLastData=f},_fnBoundData:function(a,b,c){return""===b?a:b+a.replace(c,b+b)+b},_fnChunkData:function(a,b){for(var c=[],d=a.length,e=0;e<d;e+=b)e+b<d?c.push(a.substring(e,e+b)):c.push(a.substring(e,d));return c},_fnHtmlDecode:function(a){if(-1==a.indexOf("&"))return a;var a=this._fnChunkData(a,2048),b=h.createElement("div"),c,d,e,f="";for(c=0,d=a.length;c<d;c++)e=a[c].lastIndexOf("&"),-1!=e&&8<=a[c].length&&e>a[c].length-
8&&(a[c].substr(e),a[c]=a[c].substr(0,e)),b.innerHTML=a[c],f+=b.childNodes[0].nodeValue;return f},_fnPrintConfig:function(a,b){var c=this;null!==b.fnInit&&b.fnInit.call(this,a,b);if(""!==b.sToolTip)a.title=b.sToolTip;e(a).hover(function(){e(a).addClass(b.sButtonClassHover)},function(){e(a).removeClass(b.sButtonClassHover)});null!==b.fnSelect&&TableTools._fnEventListen(this,"select",function(d){b.fnSelect.call(c,a,b,d)});e(a).click(function(d){d.preventDefault();c._fnPrintStart.call(c,d,b);null!==
b.fnClick&&b.fnClick.call(c,a,b,null);null!==b.fnComplete&&b.fnComplete.call(c,a,b,null,null);c._fnCollectionHide(a,b)})},_fnPrintStart:function(a,b){var c=this,d=this.s.dt;this._fnPrintHideNodes(d.nTable);this.s.print.saveStart=d._iDisplayStart;this.s.print.saveLength=d._iDisplayLength;if(b.bShowAll)d._iDisplayStart=0,d._iDisplayLength=-1,d.oApi._fnCalculateEnd(d),d.oApi._fnDraw(d);(""!==d.oScroll.sX||""!==d.oScroll.sY)&&this._fnPrintScrollStart(d);var d=d.aanFeatures,j;for(j in d)if("i"!=j&&"t"!=
j&&1==j.length)for(var f=0,g=d[j].length;f<g;f++)this.dom.print.hidden.push({node:d[j][f],display:"block"}),d[j][f].style.display="none";e(h.body).addClass("DTTT_Print");if(""!==b.sInfo){var l=h.createElement("div");l.className="DTTT_print_info";l.innerHTML=b.sInfo;h.body.appendChild(l);setTimeout(function(){e(l).fadeOut("normal",function(){h.body.removeChild(l)})},2E3)}if(""!==b.sMessage)this.dom.print.message=h.createElement("div"),this.dom.print.message.className="DTTT_PrintMessage",this.dom.print.message.innerHTML=
b.sMessage,h.body.insertBefore(this.dom.print.message,h.body.childNodes[0]);this.s.print.saveScroll=e(n).scrollTop();n.scrollTo(0,0);this.s.print.funcEnd=function(a){c._fnPrintEnd.call(c,a)};e(h).bind("keydown",null,this.s.print.funcEnd)},_fnPrintEnd:function(a){if(27==a.keyCode){a.preventDefault();var a=this.s.dt,b=this.s.print,c=this.dom.print;this._fnPrintShowNodes();(""!==a.oScroll.sX||""!==a.oScroll.sY)&&this._fnPrintScrollEnd();n.scrollTo(0,b.saveScroll);if(null!==c.message)h.body.removeChild(c.message),
c.message=null;e(h.body).removeClass("DTTT_Print");a._iDisplayStart=b.saveStart;a._iDisplayLength=b.saveLength;a.oApi._fnCalculateEnd(a);a.oApi._fnDraw(a);e(h).unbind("keydown",this.s.print.funcEnd);this.s.print.funcEnd=null}},_fnPrintScrollStart:function(){var a=this.s.dt;a.nScrollHead.getElementsByTagName("div")[0].getElementsByTagName("table");var b=a.nTable.parentNode,c=a.nTable.getElementsByTagName("thead");0<c.length&&a.nTable.removeChild(c[0]);null!==a.nTFoot&&(c=a.nTable.getElementsByTagName("tfoot"),
0<c.length&&a.nTable.removeChild(c[0]));c=a.nTHead.cloneNode(!0);a.nTable.insertBefore(c,a.nTable.childNodes[0]);null!==a.nTFoot&&(c=a.nTFoot.cloneNode(!0),a.nTable.insertBefore(c,a.nTable.childNodes[1]));if(""!==a.oScroll.sX)a.nTable.style.width=e(a.nTable).outerWidth()+"px",b.style.width=e(a.nTable).outerWidth()+"px",b.style.overflow="visible";if(""!==a.oScroll.sY)b.style.height=e(a.nTable).outerHeight()+"px",b.style.overflow="visible"},_fnPrintScrollEnd:function(){var a=this.s.dt,b=a.nTable.parentNode;
if(""!==a.oScroll.sX)b.style.width=a.oApi._fnStringToCss(a.oScroll.sX),b.style.overflow="auto";if(""!==a.oScroll.sY)b.style.height=a.oApi._fnStringToCss(a.oScroll.sY),b.style.overflow="auto"},_fnPrintShowNodes:function(){for(var a=this.dom.print.hidden,b=0,c=a.length;b<c;b++)a[b].node.style.display=a[b].display;a.splice(0,a.length)},_fnPrintHideNodes:function(a){for(var b=this.dom.print.hidden,c=a.parentNode,d=c.childNodes,j=0,f=d.length;j<f;j++)if(d[j]!=a&&1==d[j].nodeType){var g=e(d[j]).css("display");
if("none"!=g)b.push({node:d[j],display:g}),d[j].style.display="none"}"BODY"!=c.nodeName&&this._fnPrintHideNodes(c)}};TableTools._aInstances=[];TableTools._aListeners=[];TableTools.fnGetMasters=function(){for(var a=[],b=0,c=TableTools._aInstances.length;b<c;b++)TableTools._aInstances[b].s.master&&a.push(TableTools._aInstances[b]);return a};TableTools.fnGetInstance=function(a){"object"!=typeof a&&(a=h.getElementById(a));for(var b=0,c=TableTools._aInstances.length;b<c;b++)if(TableTools._aInstances[b].s.master&&
TableTools._aInstances[b].dom.table==a)return TableTools._aInstances[b];return null};TableTools._fnEventListen=function(a,b,c){TableTools._aListeners.push({that:a,type:b,fn:c})};TableTools._fnEventDispatch=function(a,b,c){for(var d=TableTools._aListeners,e=0,f=d.length;e<f;e++)a.dom.table==d[e].that.dom.table&&d[e].type==b&&d[e].fn(c)};TableTools.BUTTONS={csv:{sAction:"flash_save",sCharSet:"utf8",bBomInc:!1,sFileName:"*.csv",sFieldBoundary:'"',sFieldSeperator:",",sNewLine:"auto",sTitle:"",sToolTip:"",
sButtonClass:"DTTT_button_csv",sButtonClassHover:"DTTT_button_csv_hover",sButtonText:"CSV",mColumns:"all",bHeader:!0,bFooter:!0,bSelectedOnly:!1,fnMouseover:null,fnMouseout:null,fnClick:function(a,b,c){this.fnSetText(c,this.fnGetTableData(b))},fnSelect:null,fnComplete:null,fnInit:null,fnCellRender:null},xls:{sAction:"flash_save",sCharSet:"utf16le",bBomInc:!0,sFileName:"*.csv",sFieldBoundary:"",sFieldSeperator:"\t",sNewLine:"auto",sTitle:"",sToolTip:"",sButtonClass:"DTTT_button_xls",sButtonClassHover:"DTTT_button_xls_hover",
sButtonText:"Excel",mColumns:"all",bHeader:!0,bFooter:!0,bSelectedOnly:!1,fnMouseover:null,fnMouseout:null,fnClick:function(a,b,c){this.fnSetText(c,this.fnGetTableData(b))},fnSelect:null,fnComplete:null,fnInit:null,fnCellRender:null},copy:{sAction:"flash_copy",sFieldBoundary:"",sFieldSeperator:"\t",sNewLine:"auto",sToolTip:"",sButtonClass:"DTTT_button_copy",sButtonClassHover:"DTTT_button_copy_hover",sButtonText:"Copy",mColumns:"all",bHeader:!0,bFooter:!0,bSelectedOnly:!1,fnMouseover:null,fnMouseout:null,
fnClick:function(a,b,c){this.fnSetText(c,this.fnGetTableData(b))},fnSelect:null,fnComplete:function(a,b,c,d){a=d.split("\n").length;a=null===this.s.dt.nTFoot?a-1:a-2;alert("Copied "+a+" row"+(1==a?"":"s")+" to the clipboard")},fnInit:null,fnCellRender:null},pdf:{sAction:"flash_pdf",sFieldBoundary:"",sFieldSeperator:"\t",sNewLine:"\n",sFileName:"*.pdf",sToolTip:"",sTitle:"",sButtonClass:"DTTT_button_pdf",sButtonClassHover:"DTTT_button_pdf_hover",sButtonText:"PDF",mColumns:"all",bHeader:!0,bFooter:!1,
bSelectedOnly:!1,fnMouseover:null,fnMouseout:null,sPdfOrientation:"portrait",sPdfSize:"A4",sPdfMessage:"",fnClick:function(a,b,c){this.fnSetText(c,"title:"+this.fnGetTitle(b)+"\nmessage:"+b.sPdfMessage+"\ncolWidth:"+this.fnCalcColRatios(b)+"\norientation:"+b.sPdfOrientation+"\nsize:"+b.sPdfSize+"\n--/TableToolsOpts--\n"+this.fnGetTableData(b))},fnSelect:null,fnComplete:null,fnInit:null,fnCellRender:null},print:{sAction:"print",sInfo:"<h6>Print view</h6><p>Please use your browser's print function to print this table. Press escape when finished.",
sMessage:"",bShowAll:!0,sToolTip:"View print view",sButtonClass:"DTTT_button_print",sButtonClassHover:"DTTT_button_print_hover",sButtonText:"Print",fnMouseover:null,fnMouseout:null,fnClick:null,fnSelect:null,fnComplete:null,fnInit:null,fnCellRender:null},text:{sAction:"text",sToolTip:"",sButtonClass:"DTTT_button_text",sButtonClassHover:"DTTT_button_text_hover",sButtonText:"Text button",mColumns:"all",bHeader:!0,bFooter:!0,bSelectedOnly:!1,fnMouseover:null,fnMouseout:null,fnClick:null,fnSelect:null,
fnComplete:null,fnInit:null,fnCellRender:null},select:{sAction:"text",sToolTip:"",sButtonClass:"DTTT_button_text",sButtonClassHover:"DTTT_button_text_hover",sButtonText:"Select button",mColumns:"all",bHeader:!0,bFooter:!0,fnMouseover:null,fnMouseout:null,fnClick:null,fnSelect:function(a){0!==this.fnGetSelected().length?e(a).removeClass("DTTT_disabled"):e(a).addClass("DTTT_disabled")},fnComplete:null,fnInit:function(a){e(a).addClass("DTTT_disabled")},fnCellRender:null},select_single:{sAction:"text",
sToolTip:"",sButtonClass:"DTTT_button_text",sButtonClassHover:"DTTT_button_text_hover",sButtonText:"Select button",mColumns:"all",bHeader:!0,bFooter:!0,fnMouseover:null,fnMouseout:null,fnClick:null,fnSelect:function(a){1==this.fnGetSelected().length?e(a).removeClass("DTTT_disabled"):e(a).addClass("DTTT_disabled")},fnComplete:null,fnInit:function(a){e(a).addClass("DTTT_disabled")},fnCellRender:null},select_all:{sAction:"text",sToolTip:"",sButtonClass:"DTTT_button_text",sButtonClassHover:"DTTT_button_text_hover",
sButtonText:"Select all",mColumns:"all",bHeader:!0,bFooter:!0,fnMouseover:null,fnMouseout:null,fnClick:function(){this.fnSelectAll()},fnSelect:function(a){this.fnGetSelected().length==this.s.dt.fnRecordsDisplay()?e(a).addClass("DTTT_disabled"):e(a).removeClass("DTTT_disabled")},fnComplete:null,fnInit:null,fnCellRender:null},select_none:{sAction:"text",sToolTip:"",sButtonClass:"DTTT_button_text",sButtonClassHover:"DTTT_button_text_hover",sButtonText:"Deselect all",mColumns:"all",bHeader:!0,bFooter:!0,
fnMouseover:null,fnMouseout:null,fnClick:function(){this.fnSelectNone()},fnSelect:function(a){0!==this.fnGetSelected().length?e(a).removeClass("DTTT_disabled"):e(a).addClass("DTTT_disabled")},fnComplete:null,fnInit:function(a){e(a).addClass("DTTT_disabled")},fnCellRender:null},ajax:{sAction:"text",sFieldBoundary:"",sFieldSeperator:"\t",sNewLine:"\n",sAjaxUrl:"/xhr.php",sToolTip:"",sButtonClass:"DTTT_button_text",sButtonClassHover:"DTTT_button_text_hover",sButtonText:"Ajax button",mColumns:"all",bHeader:!0,
bFooter:!0,bSelectedOnly:!1,fnMouseover:null,fnMouseout:null,fnClick:function(a,b){var c=this.fnGetTableData(b);e.ajax({url:b.sAjaxUrl,data:[{name:"tableData",value:c}],success:b.fnAjaxComplete,dataType:"json",type:"POST",cache:!1,error:function(){alert("Error detected when sending table data to server")}})},fnSelect:null,fnComplete:null,fnInit:null,fnAjaxComplete:function(){alert("Ajax complete")},fnCellRender:null},div:{sAction:"div",sToolTip:"",sButtonClass:"DTTT_nonbutton",sButtonClassHover:"",
sButtonText:"Text button",fnMouseover:null,fnMouseout:null,fnClick:null,fnSelect:null,fnComplete:null,fnInit:null,nContent:null,fnCellRender:null},collection:{sAction:"collection",sToolTip:"",sButtonClass:"DTTT_button_collection",sButtonClassHover:"DTTT_button_collection_hover",sButtonText:"Collection",fnMouseover:null,fnMouseout:null,fnClick:function(a,b){this._fnCollectionShow(a,b)},fnSelect:null,fnComplete:null,fnInit:null,fnCellRender:null}};TableTools.DEFAULTS={sSwfPath:"media/swf/copy_cvs_xls_pdf.swf",
sRowSelect:"none",sSelectedClass:"DTTT_selected",fnPreRowSelect:null,fnRowSelected:null,fnRowDeselected:null,aButtons:["copy","csv","xls","pdf","print"]};TableTools.prototype.CLASS="TableTools";TableTools.VERSION="2.0.2";TableTools.prototype.VERSION=TableTools.VERSION;"function"==typeof e.fn.dataTable&&"function"==typeof e.fn.dataTableExt.fnVersionCheck&&e.fn.dataTableExt.fnVersionCheck("1.8.2")?e.fn.dataTableExt.aoFeatures.push({fnInit:function(a){a=new TableTools(a.oInstance,"undefined"!=typeof a.oInit.oTableTools?
a.oInit.oTableTools:{});TableTools._aInstances.push(a);return a.dom.container},cFeature:"T",sFeature:"TableTools"}):alert("Warning: TableTools 2 requires DataTables 1.8.2 or newer - www.datatables.net/download")})(jQuery,window,document);

View File

@ -0,0 +1,367 @@
// Simple Set Clipboard System
// Author: Joseph Huckaby
var ZeroClipboard = {
version: "1.0.4-TableTools2",
clients: {}, // registered upload clients on page, indexed by id
moviePath: '', // URL to movie
nextId: 1, // ID of next movie
$: function(thingy) {
// simple DOM lookup utility function
if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
if (!thingy.addClass) {
// extend element with a few useful methods
thingy.hide = function() { this.style.display = 'none'; };
thingy.show = function() { this.style.display = ''; };
thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
thingy.removeClass = function(name) {
this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
};
thingy.hasClass = function(name) {
return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
}
}
return thingy;
},
setMoviePath: function(path) {
// set path to ZeroClipboard.swf
this.moviePath = path;
},
dispatch: function(id, eventName, args) {
// receive event from flash movie, send to client
var client = this.clients[id];
if (client) {
client.receiveEvent(eventName, args);
}
},
register: function(id, client) {
// register new client to receive events
this.clients[id] = client;
},
getDOMObjectPosition: function(obj) {
// get absolute coordinates for dom element
var info = {
left: 0,
top: 0,
width: obj.width ? obj.width : obj.offsetWidth,
height: obj.height ? obj.height : obj.offsetHeight
};
if ( obj.style.width != "" )
info.width = obj.style.width.replace("px","");
if ( obj.style.height != "" )
info.height = obj.style.height.replace("px","");
while (obj) {
info.left += obj.offsetLeft;
info.top += obj.offsetTop;
obj = obj.offsetParent;
}
return info;
},
Client: function(elem) {
// constructor for new simple upload client
this.handlers = {};
// unique ID
this.id = ZeroClipboard.nextId++;
this.movieId = 'ZeroClipboardMovie_' + this.id;
// register client with singleton to receive flash events
ZeroClipboard.register(this.id, this);
// create movie
if (elem) this.glue(elem);
}
};
ZeroClipboard.Client.prototype = {
id: 0, // unique ID for us
ready: false, // whether movie is ready to receive events or not
movie: null, // reference to movie object
clipText: '', // text to copy to clipboard
fileName: '', // default file save name
action: 'copy', // action to perform
handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
cssEffects: true, // enable CSS mouse effects on dom container
handlers: null, // user event handlers
sized: false,
glue: function(elem, title) {
// glue to DOM element
// elem can be ID or actual DOM element object
this.domElement = ZeroClipboard.$(elem);
// float just above object, or zIndex 99 if dom element isn't set
var zIndex = 99;
if (this.domElement.style.zIndex) {
zIndex = parseInt(this.domElement.style.zIndex) + 1;
}
// find X/Y position of domElement
var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
// create floating DIV above element
this.div = document.createElement('div');
var style = this.div.style;
style.position = 'absolute';
style.left = (this.domElement.offsetLeft)+'px';
//style.left = (this.domElement.offsetLeft+2)+'px';
style.top = this.domElement.offsetTop+'px';
style.width = (box.width) + 'px';
//style.width = (box.width-4) + 'px';
style.height = box.height + 'px';
style.zIndex = zIndex;
if ( typeof title != "undefined" && title != "" ) {
this.div.title = title;
}
if ( box.width != 0 && box.height != 0 ) {
this.sized = true;
}
// style.backgroundColor = '#f00'; // debug
this.domElement.parentNode.appendChild(this.div);
this.div.innerHTML = this.getHTML( box.width, box.height );
},
positionElement: function() {
var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
var style = this.div.style;
style.position = 'absolute';
style.left = (this.domElement.offsetLeft)+'px';
style.top = this.domElement.offsetTop+'px';
style.width = box.width + 'px';
style.height = box.height + 'px';
if ( box.width != 0 && box.height != 0 ) {
this.sized = true;
} else {
return;
}
var flash = this.div.childNodes[0];
flash.width = box.width;
flash.height = box.height;
},
getHTML: function(width, height) {
// return HTML for movie
var html = '';
var flashvars = 'id=' + this.id +
'&width=' + width +
'&height=' + height;
if (navigator.userAgent.match(/MSIE/)) {
// IE gets an OBJECT tag
var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
html += '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
}
else {
// all other browsers get an EMBED tag
html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
}
return html;
},
hide: function() {
// temporarily hide floater offscreen
if (this.div) {
this.div.style.left = '-2000px';
}
},
show: function() {
// show ourselves after a call to hide()
this.reposition();
},
destroy: function() {
// destroy control and floater
if (this.domElement && this.div) {
this.hide();
this.div.innerHTML = '';
var body = document.getElementsByTagName('body')[0];
try { body.removeChild( this.div ); } catch(e) {;}
this.domElement = null;
this.div = null;
}
},
reposition: function(elem) {
// reposition our floating div, optionally to new container
// warning: container CANNOT change size, only position
if (elem) {
this.domElement = ZeroClipboard.$(elem);
if (!this.domElement) this.hide();
}
if (this.domElement && this.div) {
var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
var style = this.div.style;
style.left = '' + box.left + 'px';
style.top = '' + box.top + 'px';
}
},
clearText: function() {
// clear the text to be copy / saved
this.clipText = '';
if (this.ready) this.movie.clearText();
},
appendText: function(newText) {
// append text to that which is to be copied / saved
this.clipText += newText;
if (this.ready) { this.movie.appendText(newText) ;}
},
setText: function(newText) {
// set text to be copied to be copied / saved
this.clipText = newText;
if (this.ready) { this.movie.setText(newText) ;}
},
setCharSet: function(charSet) {
// set the character set (UTF16LE or UTF8)
this.charSet = charSet;
if (this.ready) { this.movie.setCharSet(charSet) ;}
},
setBomInc: function(bomInc) {
// set if the BOM should be included or not
this.incBom = bomInc;
if (this.ready) { this.movie.setBomInc(bomInc) ;}
},
setFileName: function(newText) {
// set the file name
this.fileName = newText;
if (this.ready) this.movie.setFileName(newText);
},
setAction: function(newText) {
// set action (save or copy)
this.action = newText;
if (this.ready) this.movie.setAction(newText);
},
addEventListener: function(eventName, func) {
// add user event listener for event
// event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
eventName = eventName.toString().toLowerCase().replace(/^on/, '');
if (!this.handlers[eventName]) this.handlers[eventName] = [];
this.handlers[eventName].push(func);
},
setHandCursor: function(enabled) {
// enable hand cursor (true), or default arrow cursor (false)
this.handCursorEnabled = enabled;
if (this.ready) this.movie.setHandCursor(enabled);
},
setCSSEffects: function(enabled) {
// enable or disable CSS effects on DOM container
this.cssEffects = !!enabled;
},
receiveEvent: function(eventName, args) {
// receive event from flash
eventName = eventName.toString().toLowerCase().replace(/^on/, '');
// special behavior for certain events
switch (eventName) {
case 'load':
// movie claims it is ready, but in IE this isn't always the case...
// bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
this.movie = document.getElementById(this.movieId);
if (!this.movie) {
var self = this;
setTimeout( function() { self.receiveEvent('load', null); }, 1 );
return;
}
// firefox on pc needs a "kick" in order to set these in certain cases
if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
var self = this;
setTimeout( function() { self.receiveEvent('load', null); }, 100 );
this.ready = true;
return;
}
this.ready = true;
this.movie.clearText();
this.movie.appendText( this.clipText );
this.movie.setFileName( this.fileName );
this.movie.setAction( this.action );
this.movie.setCharSet( this.charSet );
this.movie.setBomInc( this.incBom );
this.movie.setHandCursor( this.handCursorEnabled );
break;
case 'mouseover':
if (this.domElement && this.cssEffects) {
//this.domElement.addClass('hover');
if (this.recoverActive) this.domElement.addClass('active');
}
break;
case 'mouseout':
if (this.domElement && this.cssEffects) {
this.recoverActive = false;
if (this.domElement.hasClass('active')) {
this.domElement.removeClass('active');
this.recoverActive = true;
}
//this.domElement.removeClass('hover');
}
break;
case 'mousedown':
if (this.domElement && this.cssEffects) {
this.domElement.addClass('active');
}
break;
case 'mouseup':
if (this.domElement && this.cssEffects) {
this.domElement.removeClass('active');
this.recoverActive = false;
}
break;
} // switch eventName
if (this.handlers[eventName]) {
for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
var func = this.handlers[eventName][idx];
if (typeof(func) == 'function') {
// actual function reference
func(this, args);
}
else if ((typeof(func) == 'object') && (func.length == 2)) {
// PHP style object + method, i.e. [myObject, 'myMethod']
func[0][ func[1] ](this, args);
}
else if (typeof(func) == 'string') {
// name of function
window[func](this, args);
}
} // foreach event handler defined
} // user defined handler for event
}
};

View File

@ -104,6 +104,7 @@ class PypoPush(Thread):
track, so let's push it now so that Liquidsoap can start playing track, so let's push it now so that Liquidsoap can start playing
it immediately after (and prepare crossfades if need be). it immediately after (and prepare crossfades if need be).
""" """
self.logger.debug("Push track immediately.")
self.telnet_to_liquidsoap(media_item) self.telnet_to_liquidsoap(media_item)
self.last_end_time = media_item["end"] self.last_end_time = media_item["end"]
else: else:
@ -111,11 +112,13 @@ class PypoPush(Thread):
this media item does not start right after a current playing track. this media item does not start right after a current playing track.
We need to sleep, and then wake up when this track starts. We need to sleep, and then wake up when this track starts.
""" """
self.logger.debug("sleep until track start.")
self.sleep_until_start(media_item) self.sleep_until_start(media_item)
self.telnet_to_liquidsoap(media_item) self.telnet_to_liquidsoap(media_item)
self.last_end_time = media_item["end"] self.last_end_time = media_item["end"]
except Exception, e: except Exception, e:
self.logger.error('Pypo Push Exception: %s', e)
return False return False
return True return True