diff --git a/airtime_mvc/application/configs/ACL.php b/airtime_mvc/application/configs/ACL.php index f0bb211c8..d2ce2e23a 100644 --- a/airtime_mvc/application/configs/ACL.php +++ b/airtime_mvc/application/configs/ACL.php @@ -26,6 +26,7 @@ $ccAcl->add(new Zend_Acl_Resource('library')) ->add(new Zend_Acl_Resource('recorder')) ->add(new Zend_Acl_Resource('showbuilder')) ->add(new Zend_Acl_Resource('auth')) + ->add(new Zend_Acl_Resource('playouthistory')) ->add(new Zend_Acl_Resource('usersettings')); /** Creating permissions */ @@ -44,6 +45,7 @@ $ccAcl->allow('G', 'index') ->allow('H', 'search') ->allow('H', 'playlist') ->allow('H', 'showbuilder') + ->allow('A', 'playouthistory') ->allow('A', 'user') ->allow('A', 'systemstatus') ->allow('A', 'preference'); diff --git a/airtime_mvc/application/configs/navigation.php b/airtime_mvc/application/configs/navigation.php index 400a8b509..ef1ff8d66 100644 --- a/airtime_mvc/application/configs/navigation.php +++ b/airtime_mvc/application/configs/navigation.php @@ -11,9 +11,9 @@ $pages = array( array( 'label' => 'Now Playing', 'module' => 'default', - 'controller' => 'Nowplaying', + 'controller' => 'Showbuilder', 'action' => 'index', - 'resource' => 'nowplaying' + 'resource' => 'showbuilder' ), array( 'label' => 'Add Media', @@ -29,13 +29,6 @@ $pages = array( 'action' => 'index', 'resource' => 'library' ), - array( - 'label' => 'Airtimeline', - 'module' => 'default', - 'controller' => 'Showbuilder', - 'action' => 'index', - 'resource' => 'showbuilder' - ), array( 'label' => 'Calendar', 'module' => 'default', @@ -85,7 +78,14 @@ $pages = array( 'controller' => 'systemstatus', 'action' => 'index', 'resource' => 'systemstatus' - ) + ), + array( + 'label' => 'Playout History', + 'module' => 'default', + 'controller' => 'playouthistory', + 'action' => 'index', + 'resource' => 'playouthistory' + ) ) ), array( diff --git a/airtime_mvc/application/controllers/LibraryController.php b/airtime_mvc/application/controllers/LibraryController.php index 3b63d3ce3..e2cffe17e 100644 --- a/airtime_mvc/application/controllers/LibraryController.php +++ b/airtime_mvc/application/controllers/LibraryController.php @@ -29,9 +29,15 @@ class LibraryController extends Zend_Controller_Action public function indexAction() { + global $CC_CONFIG; + $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($baseUrl.'/js/airtime/library/main_library.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); $this->_helper->actionStack('library', 'library'); $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/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/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/jquery.contextMenu.css?'.$CC_CONFIG['airtime_version']); $this->view->headLink()->appendStylesheet($baseUrl.'/css/datatables/css/ColVis.css?'.$CC_CONFIG['airtime_version']); diff --git a/airtime_mvc/application/controllers/LoginController.php b/airtime_mvc/application/controllers/LoginController.php index 652dc4f42..5906ef814 100644 --- a/airtime_mvc/application/controllers/LoginController.php +++ b/airtime_mvc/application/controllers/LoginController.php @@ -68,7 +68,7 @@ class LoginController extends Zend_Controller_Action $tempSess = new Zend_Session_Namespace("referrer"); $tempSess->referrer = 'login'; - $this->_redirect('Nowplaying'); + $this->_redirect('Showbuilder'); } else { @@ -95,7 +95,7 @@ class LoginController extends Zend_Controller_Action public function logoutAction() { Zend_Auth::getInstance()->clearIdentity(); - $this->_redirect('login/index'); + $this->_redirect('showbuilder/index'); } } diff --git a/airtime_mvc/application/controllers/PlayouthistoryController.php b/airtime_mvc/application/controllers/PlayouthistoryController.php new file mode 100644 index 000000000..40bd16a72 --- /dev/null +++ b/airtime_mvc/application/controllers/PlayouthistoryController.php @@ -0,0 +1,87 @@ +_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"]; + } +} \ No newline at end of file diff --git a/airtime_mvc/application/controllers/ShowbuilderController.php b/airtime_mvc/application/controllers/ShowbuilderController.php index a32d15665..08edddcf0 100644 --- a/airtime_mvc/application/controllers/ShowbuilderController.php +++ b/airtime_mvc/application/controllers/ShowbuilderController.php @@ -10,6 +10,7 @@ class ShowbuilderController extends Zend_Controller_Action ->addActionContext('schedule-add', 'json') ->addActionContext('schedule-remove', 'json') ->addActionContext('builder-dialog', 'json') + ->addActionContext('check-builder-feed', 'json') ->addActionContext('builder-feed', 'json') ->initContext(); } @@ -17,10 +18,80 @@ class ShowbuilderController extends Zend_Controller_Action public function indexAction() { $this->_helper->layout->setLayout('builder'); - - $this->view->headScript()->appendFile($this->view->baseUrl('/js/airtime/library/events/library_showbuilder.js'),'text/javascript'); + $this->_helper->viewRenderer->setResponseSegment('dialog'); - $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'); } @@ -33,7 +104,7 @@ class ShowbuilderController extends Zend_Controller_Action $now = time(); $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->setTimezone(new DateTimeZone(date_default_timezone_get())); @@ -52,12 +123,12 @@ class ShowbuilderController extends Zend_Controller_Action $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/showbuilder/builder.js','text/javascript'); - $this->view->headScript()->appendFile($baseUrl.'/js/airtime/showbuilder/main_builder.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?'.$CC_CONFIG['airtime_version'],'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/showbuilder.css'); + $this->view->headLink()->appendStylesheet($baseUrl.'/css/jquery.ui.timepicker.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'/css/showbuilder.css?'.$CC_CONFIG['airtime_version']); } public function builderDialogAction() { @@ -88,6 +159,37 @@ class ShowbuilderController extends Zend_Controller_Action $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() { $request = $this->getRequest(); @@ -98,6 +200,7 @@ class ShowbuilderController extends Zend_Controller_Action $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")); @@ -109,6 +212,7 @@ class ShowbuilderController extends Zend_Controller_Action $showBuilder = new Application_Model_ShowBuilder($startsDT, $endsDT, $opts); $this->view->schedule = $showBuilder->GetItems(); + $this->view->timestamp = $current_time; } public function scheduleAddAction() { diff --git a/airtime_mvc/application/forms/DateRange.php b/airtime_mvc/application/forms/DateRange.php new file mode 100644 index 000000000..283367c73 --- /dev/null +++ b/airtime_mvc/application/forms/DateRange.php @@ -0,0 +1,68 @@ +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); + } +} \ No newline at end of file diff --git a/airtime_mvc/application/forms/ShowBuilder.php b/airtime_mvc/application/forms/ShowBuilder.php index dddc91ffa..0865a51a2 100644 --- a/airtime_mvc/application/forms/ShowBuilder.php +++ b/airtime_mvc/application/forms/ShowBuilder.php @@ -11,6 +11,12 @@ class Application_Form_ShowBuilder extends Zend_Form_SubForm 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 $startDate = new Zend_Form_Element_Text('sb_date_start'); $startDate->class = 'input_text'; diff --git a/airtime_mvc/application/layouts/scripts/builder.phtml b/airtime_mvc/application/layouts/scripts/builder.phtml index c90f2a277..d1d37a4f2 100644 --- a/airtime_mvc/application/layouts/scripts/builder.phtml +++ b/airtime_mvc/application/layouts/scripts/builder.phtml @@ -23,5 +23,8 @@
layout()->builder ?>
+ +layout()->dialog ?> + diff --git a/airtime_mvc/application/layouts/scripts/library.phtml b/airtime_mvc/application/layouts/scripts/library.phtml index 69c0dc544..d015fee03 100644 --- a/airtime_mvc/application/layouts/scripts/library.phtml +++ b/airtime_mvc/application/layouts/scripts/library.phtml @@ -23,7 +23,7 @@
layout()->library ?>
-
layout()->spl ?>
+
layout()->spl ?>
diff --git a/airtime_mvc/application/layouts/scripts/playouthistory.phtml b/airtime_mvc/application/layouts/scripts/playouthistory.phtml new file mode 100644 index 000000000..210bbeaa8 --- /dev/null +++ b/airtime_mvc/application/layouts/scripts/playouthistory.phtml @@ -0,0 +1,27 @@ +doctype() ?> + + + + headTitle() ?> + headScript() ?> + headLink() ?> + google_analytics)?$this->google_analytics:"" ?> + + + +
+ + versionNotify() ?> + partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?> + +navigation()->menu()->setPartial($partial); ?> + +navigation()->menu() ?> +
+ +
+
layout()->content ?>
+
+ + \ No newline at end of file diff --git a/airtime_mvc/application/models/Datatables.php b/airtime_mvc/application/models/Datatables.php new file mode 100644 index 000000000..0c01091b7 --- /dev/null +++ b/airtime_mvc/application/models/Datatables.php @@ -0,0 +1,109 @@ + 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 + ); + } +} \ No newline at end of file diff --git a/airtime_mvc/application/models/PlayoutHistory.php b/airtime_mvc/application/models/PlayoutHistory.php new file mode 100644 index 000000000..6918f9dd1 --- /dev/null +++ b/airtime_mvc/application/models/PlayoutHistory.php @@ -0,0 +1,82 @@ + "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; + } +} \ No newline at end of file diff --git a/airtime_mvc/application/models/Show.php b/airtime_mvc/application/models/Show.php index 6fa4fd132..06e72261b 100644 --- a/airtime_mvc/application/models/Show.php +++ b/airtime_mvc/application/models/Show.php @@ -162,7 +162,7 @@ class Application_Model_Show { ->find($con); foreach ($instances as $instance) { - $instance->updateScheduleStatus(); + $instance->updateScheduleStatus($con); } $con->commit(); @@ -1448,7 +1448,8 @@ class Application_Model_Show { } $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 LEFT JOIN cc_show ON cc_show.id = cc_show_instances.show_id WHERE cc_show_instances.modified_instance = FALSE"; @@ -1479,6 +1480,9 @@ class Application_Model_Show { $sql = $sql." AND ({$exclude})"; } + //Logging::log("getShows"); + //Logging::log($sql); + return $CC_DBC->GetAll($sql); } diff --git a/airtime_mvc/application/models/ShowBuilder.php b/airtime_mvc/application/models/ShowBuilder.php index 231293468..bb87c9e6a 100644 --- a/airtime_mvc/application/models/ShowBuilder.php +++ b/airtime_mvc/application/models/ShowBuilder.php @@ -6,13 +6,19 @@ require_once 'formatters/TimeFilledFormatter.php'; class Application_Model_ShowBuilder { private $timezone; + + //in UTC timezone private $startDT; + //in UTC timezone private $endDT; + private $user; private $opts; private $contentDT; private $epoch_now; + + private $hasCurrent; private $defaultRowArray = array( "header" => false, @@ -47,6 +53,8 @@ class Application_Model_ShowBuilder { $this->user = Application_Model_User::GetCurrentUser(); $this->opts = $p_opts; $this->epoch_now = time(); + + $this->hasCurrent = false; } //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")); $schedStartDT = new DateTime($p_item["sched_starts"], new DateTimeZone("UTC")); - + $showStartEpoch = intval($showStartDT->format('U')); $schedStartEpoch = intval($schedStartDT->format('U')); //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) { $row["allowed"] = true; } @@ -89,11 +97,13 @@ class Application_Model_ShowBuilder { } private function isCurrent($p_epochItemStart, $p_epochItemEnd, &$row) { - + if ($this->epoch_now >= $p_epochItemStart && $this->epoch_now < $p_epochItemEnd) { $row["current"] = true; //how many seconds the view should wait to redraw itself. $row["refresh"] = $p_epochItemEnd - $this->epoch_now; + + $this->hasCurrent = true; } } @@ -111,6 +121,7 @@ class Application_Model_ShowBuilder { $row["header"] = true; $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["duration"] = $showEndDT->format("U") - $showStartDT->format("U"); $row["title"] = $p_item["show_name"]; @@ -194,6 +205,39 @@ class Application_Model_ShowBuilder { 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() { $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. $display_items[] = $this->makeFooterRow($scheduled_items[$i-1]); } - + $display_items[] = $this->makeHeaderRow($item); $current_id = $item["si_id"]; @@ -247,6 +291,10 @@ class Application_Model_ShowBuilder { if (count($scheduled_items) > 0) { $display_items[] = $this->makeFooterRow($scheduled_items[count($scheduled_items)-1]); } + + if (!$this->hasCurrent) { + + } return $display_items; } diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 9dfd99e46..9615875f6 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -395,7 +395,7 @@ class Application_Model_StoredFile { } 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(); } @@ -660,7 +660,7 @@ Logging::log("getting media! - 2"); if($type == "au"){//&& isset( $audioResults )) { $row['audioFile'] = $row['gunid'].".".pathinfo($row['filepath'], PATHINFO_EXTENSION); - $row['image'] = '
'; + $row['image'] = ''; } else { $row['image'] = ''; @@ -669,22 +669,22 @@ Logging::log("getting media! - 2"); return $results; } - + public static function searchFiles($displayColumns, $fromTable, $data) { $con = Propel::getConnection(CcFilesPeer::DATABASE_NAME); $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++) { @@ -692,12 +692,12 @@ Logging::log("getting media! - 2"); $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}%'"; @@ -707,7 +707,7 @@ Logging::log("getting media! - 2"); $where[] = "(".join(" AND ", $outerCond).")"; } // End Where clause - + // Order By clause $orderby = array(); for ($i = 0; $i < $data["iSortingCols"]; $i++){ @@ -717,22 +717,22 @@ Logging::log("getting media! - 2"); $orderby[] = "id"; $orderby = join("," , $orderby); // End Order By clause - + 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." OFFSET ".$data["iDisplayStart"]." LIMIT ".$data["iDisplayLength"]; } else { $sql = $selectorRows." FROM ".$fromTable." ORDER BY ".$orderby." OFFSET ".$data["iDisplayStart"]." LIMIT ".$data["iDisplayLength"]; } - + try { $r = $con->query($sqlTotalRows); $totalRows = $r->fetchColumn(0); - + if (isset($sqlTotalDisplayRows)) { $r = $con->query($sqlTotalDisplayRows); $totalDisplayRows = $r->fetchColumn(0); @@ -740,7 +740,7 @@ Logging::log("getting media! - 2"); else { $totalDisplayRows = $totalRows; } - + $r = $con->query($sql); $r->setFetchMode(PDO::FETCH_ASSOC); $results = $r->fetchAll(); @@ -748,10 +748,10 @@ Logging::log("getting media! - 2"); 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" => $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: post-check=0, pre-check=0", false); header("Pragma: no-cache"); - + // Settings $cleanupTargetDir = false; // Remove old files $maxFileAge = 60 * 60; // Temp file age in seconds - + // 5 minutes execution time @set_time_limit(5 * 60); // usleep(5000); - + // Get parameters $chunk = isset($_REQUEST["chunk"]) ? $_REQUEST["chunk"] : 0; $chunks = isset($_REQUEST["chunks"]) ? $_REQUEST["chunks"] : 0; @@ -781,29 +781,29 @@ Logging::log("getting media! - 2"); // Clean the fileName for security reasons //this needs fixing for songs not in ascii. //$fileName = preg_replace('/[^\w\._]+/', '', $fileName); - + // Create target dir if (!file_exists($p_targetDir)) @mkdir($p_targetDir); - + // Remove old temp files if (is_dir($p_targetDir) && ($dir = opendir($p_targetDir))) { while (($file = readdir($dir)) !== false) { $filePath = $p_targetDir . DIRECTORY_SEPARATOR . $file; - + // Remove temp files if they are older than the max age if (preg_match('/\.tmp$/', $file) && (filemtime($filePath) < time() - $maxFileAge)) @unlink($filePath); } - + closedir($dir); } else die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}'); - + // Look for the content type header if (isset($_SERVER["HTTP_CONTENT_TYPE"])) $contentType = $_SERVER["HTTP_CONTENT_TYPE"]; - + if (isset($_SERVER["CONTENT_TYPE"])) $contentType = $_SERVER["CONTENT_TYPE"]; @@ -819,13 +819,13 @@ Logging::log("getting media! - 2"); if ($out) { // Read binary input stream and append it to temp file $in = fopen($_FILES['file']['tmp_name'], "rb"); - + if ($in) { while ($buff = fread($in, 4096)) fwrite($out, $buff); } else die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}'); - + fclose($out); unlink($_FILES['file']['tmp_name']); } else @@ -838,18 +838,18 @@ Logging::log("getting media! - 2"); if ($out) { // Read binary input stream and append it to temp file $in = fopen("php://input", "rb"); - + if ($in) { while ($buff = fread($in, 4096)) fwrite($out, $buff); } else die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}'); - + fclose($out); } else die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}'); } - + return $tempFilePath; } @@ -899,7 +899,7 @@ Logging::log("getting media! - 2"); 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 $r = @rename($audio_file, $audio_stor); - + if ($r === false) { #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. diff --git a/airtime_mvc/application/models/formatters/TimeFilledFormatter.php b/airtime_mvc/application/models/formatters/TimeFilledFormatter.php index 6a894d194..a1d751eee 100644 --- a/airtime_mvc/application/models/formatters/TimeFilledFormatter.php +++ b/airtime_mvc/application/models/formatters/TimeFilledFormatter.php @@ -19,6 +19,7 @@ class TimeFilledFormatter { { $formatted = ""; $sign = ($this->_seconds < 0) ? "-" : "+"; + $perfect = true; $time = Application_Model_Playlist::secondsToPlaylistTime(abs($this->_seconds)); Logging::log("time is: ".$time); @@ -29,16 +30,24 @@ class TimeFilledFormatter { if (intval($info[0]) > 0) { $info[0] = ltrim($info[0], "0"); $formatted .= " {$info[0]}h"; + $perfect = false; } if (intval($info[1]) > 0) { $info[1] = ltrim($info[1], "0"); $formatted .= " {$info[1]}m"; + $perfect = false; } if (intval($info[2]) > 0) { $sec = round($info[2], 0); $formatted .= " {$sec}s"; + $perfect = false; + } + + //0 over/under lap of content. + if ($perfect === true) { + $formatted = "+ 0s"; } return $formatted; diff --git a/airtime_mvc/application/views/scripts/form/daterange.phtml b/airtime_mvc/application/views/scripts/form/daterange.phtml new file mode 100644 index 000000000..5d0d86d4f --- /dev/null +++ b/airtime_mvc/application/views/scripts/form/daterange.phtml @@ -0,0 +1,7 @@ +
+ element->getElement('his_date_start') ?> + element->getElement('his_time_start') ?> + element->getElement('his_date_end') ?> + element->getElement('his_time_end') ?> + +
\ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/form/showbuilder.phtml b/airtime_mvc/application/views/scripts/form/showbuilder.phtml index fb4c3b135..e2b67262e 100644 --- a/airtime_mvc/application/views/scripts/form/showbuilder.phtml +++ b/airtime_mvc/application/views/scripts/form/showbuilder.phtml @@ -1,4 +1,5 @@
+ element->getElement('sb_timestamp') ?> element->getElement('sb_date_start') ?> element->getElement('sb_time_start') ?> element->getElement('sb_date_end') ?> diff --git a/airtime_mvc/application/views/scripts/playouthistory/index.phtml b/airtime_mvc/application/views/scripts/playouthistory/index.phtml new file mode 100644 index 000000000..df820f39b --- /dev/null +++ b/airtime_mvc/application/views/scripts/playouthistory/index.phtml @@ -0,0 +1,2 @@ +date_form; ?> +
\ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/showbuilder/index.phtml b/airtime_mvc/application/views/scripts/showbuilder/index.phtml index e69de29bb..f8dc512d7 100644 --- a/airtime_mvc/application/views/scripts/showbuilder/index.phtml +++ b/airtime_mvc/application/views/scripts/showbuilder/index.phtml @@ -0,0 +1 @@ +dialog ?> \ No newline at end of file diff --git a/airtime_mvc/public/css/media_library.css b/airtime_mvc/public/css/media_library.css index 97de2e91c..87e156037 100644 --- a/airtime_mvc/public/css/media_library.css +++ b/airtime_mvc/public/css/media_library.css @@ -1,7 +1,7 @@ #library_content { float: left; width: 50%; - min-height: 475px; + overflow: hidden; } #library_display { @@ -9,10 +9,6 @@ table-layout:fixed; } -#library_display th { - text-align: left; -} - #library_content #library_display { width:100%; } @@ -80,7 +76,8 @@ text-align: center; } -.library_sr, -.library_bitrate { - text-align: right; -} +td.library_track, +td.library_sr, +td.library_bitrate { + text-align: right; +} \ No newline at end of file diff --git a/airtime_mvc/public/css/playlist_builder.css b/airtime_mvc/public/css/playlist_builder.css index 931bc8ff0..4f08a3976 100644 --- a/airtime_mvc/public/css/playlist_builder.css +++ b/airtime_mvc/public/css/playlist_builder.css @@ -1,9 +1,7 @@ #side_playlist { width: 40%; - min-height: 475px; - padding: 8px; - padding-bottom: 0px; font-size: 16px; + overflow: auto; } #side_playlist, diff --git a/airtime_mvc/public/css/showbuilder.css b/airtime_mvc/public/css/showbuilder.css index a0a7d8e82..4a2a47673 100644 --- a/airtime_mvc/public/css/showbuilder.css +++ b/airtime_mvc/public/css/showbuilder.css @@ -2,6 +2,7 @@ #show_builder { width:95%; + overflow: auto; } #show_builder_table th { @@ -47,10 +48,22 @@ tr.cursor-selected-row .marker { .ui-dialog .wrapper { margin: 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 { - width:45%; + margin: 0 0 10px 0; + overflow: auto; +} + +.ui-dialog .padded { + padding: 5px 10px 5px 8px; } .ui-dialog .ui-buttonset { diff --git a/airtime_mvc/public/css/styles.css b/airtime_mvc/public/css/styles.css index 5215c675e..a7de7fa82 100644 --- a/airtime_mvc/public/css/styles.css +++ b/airtime_mvc/public/css/styles.css @@ -9,7 +9,7 @@ body { padding: 0; } html, body { -height: 100%; + height: 100%; } #login-page { @@ -366,7 +366,7 @@ select { .wrapper { margin: 0 20px 0 20px; - padding:20px 0 0 0; + padding:10px 0 0 0; } .alpha-block { @@ -510,6 +510,11 @@ dl.inline-list dd { border-width: 1px 1px 1px 1px; width:100%; } + +.datatable th { + text-align: left; +} + .datatable tr td, .datatable tr th { border-color: #b1b1b1; border-style: solid; @@ -554,6 +559,14 @@ dl.inline-list dd { border-width: 0px 1px 0 1px; } +.dataTables_scrolling { + overflow: auto; +} + +.dataTables_scrolling table{ + border-width: 0px 1px 0 1px; +} + .DataTables_sort_wrapper .ui-icon { display: block; float: left; @@ -577,7 +590,7 @@ dl.inline-list dd { line-height:22px; } .dataTables_filter { - margin:8px 0 0 8px; + margin:0 0 0 8px; } .dataTables_filter .auto-search { width:55%; @@ -611,6 +624,7 @@ dl.inline-list dd { .dataTables_paginate { float: right; padding: 8px 0 8px 8px; + clear: left; } .dataTables_paginate .ui-button { font-size:12px; @@ -623,7 +637,7 @@ dl.inline-list dd { width: 55%; border: 1px solid #5B5B5B; margin-left: -8px; - padding: 4px 3px 4px 25px; + padding: 5px 3px 4px 25px; } .dataTables_length select { background-color: #DDDDDD; @@ -662,7 +676,6 @@ button.ColVis_Button.ColVis_ShowAll { .library_length { text-align: right; - padding-right: 1em !important; } /*----END Data Table----*/ diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js index 71ae50618..7bca9c849 100644 --- a/airtime_mvc/public/js/airtime/library/library.js +++ b/airtime_mvc/public/js/airtime/library/library.js @@ -1,4 +1,4 @@ - var AIRTIME = (function(AIRTIME){ +var AIRTIME = (function(AIRTIME) { var mod, libraryInit; @@ -42,14 +42,17 @@ }; libraryInit = function() { - var oTable; + var oTable, + libContentDiv = $("#library_content"); + tableHeight = libContentDiv.height() - 140; oTable = $('#library_display').dataTable( { + //put hidden columns at the top to insure they can never be visible on the table through column reordering. "aoColumns": [ - /* Checkbox */ {"sTitle": "", "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}, + /* Checkbox */ {"sTitle": "", "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"}, /* Creator */ {"sTitle": "Creator", "mDataProp": "artist_name", "sClass": "library_creator"}, /* Album */ {"sTitle": "Album", "mDataProp": "album_title", "sClass": "library_album"}, @@ -58,7 +61,7 @@ /* Length */ {"sTitle": "Length", "mDataProp": "length", "sClass": "library_length", "sWidth": "80px"}, /* Upload Time */ {"sTitle": "Uploaded", "mDataProp": "utime", "sClass": "library_upload_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"}, /* BPM */ {"sTitle": "BPM", "mDataProp": "bpm", "bSearchable": false, "bVisible": false, "sClass": "library_bpm"}, /* Composer */ {"sTitle": "Composer", "mDataProp": "composer", "bSearchable": false, "bVisible": false, "sClass": "library_composer"}, @@ -232,9 +235,9 @@ "oLanguage": { "sSearch": "" }, - + // 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": { "sRowSelect": "multi", @@ -290,6 +293,8 @@ }); oTable.fnSetFilteringDelay(350); + + libContentDiv.find(".dataTables_scrolling").css("max-height", tableHeight); AIRTIME.library.events.setupLibraryToolbar(oTable); @@ -469,9 +474,9 @@ return AIRTIME; - }(AIRTIME || {})); +}(AIRTIME || {})); - function addToolBarButtonsLibrary(aButtons) { +function addToolBarButtonsLibrary(aButtons) { var i, length = aButtons.length, libToolBar = $(".library_toolbar"), @@ -511,9 +516,9 @@ }(i)); } - } +} - function checkImportStatus(){ +function checkImportStatus(){ $.getJSON('/Preference/is-import-in-progress', function(data){ var div = $('#import_status'); if (data == true){ @@ -523,9 +528,9 @@ div.hide(); } }); - } +} - function addProgressIcon(id) { +function addProgressIcon(id) { var tr = $("#au_"+id), span; @@ -539,9 +544,9 @@ tr.find("td.library_title") .append(''); } - } +} - function checkSCUploadStatus(){ +function checkSCUploadStatus(){ var url = '/Library/get-upload-to-soundcloud-status'; @@ -563,9 +568,9 @@ } }); }); - } +} - function addQtipToSCIcons(){ +function addQtipToSCIcons(){ $(".progress, .soundcloud, .sc-error").live('mouseover', function(){ var id = $(this).parent().parent().data("aData").id; @@ -644,8 +649,7 @@ }); } }); - - } +} var audio_preview_window = null; @@ -662,4 +666,3 @@ function open_audio_preview(fileID, index) { return false; } - \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/library/main_library.js b/airtime_mvc/public/js/airtime/library/main_library.js index d50811e7e..0682ee04a 100644 --- a/airtime_mvc/public/js/airtime/library/main_library.js +++ b/airtime_mvc/public/js/airtime/library/main_library.js @@ -1 +1,16 @@ -$(document).ready(AIRTIME.library.libraryInit); \ No newline at end of file +$(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(); + +}); \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/playouthistory/historytable.js b/airtime_mvc/public/js/airtime/playouthistory/historytable.js new file mode 100644 index 000000000..8dfeca40a --- /dev/null +++ b/airtime_mvc/public/js/airtime/playouthistory/historytable.js @@ -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(); + }); + +}); \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/schedule/schedule.js b/airtime_mvc/public/js/airtime/schedule/schedule.js index e93be7df3..9fb962ba4 100644 --- a/airtime_mvc/public/js/airtime/schedule/schedule.js +++ b/airtime_mvc/public/js/airtime/schedule/schedule.js @@ -100,15 +100,32 @@ function buildScheduleDialog (json) { var dialog = $(json.dialog), viewport = findViewportDimensions(), - height = viewport.height * 0.96, - width = viewport.width * 0.96, - fnServer = AIRTIME.showbuilder.fnServerData; - + height = Math.floor(viewport.height * 0.96), + width = Math.floor(viewport.width * 0.96), + 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({ autoOpen: false, title: json.title, width: width, height: height, + resizable: false, + draggable: false, modal: true, close: closeDialog, buttons: {"Ok": function() { @@ -116,7 +133,7 @@ function buildScheduleDialog (json) { $("#schedule_calendar").fullCalendar( 'refetchEvents' ); }} }); - + //set the start end times so the builder datatables knows its time range. fnServer.start = json.start; fnServer.end = json.end; @@ -124,7 +141,17 @@ function buildScheduleDialog (json) { AIRTIME.library.libraryInit(); AIRTIME.showbuilder.builderDataTable(); + dialog.find(".dataTables_scrolling") + .css("max-height", height - 110 - 155); + 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){ diff --git a/airtime_mvc/public/js/airtime/showbuilder/builder.js b/airtime_mvc/public/js/airtime/showbuilder/builder.js index 74b3b18b3..fd0e0dc84 100644 --- a/airtime_mvc/public/js/airtime/showbuilder/builder.js +++ b/airtime_mvc/public/js/airtime/showbuilder/builder.js @@ -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) { var oLibTT = TableTools.fnGetInstance('library_display'); @@ -47,6 +75,8 @@ var AIRTIME = (function(AIRTIME){ }; fnServerData = function ( sSource, aoData, fnCallback ) { + + aoData.push( { name: "timestamp", value: AIRTIME.showbuilder.getTimestamp()} ); aoData.push( { name: "format", value: "json"} ); if (fnServerData.hasOwnProperty("start")) { @@ -65,7 +95,10 @@ var AIRTIME = (function(AIRTIME){ "type": "GET", "url": sSource, "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() { var tableDiv = $('#show_builder_table'), oTable, - fnRemoveSelectedItems; + fnRemoveSelectedItems, + tableHeight; fnRemoveSelectedItems = function() { var oTT = TableTools.fnGetInstance('show_builder_table'), @@ -269,7 +303,11 @@ var AIRTIME = (function(AIRTIME){ markerDiv, td, $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. 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. tr = tableDiv.find("tr.sb-now-playing"); + if (tr.length > 0) { - var oTable = $('#show_builder_table').dataTable(), - aData = tr.data("aData"); + aData = tr.data("aData"); setTimeout(function(){ + AIRTIME.showbuilder.resetTimestamp(); oTable.fnDraw(); }, 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) { $(nHead).find("input[type=checkbox]").attr("checked", false); }, //remove any selected nodes before the draw. "fnPreDrawCallback": function( oSettings ) { - var oTT = TableTools.fnGetInstance('show_builder_table'); + var oTT; + + oTT = TableTools.fnGetInstance('show_builder_table'); oTT.fnSelectNone(); }, @@ -371,7 +425,7 @@ var AIRTIME = (function(AIRTIME){ }, // R = ColReorderResize, C = ColVis, T = TableTools - "sDom": 'Rr<"H"CT>t<"F">', + "sDom": 'Rr<"H"CT>t', "sAjaxDataProp": "schedule", "sAjaxSource": "/showbuilder/builder-feed" diff --git a/airtime_mvc/public/js/airtime/showbuilder/main_builder.js b/airtime_mvc/public/js/airtime/showbuilder/main_builder.js index 4a0af1638..78c6d5723 100644 --- a/airtime_mvc/public/js/airtime/showbuilder/main_builder.js +++ b/airtime_mvc/public/js/airtime/showbuilder/main_builder.js @@ -1,8 +1,24 @@ $(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, - 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 = { dateFormat: 'yy-mm-dd', @@ -18,78 +34,10 @@ $(document).ready(function(){ defaultTime: '0:00' }; - /* - * 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 - */ - 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); + builder.find(dateStartId).datepicker(oBaseDatePickerSettings); + builder.find(timeStartId).timepicker(oBaseTimePickerSettings); + builder.find(dateEndId).datepicker(oBaseDatePickerSettings); + builder.find(timeEndId).timepicker(oBaseTimePickerSettings); $("#sb_submit").click(function(ev){ var fn, @@ -97,7 +45,10 @@ $(document).ready(function(){ op, 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.start = oRange.start; @@ -120,40 +71,70 @@ $(document).ready(function(){ var $button = $(this), $lib = $("#library_content"), $builder = $("#show_builder"), - oTable = $("#show_builder_table").dataTable(); + schedTable = $("#show_builder_table").dataTable(); if ($button.hasClass("sb-edit")) { + //reset timestamp to redraw the cursors. + AIRTIME.showbuilder.resetTimestamp(); + $lib.show(); - $lib.width("45%"); - $builder.width("50%"); + $lib.width(Math.floor(screenWidth * 0.5)); + $builder.width(Math.floor(screenWidth * 0.5)); $button.removeClass("sb-edit"); $button.addClass("sb-finish-edit"); $button.val("Close Library"); } - else if($button.hasClass("sb-finish-edit")) { + else if ($button.hasClass("sb-finish-edit")) { $lib.hide(); - $builder.width("95%"); + $builder.width(screenWidth); $button.removeClass("sb-finish-edit"); $button.addClass("sb-edit"); $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.end = oRange.end; - + + AIRTIME.library.libraryInit(); AIRTIME.showbuilder.builderDataTable(); + //check if the timeline viewed needs updating. setInterval(function(){ - var oTable = $('#show_builder_table').dataTable(); - oTable.fnDraw(); - }, 20 * 1000); //need refresh in milliseconds + var data = {}, + oTable = $('#show_builder_table').dataTable(), + 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 }); \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/utilities/utilities.js b/airtime_mvc/public/js/airtime/utilities/utilities.js new file mode 100644 index 000000000..54475a580 --- /dev/null +++ b/airtime_mvc/public/js/airtime/utilities/utilities.js @@ -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 || {})); \ No newline at end of file diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/as3/ZeroClipboard.as b/airtime_mvc/public/js/datatables/plugin/TableTools/as3/ZeroClipboard.as new file mode 100755 index 000000000..367b0497d --- /dev/null +++ b/airtime_mvc/public/js/datatables/plugin/TableTools/as3/ZeroClipboard.as @@ -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> 8 ); + } + + i++; + } + + return utf16; + } + } +} diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/as3/ZeroClipboardPdf.as b/airtime_mvc/public/js/datatables/plugin/TableTools/as3/ZeroClipboardPdf.as new file mode 100755 index 000000000..937187e43 --- /dev/null +++ b/airtime_mvc/public/js/datatables/plugin/TableTools/as3/ZeroClipboardPdf.as @@ -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> 8 ); + } + + i++; + } + + return utf16; + } + } +} diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/as3/lib/AlivePDF.swc b/airtime_mvc/public/js/datatables/plugin/TableTools/as3/lib/AlivePDF.swc new file mode 100644 index 000000000..ee0f3f8f4 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/as3/lib/AlivePDF.swc differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/css/TableTools.css b/airtime_mvc/public/js/datatables/plugin/TableTools/css/TableTools.css new file mode 100755 index 000000000..4f3dd532e --- /dev/null +++ b/airtime_mvc/public/js/datatables/plugin/TableTools/css/TableTools.css @@ -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; +} diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/css/TableTools_JUI.css b/airtime_mvc/public/js/datatables/plugin/TableTools/css/TableTools_JUI.css new file mode 100755 index 000000000..95996ed2b --- /dev/null +++ b/airtime_mvc/public/js/datatables/plugin/TableTools/css/TableTools_JUI.css @@ -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; +} diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/background.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/background.png new file mode 100644 index 000000000..915efba68 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/background.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/collection.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/collection.png new file mode 100644 index 000000000..5dd4dfdf6 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/collection.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/collection_hover.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/collection_hover.png new file mode 100644 index 000000000..7b37b1e96 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/collection_hover.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/copy.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/copy.png new file mode 100755 index 000000000..5b01ab165 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/copy.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/copy_hover.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/copy_hover.png new file mode 100755 index 000000000..039a7fc32 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/copy_hover.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/csv.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/csv.png new file mode 100755 index 000000000..43df1559f Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/csv.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/csv_hover.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/csv_hover.png new file mode 100755 index 000000000..10b34d3b9 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/csv_hover.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/pdf.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/pdf.png new file mode 100644 index 000000000..1b038d088 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/pdf.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/pdf_hover.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/pdf_hover.png new file mode 100644 index 000000000..eb06855f4 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/pdf_hover.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/print.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/print.png new file mode 100755 index 000000000..2db08242a Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/print.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/print_hover.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/print_hover.png new file mode 100755 index 000000000..9808a9cc9 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/print_hover.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/collection.psd b/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/collection.psd new file mode 100644 index 000000000..7eb7caf2c Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/collection.psd differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/copy document.psd b/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/copy document.psd new file mode 100755 index 000000000..ca207adc6 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/copy document.psd differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/file_types.psd b/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/file_types.psd new file mode 100755 index 000000000..0f280ad52 Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/file_types.psd differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/printer.psd b/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/printer.psd new file mode 100755 index 000000000..8c33f7aaa Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/psd/printer.psd differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/xls.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/xls.png new file mode 100755 index 000000000..5aaf40d0e Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/xls.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/images/xls_hover.png b/airtime_mvc/public/js/datatables/plugin/TableTools/images/xls_hover.png new file mode 100755 index 000000000..5b1930afd Binary files /dev/null and b/airtime_mvc/public/js/datatables/plugin/TableTools/images/xls_hover.png differ diff --git a/airtime_mvc/public/js/datatables/plugin/TableTools/js/TableTools.js b/airtime_mvc/public/js/datatables/plugin/TableTools/js/TableTools.js new file mode 100755 index 000000000..3e02c2c08 --- /dev/null +++ b/airtime_mvc/public/js/datatables/plugin/TableTools/js/TableTools.js @@ -0,0 +1,2569 @@ +/* + * File: TableTools.js + * Version: 2.0.2 + * Description: Tools and buttons for DataTables + * Author: Allan Jardine (www.sprymedia.co.uk) + * Language: Javascript + * License: GPL v2 or BSD 3 point style + * Project: DataTables + * + * Copyright 2009-2012 Allan Jardine, all rights reserved. + * + * This source file is free software, under either the GPL v2 license or a + * BSD style license, available at: + * http://datatables.net/license_gpl2 + * http://datatables.net/license_bsd + */ + +/* Global scope for TableTools */ +var TableTools; + +(function($, window, document) { + +/** + * TableTools provides flexible buttons and other tools for a DataTables enhanced table + * @class TableTools + * @constructor + * @param {Object} oDT DataTables instance + * @param {Object} oOpts TableTools options + * @param {String} oOpts.sSwfPath ZeroClipboard SWF path + * @param {String} oOpts.sRowSelect Row selection options - 'none', 'single' or 'multi' + * @param {Function} oOpts.fnPreRowSelect Callback function just prior to row selection + * @param {Function} oOpts.fnRowSelected Callback function just after row selection + * @param {Function} oOpts.fnRowDeselected Callback function when row is deselected + * @param {Array} oOpts.aButtons List of buttons to be used + */ +TableTools = function( oDT, oOpts ) +{ + /* Santiy check that we are a new instance */ + if ( !this.CLASS || this.CLASS != "TableTools" ) + { + alert( "Warning: TableTools must be initialised with the keyword 'new'" ); + } + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Public class variables + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * @namespace Settings object which contains customisable information for TableTools instance + */ + this.s = { + /** + * Store 'this' so the instance can be retreieved from the settings object + * @property that + * @type object + * @default this + */ + "that": this, + + /** + * DataTables settings objects + * @property dt + * @type object + * @default null + */ + "dt": null, + + /** + * @namespace Print specific information + */ + "print": { + /** + * DataTables draw 'start' point before the printing display was shown + * @property saveStart + * @type int + * @default -1 + */ + "saveStart": -1, + + /** + * DataTables draw 'length' point before the printing display was shown + * @property saveLength + * @type int + * @default -1 + */ + "saveLength": -1, + + /** + * Page scrolling point before the printing display was shown so it can be restored + * @property saveScroll + * @type int + * @default -1 + */ + "saveScroll": -1, + + /** + * Wrapped function to end the print display (to maintain scope) + * @property funcEnd + * @type Function + * @default function () {} + */ + "funcEnd": function () {} + }, + + /** + * A unique ID is assigned to each button in each instance + * @property buttonCounter + * @type int + * @default 0 + */ + "buttonCounter": 0, + + /** + * @namespace Select rows specific information + */ + "select": { + /** + * Select type - can be 'none', 'single' or 'multi' + * @property type + * @type string + * @default "" + */ + "type": "", + + /** + * Array of nodes which are currently selected + * @property selected + * @type array + * @default [] + */ + "selected": [], + + /** + * Function to run before the selection can take place. Will cancel the select if the + * function returns false + * @property preRowSelect + * @type Function + * @default null + */ + "preRowSelect": null, + + /** + * Function to run when a row is selected + * @property postSelected + * @type Function + * @default null + */ + "postSelected": null, + + /** + * Function to run when a row is deselected + * @property postDeselected + * @type Function + * @default null + */ + "postDeselected": null, + + /** + * Indicate if all rows are selected (needed for server-side processing) + * @property all + * @type boolean + * @default false + */ + "all": false, + + /** + * Class name to add to selected TR nodes + * @property selectedClass + * @type String + * @default "" + */ + "selectedClass": "" + }, + + /** + * Store of the user input customisation object + * @property custom + * @type object + * @default {} + */ + "custom": {}, + + /** + * SWF movie path + * @property swfPath + * @type string + * @default "" + */ + "swfPath": "", + + /** + * Default button set + * @property buttonSet + * @type array + * @default [] + */ + "buttonSet": [], + + /** + * When there is more than one TableTools instance for a DataTable, there must be a + * master which controls events (row selection etc) + * @property master + * @type boolean + * @default false + */ + "master": false + }; + + + /** + * @namespace Common and useful DOM elements for the class instance + */ + this.dom = { + /** + * DIV element that is create and all TableTools buttons (and their children) put into + * @property container + * @type node + * @default null + */ + "container": null, + + /** + * The table node to which TableTools will be applied + * @property table + * @type node + * @default null + */ + "table": null, + + /** + * @namespace Nodes used for the print display + */ + "print": { + /** + * Nodes which have been removed from the display by setting them to display none + * @property hidden + * @type array + * @default [] + */ + "hidden": [], + + /** + * The information display saying tellng the user about the print display + * @property message + * @type node + * @default null + */ + "message": null + }, + + /** + * @namespace Nodes used for a collection display. This contains the currently used collection + */ + "collection": { + /** + * The div wrapper containing the buttons in the collection (i.e. the menu) + * @property collection + * @type node + * @default null + */ + "collection": null, + + /** + * Background display to provide focus and capture events + * @property background + * @type node + * @default null + */ + "background": null + } + }; + + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Public class methods + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * Retreieve the settings object from an instance + * @method fnSettings + * @returns {object} TableTools settings object + */ + this.fnSettings = function () { + return this.s; + }; + + + /* Constructor logic */ + if ( typeof oOpts == 'undefined' ) + { + oOpts = {}; + } + + this.s.dt = oDT.fnSettings(); + this._fnConstruct( oOpts ); + + return this; +}; + + + +TableTools.prototype = { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Public methods + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * Retreieve the settings object from an instance + * @method fnGetSelected + * @returns {array} List of TR nodes which are currently selected + */ + "fnGetSelected": function () + { + var masterS = this._fnGetMasterSettings(); + return masterS.select.selected; + }, + + + /** + * Get the data source objects/arrays from DataTables for the selected rows (same as + * fnGetSelected followed by fnGetData on each row from the table) + * @method fnGetSelectedData + * @returns {array} Data from the TR nodes which are currently selected + */ + "fnGetSelectedData": function () + { + var masterS = this._fnGetMasterSettings(); + var selected = masterS.select.selected; + var out = []; + + for ( var i=0, iLen=selected.length ; i 0 ) + { + sTitle = anTitle[0].innerHTML; + } + } + + /* Strip characters which the OS will object to - checking for UTF8 support in the scripting + * engine + */ + if ( "\u00A1".toString().length < 4 ) { + return sTitle.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, ""); + } else { + return sTitle.replace(/[^a-zA-Z0-9_\.,\-_ !\(\)]/g, ""); + } + }, + + + /** + * Calculate a unity array with the column width by proportion for a set of columns to be + * included for a button. This is particularly useful for PDF creation, where we can use the + * column widths calculated by the browser to size the columns in the PDF. + * @method fnCalcColRations + * @param {Object} oConfig Button configuration object + * @returns {Array} Unity array of column ratios + */ + "fnCalcColRatios": function ( oConfig ) + { + var + aoCols = this.s.dt.aoColumns, + aColumnsInc = this._fnColumnTargets( oConfig.mColumns ), + aColWidths = [], + iWidth = 0, iTotal = 0, i, iLen; + + for ( i=0, iLen=aColumnsInc.length ; i